split main src and lib

This commit is contained in:
Alexey Kuznetsov 2017-02-24 10:37:32 +03:00
commit ba01f8003d
72 changed files with 836 additions and 683 deletions

1
android-audio-library/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,38 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
minSdkVersion 9
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:design:25.2.0'
compile 'com.android.support:appcompat-v7:25.2.0'
compile 'com.google.android.gms:play-services-appindexing:9.8.0'
compile 'org.apache.commons:commons-math3:3.6.1'
compile 'com.github.axet:android-library:1.9.9' //compile project(':android-library')
compile 'com.github.axet:jebml:0.0.2' // compile project(':jebml')
compile 'com.github.axet:vorbis:1.0.0' // compile project(':vorbis')
testCompile 'junit:junit:4.12'
compile project(path: ':android-library')
}

View file

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/axet/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View file

@ -0,0 +1,26 @@
package com.github.axet.audiolibrary;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumentation test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.github.axet.audiolibrary.test", appContext.getPackageName());
}
}

View file

@ -0,0 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.axet.audiolibrary">
<application android:allowBackup="true" android:label="@string/app_name"
android:supportsRtl="true">
</application>
</manifest>

View file

@ -1,15 +1,14 @@
package com.github.axet.audiorecorder.animations;
package com.github.axet.audiolibrary.animations;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.animation.Transformation;
import android.widget.ListView;
import com.github.axet.androidlibrary.animations.MarginAnimation;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiolibrary.R;
public class RecordingAnimation extends MarginAnimation {
ListView list;

View file

@ -0,0 +1,83 @@
package com.github.axet.audiolibrary.app;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.media.AudioFormat;
import android.preference.PreferenceManager;
import com.github.axet.androidlibrary.app.MainLibrary;
import com.github.axet.audiolibrary.R;
public class MainApplication extends Application {
public static final String PREFERENCE_STORAGE = "storage_path";
public static final String PREFERENCE_RATE = "sample_rate";
public static final String PREFERENCE_CALL = "call";
public static final String PREFERENCE_SILENT = "silence";
public static final String PREFERENCE_ENCODING = "encoding";
public static final String PREFERENCE_LAST = "last_recording";
public static final String PREFERENCE_THEME = "theme";
public static final String PREFERENCE_CHANNELS = "channels";
@Override
public void onCreate() {
super.onCreate();
Context context = this;
context.setTheme(getUserTheme());
}
public int getUserTheme() {
return getTheme(this, R.style.AppThemeLight, R.style.AppThemeDark);
}
public static int getTheme(Context context, int light, int dark) {
final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
String theme = shared.getString(PREFERENCE_THEME, "");
if (theme.equals("Theme_Dark")) {
return dark;
} else {
return light;
}
}
public String formatFree(long free, long left) {
String str = "";
long diff = left;
int diffSeconds = (int) (diff / 1000 % 60);
int diffMinutes = (int) (diff / (60 * 1000) % 60);
int diffHours = (int) (diff / (60 * 60 * 1000) % 24);
int diffDays = (int) (diff / (24 * 60 * 60 * 1000));
if (diffDays > 0) {
str = getResources().getQuantityString(R.plurals.days, diffDays, diffDays);
} else if (diffHours > 0) {
str = getResources().getQuantityString(R.plurals.hours, diffHours, diffHours);
} else if (diffMinutes > 0) {
str = getResources().getQuantityString(R.plurals.minutes, diffMinutes, diffMinutes);
} else if (diffSeconds > 0) {
str = getResources().getQuantityString(R.plurals.seconds, diffSeconds, diffSeconds);
}
return getString(R.string.title_header, MainLibrary.formatSize(this, free), str);
}
public static int getChannels(Context context) {
final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
int i = Integer.parseInt(shared.getString(MainApplication.PREFERENCE_CHANNELS, "1"));
return i;
}
public static int getMode(Context context) {
switch (getChannels(context)) {
case 1:
return AudioFormat.CHANNEL_IN_MONO;
case 2:
return AudioFormat.CHANNEL_IN_STEREO;
default:
throw new RuntimeException("unknown mode");
}
}
}

View file

@ -1,10 +1,8 @@
package com.github.axet.audiorecorder.app;
package com.github.axet.audiolibrary.app;
import android.media.AudioFormat;
import android.util.Log;
import com.github.axet.audiorecorder.activities.RecordingActivity;
import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.transform.DftNormalization;
import org.apache.commons.math3.transform.FastFourierTransformer;

View file

@ -0,0 +1,447 @@
package com.github.axet.audiolibrary.app;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Handler;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.PopupMenu;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import com.github.axet.androidlibrary.animations.RemoveItemAnimation;
import com.github.axet.androidlibrary.app.MainLibrary;
import com.github.axet.androidlibrary.widgets.OpenFileDialog;
import com.github.axet.androidlibrary.widgets.PopupShareActionProvider;
import com.github.axet.audiolibrary.R;
import com.github.axet.audiolibrary.animations.RecordingAnimation;
import com.github.axet.audiolibrary.encoders.Factory;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class Recordings extends ArrayAdapter<File> implements AbsListView.OnScrollListener {
public static String TAG = Recordings.class.getSimpleName();
static final int TYPE_COLLAPSED = 0;
static final int TYPE_EXPANDED = 1;
static final int TYPE_DELETED = 2;
public static class SortFiles implements Comparator<File> {
@Override
public int compare(File file, File file2) {
if (file.isDirectory() && file2.isFile())
return -1;
else if (file.isFile() && file2.isDirectory())
return 1;
else
return file.getPath().compareTo(file2.getPath());
}
}
Handler handler;
Storage storage;
MediaPlayer player;
Runnable updatePlayer;
int selected = -1;
ListView list;
PopupShareActionProvider shareProvider;
int scrollState;
Map<File, Integer> durations = new TreeMap<>();
public Recordings(Context context, ListView list) {
super(context, 0);
this.list = list;
this.handler = new Handler();
this.storage = new Storage(context);
this.list.setOnScrollListener(this);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
this.scrollState = scrollState;
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
public void scan(File dir) {
setNotifyOnChange(false);
clear();
durations.clear();
List<File> ff = storage.scan(dir);
for (File f : ff) {
if (f.isFile()) {
MediaPlayer mp = null;
try {
mp = MediaPlayer.create(getContext(), Uri.fromFile(f));
} catch (IllegalStateException e) {
Log.d(TAG, f.toString(), e);
}
if (mp != null) {
int d = mp.getDuration();
mp.release();
durations.put(f, d);
add(f);
} else {
Log.e(TAG, f.toString());
}
}
}
sort(new SortFiles());
notifyDataSetChanged();
}
public void close() {
if (player != null) {
player.release();
player = null;
}
if (updatePlayer != null) {
handler.removeCallbacks(updatePlayer);
updatePlayer = null;
}
}
public void load() {
scan(storage.getStoragePath());
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(getContext());
if (convertView == null) {
convertView = inflater.inflate(R.layout.recording, parent, false);
convertView.setTag(-1);
}
final View view = convertView;
final View base = convertView.findViewById(R.id.recording_base);
if ((int) convertView.getTag() == TYPE_DELETED) {
RemoveItemAnimation.restore(base);
convertView.setTag(-1);
}
final File f = getItem(position);
TextView title = (TextView) convertView.findViewById(R.id.recording_title);
title.setText(f.getName());
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
TextView time = (TextView) convertView.findViewById(R.id.recording_time);
time.setText(s.format(new Date(f.lastModified())));
TextView dur = (TextView) convertView.findViewById(R.id.recording_duration);
dur.setText(MainLibrary.formatDuration(getContext(), durations.get(f)));
TextView size = (TextView) convertView.findViewById(R.id.recording_size);
size.setText(MainLibrary.formatSize(getContext(), f.length()));
final View playerBase = convertView.findViewById(R.id.recording_player);
playerBase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
final Runnable delete = new Runnable() {
@Override
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(R.string.delete_recording);
builder.setMessage("...\\" + f.getName() + "\n\n" + getContext().getString(R.string.are_you_sure));
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
playerStop();
dialog.cancel();
RemoveItemAnimation.apply(list, base, new Runnable() {
@Override
public void run() {
f.delete();
view.setTag(TYPE_DELETED);
select(-1);
load();
}
});
}
});
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.show();
}
};
final Runnable rename = new Runnable() {
@Override
public void run() {
final OpenFileDialog.EditTextDialog e = new OpenFileDialog.EditTextDialog(getContext());
e.setTitle(getContext().getString(R.string.rename_recording));
e.setText(Storage.getNameNoExt(f));
e.setPositiveButton(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String ext = Storage.getExt(f);
String s = String.format("%s.%s", e.getText(), ext);
File ff = new File(f.getParent(), s);
f.renameTo(ff);
load();
}
});
e.show();
}
};
if (selected == position) {
RecordingAnimation.apply(list, convertView, true, scrollState == SCROLL_STATE_IDLE && (int) convertView.getTag() == TYPE_COLLAPSED);
convertView.setTag(TYPE_EXPANDED);
updatePlayerText(convertView, f);
final View play = convertView.findViewById(R.id.recording_player_play);
play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (player == null) {
playerPlay(playerBase, f);
} else if (player.isPlaying()) {
playerPause(playerBase, f);
} else {
playerPlay(playerBase, f);
}
}
});
final View edit = convertView.findViewById(R.id.recording_player_edit);
edit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
rename.run();
}
});
final View share = convertView.findViewById(R.id.recording_player_share);
share.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
shareProvider = new PopupShareActionProvider(getContext(), share);
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType(Factory.MP4A);
emailIntent.putExtra(Intent.EXTRA_EMAIL, "");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, f.getName());
emailIntent.putExtra(Intent.EXTRA_TEXT, getContext().getString(R.string.shared_via, getContext().getString(R.string.app_name)));
shareProvider.setShareIntent(emailIntent);
shareProvider.show();
}
});
View trash = convertView.findViewById(R.id.recording_player_trash);
trash.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
delete.run();
}
});
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
select(-1);
}
});
} else {
RecordingAnimation.apply(list, convertView, false, scrollState == SCROLL_STATE_IDLE && (int) convertView.getTag() == TYPE_EXPANDED);
convertView.setTag(TYPE_COLLAPSED);
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
select(position);
}
});
}
convertView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
PopupMenu popup = new PopupMenu(getContext(), v);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.menu_context, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.action_delete) {
delete.run();
return true;
}
if (item.getItemId() == R.id.action_rename) {
rename.run();
return true;
}
return false;
}
});
popup.show();
return true;
}
});
return convertView;
}
void playerPlay(View v, File f) {
if (player == null)
player = MediaPlayer.create(getContext(), Uri.fromFile(f));
if (player == null) {
Toast.makeText(getContext(), R.string.file_not_found, Toast.LENGTH_SHORT).show();
return;
}
player.start();
updatePlayerRun(v, f);
}
void playerPause(View v, File f) {
if (player != null) {
player.pause();
}
if (updatePlayer != null) {
handler.removeCallbacks(updatePlayer);
updatePlayer = null;
}
updatePlayerText(v, f);
}
void playerStop() {
if (updatePlayer != null) {
handler.removeCallbacks(updatePlayer);
updatePlayer = null;
}
if (player != null) {
player.stop();
player.release();
player = null;
}
}
void updatePlayerRun(final View v, final File f) {
boolean playing = updatePlayerText(v, f);
if (updatePlayer != null) {
handler.removeCallbacks(updatePlayer);
updatePlayer = null;
}
if (!playing) {
playerStop(); // clear player instance
updatePlayerText(v, f); // update length
return;
}
updatePlayer = new Runnable() {
@Override
public void run() {
updatePlayerRun(v, f);
}
};
handler.postDelayed(updatePlayer, 200);
}
boolean updatePlayerText(final View v, final File f) {
ImageView i = (ImageView) v.findViewById(R.id.recording_player_play);
final boolean playing = player != null && player.isPlaying();
i.setImageResource(playing ? R.drawable.ic_pause_24dp : R.drawable.ic_play_arrow_black_24dp);
TextView start = (TextView) v.findViewById(R.id.recording_player_start);
SeekBar bar = (SeekBar) v.findViewById(R.id.recording_player_seek);
TextView end = (TextView) v.findViewById(R.id.recording_player_end);
int c = 0;
int d = durations.get(f);
if (player != null) {
c = player.getCurrentPosition();
d = player.getDuration();
}
bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (!fromUser)
return;
if (player == null)
playerPlay(v, f);
if (player != null) {
player.seekTo(progress);
if (!player.isPlaying())
playerPlay(v, f);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
start.setText(MainLibrary.formatDuration(getContext(), c));
bar.setMax(d);
bar.setKeyProgressIncrement(1);
bar.setProgress(c);
end.setText("-" + MainLibrary.formatDuration(getContext(), d - c));
return playing;
}
public void select(int pos) {
selected = pos;
notifyDataSetChanged();
playerStop();
}
public int getSelected() {
return selected;
}
}

View file

@ -1,15 +1,12 @@
package com.github.axet.audiorecorder.app;
package com.github.axet.audiolibrary.app;
import android.content.Context;
import android.content.SharedPreferences;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.preference.PreferenceManager;
import java.util.Arrays;
public class Sound extends com.github.axet.androidlibrary.sound.Sound {
public Sound(Context context) {

View file

@ -1,4 +1,4 @@
package com.github.axet.audiorecorder.app;
package com.github.axet.audiolibrary.app;
import android.Manifest;
import android.content.Context;
@ -9,8 +9,7 @@ import android.os.StatFs;
import android.preference.PreferenceManager;
import android.support.v4.content.ContextCompat;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiorecorder.encoders.Factory;
import com.github.axet.audiolibrary.encoders.Factory;
import java.io.File;
import java.io.FileInputStream;

View file

@ -1,4 +1,4 @@
package com.github.axet.audiorecorder.encoders;
package com.github.axet.audiolibrary.encoders;
public interface Encoder {
void encode(short[] buf, int len);

View file

@ -1,4 +1,4 @@
package com.github.axet.audiorecorder.encoders;
package com.github.axet.audiolibrary.encoders;
public class EncoderInfo {
public int channels;

View file

@ -1,11 +1,11 @@
package com.github.axet.audiorecorder.encoders;
package com.github.axet.audiolibrary.encoders;
import android.content.Context;
import android.media.AudioFormat;
import android.os.Build;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiorecorder.app.RawSamples;
import com.github.axet.audiolibrary.R;
import com.github.axet.audiolibrary.app.RawSamples;
import java.io.File;
import java.util.ArrayList;

View file

@ -1,10 +1,10 @@
package com.github.axet.audiorecorder.encoders;
package com.github.axet.audiolibrary.encoders;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import com.github.axet.audiorecorder.app.RawSamples;
import com.github.axet.audiolibrary.app.RawSamples;
import java.io.File;

View file

@ -1,7 +1,6 @@
package com.github.axet.audiorecorder.encoders;
package com.github.axet.audiolibrary.encoders;
import android.annotation.TargetApi;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import java.io.File;

View file

@ -1,4 +1,4 @@
package com.github.axet.audiorecorder.encoders;
package com.github.axet.audiolibrary.encoders;
import android.annotation.TargetApi;
import android.media.MediaCodecInfo;

View file

@ -1,4 +1,4 @@
package com.github.axet.audiorecorder.encoders;
package com.github.axet.audiolibrary.encoders;
import android.annotation.TargetApi;
import android.media.MediaCodec;

View file

@ -1,4 +1,4 @@
package com.github.axet.audiorecorder.encoders;
package com.github.axet.audiolibrary.encoders;
import com.github.axet.vorbisjni.Vorbis;

View file

@ -1,9 +1,7 @@
package com.github.axet.audiorecorder.encoders;
package com.github.axet.audiolibrary.encoders;
// based on http://soundfile.sapp.org/doc/WaveFormat/
import android.util.Log;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

View file

@ -1,4 +1,4 @@
package com.github.axet.audiorecorder.encoders;
package com.github.axet.audiolibrary.encoders;
import android.annotation.TargetApi;
import android.media.MediaCodec;

View file

@ -1,16 +1,10 @@
package com.github.axet.audiorecorder.widgets;
package com.github.axet.audiolibrary.widgets;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.github.axet.androidlibrary.widgets.ThemeUtils;
import com.github.axet.audiorecorder.app.RawSamples;
public class FFTBarView extends FFTView {
public static final String TAG = FFTBarView.class.getSimpleName();

View file

@ -1,17 +1,11 @@
package com.github.axet.audiorecorder.widgets;
package com.github.axet.audiolibrary.widgets;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.github.axet.audiorecorder.app.RawSamples;
import com.github.axet.audiolibrary.app.RawSamples;
public class FFTChartView extends FFTView {
public static final String TAG = FFTChartView.class.getSimpleName();

View file

@ -1,15 +1,13 @@
package com.github.axet.audiorecorder.widgets;
package com.github.axet.audiolibrary.widgets;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.github.axet.androidlibrary.widgets.ThemeUtils;
import com.github.axet.audiorecorder.app.RawSamples;
import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.transform.DftNormalization;

View file

@ -1,4 +1,4 @@
package com.github.axet.audiorecorder.widgets;
package com.github.axet.audiolibrary.widgets;
import android.content.Context;
import android.graphics.Canvas;
@ -7,13 +7,12 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.github.axet.androidlibrary.widgets.ThemeUtils;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiorecorder.app.RawSamples;
import com.github.axet.audiolibrary.R;
import com.github.axet.audiolibrary.app.RawSamples;
import java.util.LinkedList;
import java.util.List;

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M8,5v14l11,-7z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
</vector>

View file

@ -54,7 +54,7 @@
android:id="@+id/notification_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/pause" />
android:src="@drawable/ic_pause_black_24dp" />
</LinearLayout>
</LinearLayout>
</FrameLayout>

View file

@ -120,7 +120,7 @@
android:id="@+id/recording_player_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play"
android:src="@drawable/ic_play_arrow_black_24dp"
android:tint="?attr/colorAccent" />
<View
@ -145,7 +145,7 @@
android:id="@+id/recording_player_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/share"
android:src="@drawable/ic_share_black_24dp"
android:tint="?attr/colorAccent" />
<View
@ -157,7 +157,7 @@
android:id="@+id/recording_player_trash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/trash"
android:src="@drawable/ic_delete_black_24dp"
android:tint="?attr/colorAccent" />
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,17 @@
<resources>
<string-array name="encodings_text">
<item>.wav (по умолчанию)</item>
</string-array>
<string name="title_header">%1$s свободно ~ %2$s</string>
<string name="db">дБ</string>
<string name="no">Нет</string>
<string name="yes">Да</string>
<string name="are_you_sure">Вы уверены?</string>
<string name="delete_recording">Удалить запись</string>
<string name="rename_recording">Переименовать запись</string>
<string name="shared_via">"Создано с помощью: %1$s"</string>
<string name="file_not_found">Файл не найден</string>
<string name="rename">Переименовать</string>
<string name="delete">Удалить</string>
</resources>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="titleColor" format="color" />
<attr name="secondBackground" format="color" />
<attr name="roundButton" format="reference" />
</resources>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="secondBackground">#33333333</color>
<color name="colorAccentLight">#FF4081</color>
<color name="colorAccentDark">#a4a4a4</color>
</resources>

View file

@ -0,0 +1,23 @@
<resources>
<string name="app_name">Audio Library</string>
<string-array name="encodings_text">
<item>.wav (default)</item>
</string-array>
<string-array name="encodings_values" translatable="false">
<item>wav</item>
</string-array>
<string name="title_header">%1$s free ~ %2$s left</string>
<string name="db">dB</string>
<string name="no">No</string>
<string name="yes">Yes</string>
<string name="are_you_sure">"Are you sure ? "</string>
<string name="delete_recording">Delete Recording</string>
<string name="rename_recording">Rename Recording</string>
<string name="shared_via">"Shared via %1$s"</string>
<string name="file_not_found">File not found</string>
<string name="rename">Rename</string>
<string name="delete">Delete</string>
</resources>

View file

@ -0,0 +1,48 @@
<resources>
<style name="AppThemeLight" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccentLight</item>
<item name="titleColor">@color/colorPrimary</item>
<item name="secondBackground">#c2c2c2</item>
<item name="roundButton">@drawable/round_button_light</item>
<item name="alertDialogTheme">@style/AppThemeDialogLight</item>
</style>
<style name="AppThemeDialogLight" parent="@style/Theme.AppCompat.Light.Dialog.Alert">
<item name="colorAccent">@color/colorAccentLight</item>
</style>
<style name="AppThemeLight.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="AppThemeLight.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:textColorPrimary">@android:color/white</item>
</style>
<style name="AppThemeLight.PopupOverlay" parent="ThemeOverlay.AppCompat.Light">
</style>
<style name="AppThemeDark" parent="Theme.AppCompat">
<item name="colorPrimaryDark">@color/primary_dark_material_dark</item>
<item name="colorPrimary">@color/primary_material_dark</item>
<item name="colorAccent">@color/colorAccentDark</item>
<item name="titleColor">@android:color/primary_text_dark</item>
<item name="secondBackground">#151515</item>
<item name="roundButton">@drawable/round_button_dark</item>
<item name="alertDialogTheme">@style/AppThemeDialogDark</item>
</style>
<style name="AppThemeDialogDark" parent="@style/Theme.AppCompat.Dialog.Alert">
<item name="colorAccent">@color/colorAccentDark</item>
</style>
<style name="AppThemeDark.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources>

View file

@ -0,0 +1,17 @@
package com.github.axet.audiolibrary;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}

View file

@ -45,10 +45,5 @@ dependencies {
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:25.2.0'
compile 'com.android.support:support-v4:25.2.0'
compile 'com.android.support:design:25.2.0'
compile 'com.google.android.gms:play-services-appindexing:9.8.0'
compile 'org.apache.commons:commons-math3:3.6.1'
compile 'com.github.axet:android-library:1.9.9' //compile project(':android-library')
compile 'com.github.axet:jebml:0.0.2' // compile project(':jebml')
compile 'com.github.axet:vorbis:1.0.0' // compile project(':vorbis')
compile project(':android-audio-library')
}

View file

@ -2,9 +2,6 @@ package com.github.axet.audiorecorder;
import android.app.Application;
import android.test.ApplicationTestCase;
import android.util.Log;
import com.github.axet.audiorecorder.app.RawSamples;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>

View file

@ -1,14 +1,11 @@
package com.github.axet.audiorecorder.activities;
import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@ -18,67 +15,39 @@ import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import com.github.axet.androidlibrary.animations.RemoveItemAnimation;
import com.github.axet.androidlibrary.app.MainLibrary;
import com.github.axet.androidlibrary.widgets.OpenFileDialog;
import com.github.axet.androidlibrary.widgets.PopupShareActionProvider;
import com.github.axet.audiolibrary.app.Recordings;
import com.github.axet.audiolibrary.app.Storage;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiorecorder.animations.RecordingAnimation;
import com.github.axet.audiorecorder.app.MainApplication;
import com.github.axet.audiorecorder.app.Storage;
import com.github.axet.audiorecorder.encoders.Factory;
import com.google.android.gms.appindexing.Action;
import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.common.api.GoogleApiClient;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class MainActivity extends AppCompatActivity implements AbsListView.OnScrollListener {
public class MainActivity extends AppCompatActivity {
public final static String TAG = MainActivity.class.getSimpleName();
static final int TYPE_COLLAPSED = 0;
static final int TYPE_EXPANDED = 1;
static final int TYPE_DELETED = 2;
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
FloatingActionButton fab;
Handler handler = new Handler();
final int[] ALL = {TYPE_COLLAPSED, TYPE_EXPANDED};
int scrollState;
ListView list;
Recordings recordings;
Storage storage;
ListView list;
Handler handler;
PopupShareActionProvider shareProvider;
int themeId;
@ -89,381 +58,6 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
context.startActivity(i);
}
static class SortFiles implements Comparator<File> {
@Override
public int compare(File file, File file2) {
if (file.isDirectory() && file2.isFile())
return -1;
else if (file.isFile() && file2.isDirectory())
return 1;
else
return file.getPath().compareTo(file2.getPath());
}
}
public class Recordings extends ArrayAdapter<File> {
MediaPlayer player;
Runnable updatePlayer;
int selected = -1;
Map<File, Integer> durations = new TreeMap<>();
public Recordings(Context context) {
super(context, 0);
}
public void scan(File dir) {
setNotifyOnChange(false);
clear();
durations.clear();
List<File> ff = storage.scan(dir);
for (File f : ff) {
if (f.isFile()) {
MediaPlayer mp = null;
try {
mp = MediaPlayer.create(getContext(), Uri.fromFile(f));
} catch (IllegalStateException e) {
Log.d(TAG, f.toString(), e);
}
if (mp != null) {
int d = mp.getDuration();
mp.release();
durations.put(f, d);
add(f);
} else {
Log.e(TAG, f.toString());
}
}
}
sort(new SortFiles());
notifyDataSetChanged();
}
public void close() {
if (player != null) {
player.release();
player = null;
}
if (updatePlayer != null) {
handler.removeCallbacks(updatePlayer);
updatePlayer = null;
}
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(getContext());
if (convertView == null) {
convertView = inflater.inflate(R.layout.recording, parent, false);
convertView.setTag(-1);
}
final View view = convertView;
final View base = convertView.findViewById(R.id.recording_base);
if ((int) convertView.getTag() == TYPE_DELETED) {
RemoveItemAnimation.restore(base);
convertView.setTag(-1);
}
final File f = getItem(position);
TextView title = (TextView) convertView.findViewById(R.id.recording_title);
title.setText(f.getName());
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
TextView time = (TextView) convertView.findViewById(R.id.recording_time);
time.setText(s.format(new Date(f.lastModified())));
TextView dur = (TextView) convertView.findViewById(R.id.recording_duration);
dur.setText(MainLibrary.formatDuration(getContext(), durations.get(f)));
TextView size = (TextView) convertView.findViewById(R.id.recording_size);
size.setText(MainLibrary.formatSize(getContext(), f.length()));
final View playerBase = convertView.findViewById(R.id.recording_player);
playerBase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
final Runnable delete = new Runnable() {
@Override
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(R.string.delete_recording);
builder.setMessage("...\\" + f.getName() + "\n\n" + getString(R.string.are_you_sure));
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
playerStop();
dialog.cancel();
RemoveItemAnimation.apply(list, base, new Runnable() {
@Override
public void run() {
f.delete();
view.setTag(TYPE_DELETED);
select(-1);
load();
}
});
}
});
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.show();
}
};
final Runnable rename = new Runnable() {
@Override
public void run() {
final OpenFileDialog.EditTextDialog e = new OpenFileDialog.EditTextDialog(getContext());
e.setTitle(getString(R.string.rename_recording));
e.setText(Storage.getNameNoExt(f));
e.setPositiveButton(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String ext = Storage.getExt(f);
String s = String.format("%s.%s", e.getText(), ext);
File ff = new File(f.getParent(), s);
f.renameTo(ff);
load();
}
});
e.show();
}
};
if (selected == position) {
RecordingAnimation.apply(list, convertView, true, scrollState == SCROLL_STATE_IDLE && (int) convertView.getTag() == TYPE_COLLAPSED);
convertView.setTag(TYPE_EXPANDED);
updatePlayerText(convertView, f);
final View play = convertView.findViewById(R.id.recording_player_play);
play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (player == null) {
playerPlay(playerBase, f);
} else if (player.isPlaying()) {
playerPause(playerBase, f);
} else {
playerPlay(playerBase, f);
}
}
});
final View edit = convertView.findViewById(R.id.recording_player_edit);
edit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
rename.run();
}
});
final View share = convertView.findViewById(R.id.recording_player_share);
share.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
shareProvider = new PopupShareActionProvider(getContext(), share);
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType(Factory.MP4A);
emailIntent.putExtra(Intent.EXTRA_EMAIL, "");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, f.getName());
emailIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.shared_via, getString(R.string.app_name)));
shareProvider.setShareIntent(emailIntent);
shareProvider.show();
}
});
View trash = convertView.findViewById(R.id.recording_player_trash);
trash.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
delete.run();
}
});
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
select(-1);
}
});
} else {
RecordingAnimation.apply(list, convertView, false, scrollState == SCROLL_STATE_IDLE && (int) convertView.getTag() == TYPE_EXPANDED);
convertView.setTag(TYPE_COLLAPSED);
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
select(position);
}
});
}
convertView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
PopupMenu popup = new PopupMenu(getContext(), v);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.menu_context, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.action_delete) {
delete.run();
return true;
}
if (item.getItemId() == R.id.action_rename) {
rename.run();
return true;
}
return false;
}
});
popup.show();
return true;
}
});
return convertView;
}
void playerPlay(View v, File f) {
if (player == null)
player = MediaPlayer.create(getContext(), Uri.fromFile(f));
if (player == null) {
Toast.makeText(MainActivity.this, R.string.file_not_found, Toast.LENGTH_SHORT).show();
return;
}
player.start();
updatePlayerRun(v, f);
}
void playerPause(View v, File f) {
if (player != null) {
player.pause();
}
if (updatePlayer != null) {
handler.removeCallbacks(updatePlayer);
updatePlayer = null;
}
updatePlayerText(v, f);
}
void playerStop() {
if (updatePlayer != null) {
handler.removeCallbacks(updatePlayer);
updatePlayer = null;
}
if (player != null) {
player.stop();
player.release();
player = null;
}
}
void updatePlayerRun(final View v, final File f) {
boolean playing = updatePlayerText(v, f);
if (updatePlayer != null) {
handler.removeCallbacks(updatePlayer);
updatePlayer = null;
}
if (!playing) {
playerStop(); // clear player instance
updatePlayerText(v, f); // update length
return;
}
updatePlayer = new Runnable() {
@Override
public void run() {
updatePlayerRun(v, f);
}
};
handler.postDelayed(updatePlayer, 200);
}
boolean updatePlayerText(final View v, final File f) {
ImageView i = (ImageView) v.findViewById(R.id.recording_player_play);
final boolean playing = player != null && player.isPlaying();
i.setImageResource(playing ? R.drawable.pause : R.drawable.play);
TextView start = (TextView) v.findViewById(R.id.recording_player_start);
SeekBar bar = (SeekBar) v.findViewById(R.id.recording_player_seek);
TextView end = (TextView) v.findViewById(R.id.recording_player_end);
int c = 0;
int d = durations.get(f);
if (player != null) {
c = player.getCurrentPosition();
d = player.getDuration();
}
bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (!fromUser)
return;
if (player == null)
playerPlay(v, f);
if (player != null) {
player.seekTo(progress);
if (!player.isPlaying())
playerPlay(v, f);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
start.setText(MainLibrary.formatDuration(getContext(), c));
bar.setMax(d);
bar.setKeyProgressIncrement(1);
bar.setProgress(c);
end.setText("-" + MainLibrary.formatDuration(getContext(), d - c));
return playing;
}
public void select(int pos) {
selected = pos;
notifyDataSetChanged();
playerStop();
}
}
public void setAppTheme(int id) {
super.setTheme(id);
themeId = id;
@ -480,25 +74,19 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
setContentView(R.layout.activity_main);
storage = new Storage(this);
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
storage = new Storage(this);
handler = new Handler();
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
// if (Build.VERSION.SDK_INT >= 16)
// toolbar.setBackground(new ColorDrawable(MainApplication.getActionbarColor(this)));
// else
// toolbar.setBackgroundDrawable(new ColorDrawable(MainApplication.getActionbarColor(this)));
setSupportActionBar(toolbar);
fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
fab.setClickable(false);
recordings.select(-1);
RecordingActivity.startActivity(MainActivity.this, false);
// Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
@ -506,10 +94,8 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
}
});
recordings = new Recordings(this);
list = (ListView) findViewById(R.id.list);
list.setOnScrollListener(this);
recordings = new Recordings(this, list);
list.setAdapter(recordings);
list.setEmptyView(findViewById(R.id.empty_list));
@ -525,11 +111,6 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
}
}
// load recordings
void load() {
recordings.scan(storage.getStoragePath());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
@ -578,16 +159,14 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
}
if (permitted(PERMISSIONS))
load();
recordings.load();
else
load();
recordings.load();
checkPending();
updateHeader();
fab.setClickable(true);
final int selected = getLastRecording();
handler.post(new Runnable() {
@Override
@ -631,7 +210,7 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
case 1:
if (permitted(permissions)) {
storage.migrateLocalStorage();
load();
recordings.load();
checkPending();
} else {
Toast.makeText(this, R.string.not_permitted, Toast.LENGTH_SHORT).show();
@ -666,15 +245,6 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
return true;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
this.scrollState = scrollState;
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@ -682,7 +252,7 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
handler.post(new Runnable() {
@Override
public void run() {
list.smoothScrollToPosition(recordings.selected);
list.smoothScrollToPosition(recordings.getSelected());
}
});
}

View file

@ -38,15 +38,15 @@ import com.github.axet.androidlibrary.animations.MarginBottomAnimation;
import com.github.axet.androidlibrary.app.MainLibrary;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiorecorder.app.MainApplication;
import com.github.axet.audiorecorder.app.RawSamples;
import com.github.axet.audiorecorder.app.Sound;
import com.github.axet.audiorecorder.app.Storage;
import com.github.axet.audiorecorder.encoders.Encoder;
import com.github.axet.audiorecorder.encoders.EncoderInfo;
import com.github.axet.audiorecorder.encoders.Factory;
import com.github.axet.audiorecorder.encoders.FileEncoder;
import com.github.axet.audiolibrary.app.RawSamples;
import com.github.axet.audiolibrary.app.Sound;
import com.github.axet.audiolibrary.app.Storage;
import com.github.axet.audiolibrary.encoders.Encoder;
import com.github.axet.audiolibrary.encoders.EncoderInfo;
import com.github.axet.audiolibrary.encoders.Factory;
import com.github.axet.audiolibrary.encoders.FileEncoder;
import com.github.axet.audiorecorder.services.RecordingService;
import com.github.axet.audiorecorder.widgets.PitchView;
import com.github.axet.audiolibrary.widgets.PitchView;
import java.io.File;
@ -439,7 +439,7 @@ public class RecordingActivity extends AppCompatActivity {
final ImageView playButton = (ImageView) box.findViewById(R.id.recording_play);
if (show) {
playButton.setImageResource(R.drawable.pause);
playButton.setImageResource(R.drawable.ic_pause_24dp);
playIndex = editSample;
@ -478,7 +478,7 @@ public class RecordingActivity extends AppCompatActivity {
play = null;
}
pitch.play(-1);
playButton.setImageResource(R.drawable.play);
playButton.setImageResource(R.drawable.ic_play_arrow_black_24dp);
}
}

View file

@ -26,7 +26,7 @@ import android.widget.Toast;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiorecorder.app.MainApplication;
import com.github.axet.audiorecorder.encoders.Factory;
import com.github.axet.audiolibrary.encoders.Factory;
import java.lang.reflect.Array;
import java.util.ArrayList;

View file

@ -10,83 +10,12 @@ import com.github.axet.androidlibrary.app.MainLibrary;
import com.github.axet.androidlibrary.widgets.ThemeUtils;
import com.github.axet.audiorecorder.R;
public class MainApplication extends Application {
public static final String PREFERENCE_STORAGE = "storage_path";
public static final String PREFERENCE_RATE = "sample_rate";
public static final String PREFERENCE_CALL = "call";
public static final String PREFERENCE_SILENT = "silence";
public static final String PREFERENCE_ENCODING = "encoding";
public static final String PREFERENCE_LAST = "last_recording";
public static final String PREFERENCE_THEME = "theme";
public static final String PREFERENCE_CHANNELS = "channels";
public class MainApplication extends com.github.axet.audiolibrary.app.MainApplication {
@Override
public void onCreate() {
super.onCreate();
PreferenceManager.setDefaultValues(this, R.xml.pref_general, false);
Context context = this;
context.setTheme(getUserTheme());
}
public static int getTheme(Context context, int light, int dark) {
final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
String theme = shared.getString(PREFERENCE_THEME, "");
if (theme.equals("Theme_Dark")) {
return dark;
} else {
return light;
}
}
public static int getActionbarColor(Context context) {
int colorId = MainApplication.getTheme(context, R.attr.colorPrimary, R.attr.secondBackground);
int color = ThemeUtils.getThemeColor(context, colorId);
return color;
}
public int getUserTheme() {
return getTheme(this, R.style.AppThemeLight, R.style.AppThemeDark);
}
public String formatFree(long free, long left) {
String str = "";
long diff = left;
int diffSeconds = (int) (diff / 1000 % 60);
int diffMinutes = (int) (diff / (60 * 1000) % 60);
int diffHours = (int) (diff / (60 * 60 * 1000) % 24);
int diffDays = (int) (diff / (24 * 60 * 60 * 1000));
if (diffDays > 0) {
str = getResources().getQuantityString(R.plurals.days, diffDays, diffDays);
} else if (diffHours > 0) {
str = getResources().getQuantityString(R.plurals.hours, diffHours, diffHours);
} else if (diffMinutes > 0) {
str = getResources().getQuantityString(R.plurals.minutes, diffMinutes, diffMinutes);
} else if (diffSeconds > 0) {
str = getResources().getQuantityString(R.plurals.seconds, diffSeconds, diffSeconds);
}
return getString(R.string.title_header, MainLibrary.formatSize(this, free), str);
}
public static int getChannels(Context context) {
final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
int i = Integer.parseInt(shared.getString(MainApplication.PREFERENCE_CHANNELS, "1"));
return i;
}
public static int getMode(Context context) {
switch (getChannels(context)) {
case 1:
return AudioFormat.CHANNEL_IN_MONO;
case 2:
return AudioFormat.CHANNEL_IN_STEREO;
default:
throw new RuntimeException("unknown mode");
}
}
}

View file

@ -68,7 +68,6 @@ public class RecordingService extends Service {
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
receiver = new RecordingReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
@ -142,7 +141,7 @@ public class RecordingService extends Service {
view.setOnClickPendingIntent(R.id.status_bar_latest_event_content, main);
view.setTextViewText(R.id.notification_text, ".../" + targetFile);
view.setOnClickPendingIntent(R.id.notification_pause, pe);
view.setImageViewResource(R.id.notification_pause, !recording ? R.drawable.play : R.drawable.pause);
view.setImageViewResource(R.id.notification_pause, !recording ? R.drawable.ic_play_arrow_black_24dp : R.drawable.ic_pause_24dp);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setOngoing(true)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 552 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 624 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 893 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -34,7 +34,7 @@
</LinearLayout>
<com.github.axet.audiorecorder.widgets.PitchView
<com.github.axet.audiolibrary.widgets.PitchView
android:id="@+id/recording_pitch"
android:layout_width="match_parent"
android:layout_height="120dp"
@ -65,7 +65,7 @@
android:layout_width="40dp"
android:layout_height="40dp"
android:background="?attr/roundButton"
android:src="@drawable/play" />
android:src="@drawable/ic_play_arrow_black_24dp" />
<ImageButton
android:id="@+id/recording_edit_done"

View file

@ -16,10 +16,6 @@
<item>8 kHz (телефон)</item>
</string-array>
<string-array name="encodings_text">
<item>.wav (по умолчанию)</item>
</string-array>
<string-array name="channels_text">
<item>Моно (по умолчанию)</item>
<item>Стерео</item>
@ -28,13 +24,6 @@
<string name="action_settings">Настройки</string>
<string name="not_permitted">Доступ запрещен</string>
<string name="no_folder_app">Программа для просмотра папок не установлена</string>
<string name="file_not_found">Файл не найден</string>
<string name="shared_via">"Создано с помощью: %1$s"</string>
<string name="rename_recording">Переименовать запись</string>
<string name="no">Нет</string>
<string name="yes">Да</string>
<string name="are_you_sure">Вы уверены?</string>
<string name="delete_recording">Удалить запись</string>
<string name="hold_by_call">пауза (звонок)</string>
<string name="encoding">кодировка</string>
<string name="pause">пауза</string>
@ -44,10 +33,6 @@
<string name="recording">запись</string>
<string name="encoding_title">Кодирование...</string>
<string name="recording_title">Запись</string>
<string name="db">дБ</string>
<string name="title_header">%1$s свободно ~ %2$s</string>
<string name="rename">Переименовать</string>
<string name="delete">Удалить</string>
<string name="open_recording_folder">Открыть папку с записями</string>
<string name="recording_list_is_empty">Список записей пуст.\n\nНажмите на \'Микрофон\' чтобы начать запись.</string>
</resources>

View file

@ -1,6 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="titleColor" format="color" />
<attr name="secondBackground" format="color" />
<attr name="roundButton" format="reference" />
</resources>

View file

@ -1,8 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="secondBackground">#33333333</color>
<color name="colorAccentLight">#FF4081</color>
<color name="colorAccentDark">#a4a4a4</color>
</resources>

View file

@ -21,14 +21,6 @@
<item>8000</item>
</string-array>
<string-array name="encodings_text">
<item>.wav (default)</item>
</string-array>
<string-array name="encodings_values" translatable="false">
<item>wav</item>
</string-array>
<string-array name="themes_text">
<item>Theme White (default)</item>
<item>Theme Dark</item>
@ -52,13 +44,6 @@
<string name="action_settings">Settings</string>
<string name="not_permitted">Not permitted</string>
<string name="no_folder_app">No folder view application installed</string>
<string name="file_not_found">File not found</string>
<string name="shared_via">"Shared via %1$s"</string>
<string name="rename_recording">Rename Recording</string>
<string name="no">No</string>
<string name="yes">Yes</string>
<string name="are_you_sure">"Are you sure ? "</string>
<string name="delete_recording">Delete Recording</string>
<string name="hold_by_call">pause (hold by call)</string>
<string name="encoding">encoding</string>
<string name="pause">pause</string>
@ -68,10 +53,6 @@
<string name="recording">recording</string>
<string name="encoding_title">Encoding...</string>
<string name="recording_title">Recording</string>
<string name="title_header">%1$s free ~ %2$s left</string>
<string name="db">dB</string>
<string name="rename">Rename</string>
<string name="delete">Delete</string>
<string name="open_recording_folder">Open Recording Folder</string>
<string name="recording_list_is_empty">Recording List is Empty\n\nClick Record to Start Recording</string>
</resources>

View file

@ -1,48 +1,2 @@
<resources>
<style name="AppThemeLight" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccentLight</item>
<item name="titleColor">@color/colorPrimary</item>
<item name="secondBackground">#c2c2c2</item>
<item name="roundButton">@drawable/round_button_light</item>
<item name="alertDialogTheme">@style/AppThemeDialogLight</item>
</style>
<style name="AppThemeDialogLight" parent="@style/Theme.AppCompat.Light.Dialog.Alert">
<item name="colorAccent">@color/colorAccentLight</item>
</style>
<style name="AppThemeLight.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="AppThemeLight.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:textColorPrimary">@android:color/white</item>
</style>
<style name="AppThemeLight.PopupOverlay" parent="ThemeOverlay.AppCompat.Light">
</style>
<style name="AppThemeDark" parent="Theme.AppCompat">
<item name="colorPrimaryDark">@color/primary_dark_material_dark</item>
<item name="colorPrimary">@color/primary_material_dark</item>
<item name="colorAccent">@color/colorAccentDark</item>
<item name="titleColor">@android:color/primary_text_dark</item>
<item name="secondBackground">#151515</item>
<item name="roundButton">@drawable/round_button_dark</item>
<item name="alertDialogTheme">@style/AppThemeDialogDark</item>
</style>
<style name="AppThemeDialogDark" parent="@style/Theme.AppCompat.Dialog.Alert">
<item name="colorAccent">@color/colorAccentDark</item>
</style>
<style name="AppThemeDark.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources>

View file

@ -1 +1 @@
include ':app', ':android-library', ':jebml'
include ':app', ':android-library', ':jebml', ':android-audio-library'