Merge branch 'audiorecorder-3.0.0'
This commit is contained in:
commit
ca2ee7e19e
7 changed files with 148 additions and 48 deletions
|
|
@ -8,8 +8,8 @@ android {
|
|||
applicationId "com.github.axet.audiorecorder"
|
||||
minSdkVersion 9
|
||||
targetSdkVersion 23
|
||||
versionCode 164
|
||||
versionName "2.1.0"
|
||||
versionCode 165
|
||||
versionName "3.0.0"
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
|
|
@ -43,5 +43,5 @@ android {
|
|||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile 'com.github.axet:android-audio-library:0.1.0' // compile project(':android-audio-library')
|
||||
compile 'com.github.axet:android-audio-library:1.0.0' // compile project(':android-audio-library')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.github.axet.audiorecorder.activities;
|
|||
import android.Manifest;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
|
|
@ -10,12 +11,18 @@ import android.content.IntentFilter;
|
|||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.StructStatVfs;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
|
@ -33,6 +40,7 @@ import com.github.axet.audiorecorder.app.MainApplication;
|
|||
import com.github.axet.audiorecorder.services.RecordingService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Collections;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
|
@ -130,7 +138,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
Intent showIntent() {
|
||||
Uri selectedUri = Uri.fromFile(storage.getStoragePath());
|
||||
Uri selectedUri = storage.getStoragePath();
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(selectedUri, "resource/folder");
|
||||
return intent;
|
||||
|
|
@ -187,12 +195,10 @@ public class MainActivity extends AppCompatActivity {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Storage.permitted(MainActivity.this, PERMISSIONS)) {
|
||||
try {
|
||||
storage.migrateLocalStorage();
|
||||
} catch (RuntimeException e) {
|
||||
Error(e);
|
||||
}
|
||||
try {
|
||||
storage.migrateLocalStorage();
|
||||
} catch (RuntimeException e) {
|
||||
Error(e);
|
||||
}
|
||||
|
||||
final int selected = getLastRecording();
|
||||
|
|
@ -225,11 +231,9 @@ public class MainActivity extends AppCompatActivity {
|
|||
int getLastRecording() {
|
||||
final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String last = shared.getString(MainApplication.PREFERENCE_LAST, "");
|
||||
last = last.toLowerCase();
|
||||
for (int i = 0; i < recordings.getCount(); i++) {
|
||||
File f = recordings.getItem(i);
|
||||
String n = f.getName().toLowerCase();
|
||||
if (n.equals(last)) {
|
||||
Uri f = recordings.getItem(i);
|
||||
if (storage.getDocumentName(f).equals(last)) {
|
||||
SharedPreferences.Editor edit = shared.edit();
|
||||
edit.putString(MainApplication.PREFERENCE_LAST, "");
|
||||
edit.commit();
|
||||
|
|
@ -277,8 +281,8 @@ public class MainActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
void updateHeader() {
|
||||
File f = storage.getStoragePath();
|
||||
long free = Storage.getFree(f);
|
||||
Uri uri = storage.getStoragePath();
|
||||
long free = storage.getFree(uri);
|
||||
long sec = Storage.average(this, free);
|
||||
TextView text = (TextView) findViewById(R.id.space_left);
|
||||
text.setText(MainApplication.formatFree(this, free, sec));
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.Manifest;
|
|||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
|
|
@ -13,10 +14,12 @@ import android.content.pm.PackageManager;
|
|||
import android.media.AudioFormat;
|
||||
import android.media.AudioRecord;
|
||||
import android.media.MediaRecorder;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
|
|
@ -36,6 +39,7 @@ import android.widget.Toast;
|
|||
import com.github.axet.androidlibrary.animations.MarginBottomAnimation;
|
||||
import com.github.axet.androidlibrary.sound.AudioTrack;
|
||||
import com.github.axet.audiolibrary.app.RawSamples;
|
||||
import com.github.axet.audiolibrary.app.Recordings;
|
||||
import com.github.axet.audiolibrary.app.Sound;
|
||||
import com.github.axet.audiolibrary.encoders.Encoder;
|
||||
import com.github.axet.audiolibrary.encoders.EncoderInfo;
|
||||
|
|
@ -47,7 +51,13 @@ import com.github.axet.audiorecorder.app.MainApplication;
|
|||
import com.github.axet.audiorecorder.app.Storage;
|
||||
import com.github.axet.audiorecorder.services.RecordingService;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
||||
|
|
@ -75,7 +85,7 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
// pitch size in samples. how many samples count need to update view. 4410 for 100ms update.
|
||||
int samplesUpdate;
|
||||
// output target file 2016-01-01 01.01.01.wav
|
||||
File targetFile = null;
|
||||
Uri targetUri = null;
|
||||
// how many samples passed for current recording
|
||||
long samplesTime;
|
||||
// current cut position in samples from begining of file
|
||||
|
|
@ -172,22 +182,26 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
try {
|
||||
if (storage.recordingPending()) {
|
||||
String file = shared.getString(MainApplication.PREFERENCE_TARGET, null);
|
||||
if (file != null)
|
||||
targetFile = new File(file);
|
||||
if (file != null) {
|
||||
if (file.startsWith(ContentResolver.SCHEME_CONTENT))
|
||||
targetUri = Uri.parse(file);
|
||||
else
|
||||
targetUri = Uri.fromFile(new File(file));
|
||||
}
|
||||
}
|
||||
if (targetFile == null)
|
||||
targetFile = storage.getNewFile();
|
||||
if (targetUri == null)
|
||||
targetUri = storage.getNewFile();
|
||||
SharedPreferences.Editor editor = shared.edit();
|
||||
editor.putString(MainApplication.PREFERENCE_TARGET, targetFile.toString());
|
||||
editor.putString(MainApplication.PREFERENCE_TARGET, targetUri.toString());
|
||||
editor.commit();
|
||||
} catch (RuntimeException e) {
|
||||
Log.d(TAG, "onCreate", e);
|
||||
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
title.setText(targetFile.getName());
|
||||
|
||||
title.setText(storage.getDocumentName(targetUri));
|
||||
|
||||
if (shared.getBoolean(MainApplication.PREFERENCE_CALL, false)) {
|
||||
TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
|
|
@ -343,7 +357,7 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
|
||||
boolean recording = thread != null;
|
||||
|
||||
RecordingService.startService(this, targetFile.getName(), recording, encoder != null);
|
||||
RecordingService.startService(this, storage.getDocumentName(targetUri), recording, encoder != null);
|
||||
|
||||
if (recording) {
|
||||
pitch.record();
|
||||
|
|
@ -368,7 +382,7 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
|
||||
stopRecording();
|
||||
|
||||
RecordingService.startService(this, targetFile.getName(), thread != null, encoder != null);
|
||||
RecordingService.startService(this, storage.getDocumentName(targetUri), thread != null, encoder != null);
|
||||
|
||||
pitch.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
|
|
@ -740,7 +754,7 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
}, "RecordingThread");
|
||||
thread.start();
|
||||
|
||||
RecordingService.startService(this, targetFile.getName(), thread != null, encoder != null);
|
||||
RecordingService.startService(this, storage.getDocumentName(targetUri), thread != null, encoder != null);
|
||||
}
|
||||
|
||||
// calcuale buffer length dynamically, this way we can reduce thread cycles when activity in background
|
||||
|
|
@ -823,9 +837,9 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
|
||||
void encoding(final Runnable run) {
|
||||
final File in = storage.getTempRecording();
|
||||
final File out = targetFile;
|
||||
final File out = storage.getTempEncoding();
|
||||
|
||||
File parent = targetFile.getParentFile();
|
||||
File parent = out.getParentFile();
|
||||
|
||||
if (!parent.exists()) {
|
||||
if (!parent.mkdirs()) { // in case if it were manually deleted
|
||||
|
|
@ -844,11 +858,11 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
|
||||
encoder = new FileEncoder(this, in, e);
|
||||
|
||||
RecordingService.startService(this, targetFile.getName(), thread != null, encoder != null);
|
||||
RecordingService.startService(this, storage.getDocumentName(targetUri), thread != null, encoder != null);
|
||||
|
||||
final ProgressDialog d = new ProgressDialog(this);
|
||||
d.setTitle(R.string.encoding_title);
|
||||
d.setMessage(".../" + targetFile.getName());
|
||||
d.setMessage(".../" + storage.getDocumentName(targetUri));
|
||||
d.setMax(100);
|
||||
d.setCancelable(false);
|
||||
d.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
|
|
@ -864,10 +878,32 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
@Override
|
||||
public void run() {
|
||||
d.cancel();
|
||||
storage.delete(in);
|
||||
|
||||
ContentResolver resolver = getContentResolver();
|
||||
try {
|
||||
InputStream is = new FileInputStream(out);
|
||||
OutputStream os = resolver.openOutputStream(targetUri);
|
||||
IOUtils.copy(is, os);
|
||||
is.close();
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
storage.delete(out); // delete tmp encoding file
|
||||
try {
|
||||
storage.delete(targetUri);
|
||||
} catch (RuntimeException ee) {
|
||||
Log.d(TAG, "unable to delete target uri", e); // ignore, not even created?
|
||||
}
|
||||
Error(e);
|
||||
d.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
storage.delete(in); // delete raw recording
|
||||
String n = out.getName();
|
||||
storage.delete(out); // delete tmp encoding file
|
||||
|
||||
SharedPreferences.Editor edit = shared.edit();
|
||||
edit.putString(MainApplication.PREFERENCE_LAST, out.getName());
|
||||
edit.putString(MainApplication.PREFERENCE_LAST, n);
|
||||
edit.commit();
|
||||
|
||||
run.run();
|
||||
|
|
|
|||
|
|
@ -244,7 +244,8 @@ public class SettingsActivity extends AppCompatActivity implements SharedPrefere
|
|||
bindPreferenceSummaryToValue(pm.findPreference(MainApplication.PREFERENCE_CHANNELS));
|
||||
bindPreferenceSummaryToValue(pm.findPreference(MainApplication.PREFERENCE_FORMAT));
|
||||
StoragePathPreferenceCompat s = (StoragePathPreferenceCompat) pm.findPreference(MainApplication.PREFERENCE_STORAGE);
|
||||
s.setPermissionsDialog(this, PERMISSIONS, 1);
|
||||
// s.setPermissionsDialog(this, PERMISSIONS, 1);
|
||||
s.setStorageAccessFramework(this, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -281,6 +282,19 @@ public class SettingsActivity extends AppCompatActivity implements SharedPrefere
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
StoragePathPreferenceCompat s = (StoragePathPreferenceCompat) findPreference(MainApplication.PREFERENCE_STORAGE);
|
||||
|
||||
switch (requestCode) {
|
||||
case 2:
|
||||
s.onActivityResult(resultCode, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
package com.github.axet.audiorecorder.app;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
|
@ -10,13 +15,13 @@ import java.util.Date;
|
|||
|
||||
public class Storage extends com.github.axet.audiolibrary.app.Storage {
|
||||
|
||||
public static final String TMP_ENC = "encoding.data";
|
||||
|
||||
public Storage(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getNewFile() {
|
||||
|
||||
public Uri getNewFile() {
|
||||
SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String ext = shared.getString(MainApplication.PREFERENCE_ENCODING, "");
|
||||
|
||||
|
|
@ -28,13 +33,55 @@ public class Storage extends com.github.axet.audiolibrary.app.Storage {
|
|||
format = format.replaceAll("%I", ISO8601.format(new Date()));
|
||||
format = format.replaceAll("%T", "" + System.currentTimeMillis() / 1000);
|
||||
|
||||
File parent = getStoragePath();
|
||||
if (!parent.exists()) {
|
||||
if (!parent.mkdirs())
|
||||
throw new RuntimeException("Unable to create: " + parent);
|
||||
}
|
||||
Uri path = getStoragePath();
|
||||
String s = path.getScheme();
|
||||
|
||||
return getNextFile(parent, format, ext);
|
||||
if (Build.VERSION.SDK_INT >= 21 && s.startsWith(ContentResolver.SCHEME_CONTENT)) {
|
||||
Uri n = getNextFile(path, format, ext);
|
||||
String d = getDocumentName(n);
|
||||
Uri docUri = DocumentsContract.buildDocumentUriUsingTree(path, DocumentsContract.getTreeDocumentId(path));
|
||||
String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(d);
|
||||
Uri childrenUri = DocumentsContract.createDocument(context.getContentResolver(), docUri, mime, d);
|
||||
return childrenUri;
|
||||
} else if (s.startsWith(ContentResolver.SCHEME_FILE)) {
|
||||
File f = new File(path.getPath());
|
||||
if (!f.exists() && !f.mkdirs()) {
|
||||
throw new RuntimeException("Unable to create: " + path);
|
||||
}
|
||||
return Uri.fromFile(getNextFile(f, format, ext));
|
||||
} else {
|
||||
throw new RuntimeException("unknown uri");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public File getTempEncoding() {
|
||||
File internal = new File(context.getCacheDir(), TMP_ENC);
|
||||
if (internal.exists())
|
||||
return internal;
|
||||
|
||||
// Starting in KITKAT, no permissions are required to read or write to the returned path;
|
||||
// it's always accessible to the calling app.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
if (!permitted(context, PERMISSIONS))
|
||||
return internal;
|
||||
}
|
||||
|
||||
File c = context.getExternalCacheDir();
|
||||
if (c == null) // some old phones <15API with disabled sdcard return null
|
||||
return internal;
|
||||
|
||||
File external = new File(c, TMP_ENC);
|
||||
|
||||
if (external.exists())
|
||||
return external;
|
||||
|
||||
long freeI = getFree(internal);
|
||||
long freeE = getFree(external);
|
||||
|
||||
if (freeI > freeE)
|
||||
return internal;
|
||||
else
|
||||
return external;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
|
|
@ -171,8 +172,8 @@ public class RecordingService extends Service {
|
|||
String text;
|
||||
if (targetFile == null) {
|
||||
title = getString(R.string.app_name);
|
||||
File f = storage.getStoragePath();
|
||||
long free = Storage.getFree(f);
|
||||
Uri f = storage.getStoragePath();
|
||||
long free = storage.getFree(f);
|
||||
long sec = Storage.average(this, free);
|
||||
text = MainApplication.formatFree(this, free, sec);
|
||||
view.setViewVisibility(R.id.notification_record, View.VISIBLE);
|
||||
|
|
@ -227,7 +228,6 @@ public class RecordingService extends Service {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onTaskRemoved(Intent rootIntent) {
|
||||
super.onTaskRemoved(rootIntent);
|
||||
|
|
|
|||
|
|
@ -54,8 +54,7 @@
|
|||
<ListView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="61dp"></ListView>
|
||||
</LinearLayout>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue