add MediaStore.Audio.Media.RECORD_SOUND_ACTION handler, thanks @pvagner for examples!
This commit is contained in:
parent
a7e1f45adb
commit
1b2f5a5eb2
7 changed files with 176 additions and 63 deletions
|
|
@ -53,6 +53,6 @@ android {
|
|||
|
||||
dependencies {
|
||||
testImplementation 'junit:junit:4.12'
|
||||
implementation 'com.github.axet:android-audio-library:1.0.169' // implementation project(':android-audio-library')
|
||||
implementation 'com.github.axet:android-audio-library:1.0.171' // implementation project(':android-audio-library')
|
||||
assets('com.google.android.exoplayer:exoplayer:2.7.3') { exclude group: 'com.android.support' }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,12 @@
|
|||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:exported="true"
|
||||
android:launchMode="singleInstance"
|
||||
android:showOnLockScreen="true" />
|
||||
android:showOnLockScreen="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.provider.MediaStore.RECORD_SOUND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<receiver
|
||||
android:name=".services.OnBootReceiver"
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@ import com.github.axet.androidlibrary.activities.AppCompatThemeActivity;
|
|||
import com.github.axet.androidlibrary.widgets.ErrorDialog;
|
||||
import com.github.axet.androidlibrary.preferences.OptimizationPreferenceCompat;
|
||||
import com.github.axet.androidlibrary.widgets.SearchView;
|
||||
import com.github.axet.audiolibrary.app.Storage;
|
||||
import com.github.axet.audiorecorder.R;
|
||||
import com.github.axet.audiorecorder.app.AudioApplication;
|
||||
import com.github.axet.audiorecorder.app.Recordings;
|
||||
import com.github.axet.audiorecorder.app.Storage;
|
||||
import com.github.axet.audiorecorder.services.RecordingService;
|
||||
|
||||
public class MainActivity extends AppCompatThemeActivity {
|
||||
|
|
|
|||
|
|
@ -4,17 +4,20 @@ import android.Manifest;
|
|||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Rect;
|
||||
import android.media.AudioFormat;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.v4.media.session.MediaButtonReceiver;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
import android.support.v4.media.session.PlaybackStateCompat;
|
||||
|
|
@ -34,9 +37,11 @@ import android.widget.ImageButton;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.axet.androidlibrary.animations.MarginBottomAnimation;
|
||||
import com.github.axet.androidlibrary.sound.AudioTrack;
|
||||
import com.github.axet.androidlibrary.activities.AppCompatThemeActivity;
|
||||
import com.github.axet.androidlibrary.animations.MarginBottomAnimation;
|
||||
import com.github.axet.androidlibrary.services.FileProvider;
|
||||
import com.github.axet.androidlibrary.services.StorageProvider;
|
||||
import com.github.axet.androidlibrary.sound.AudioTrack;
|
||||
import com.github.axet.androidlibrary.widgets.ErrorDialog;
|
||||
import com.github.axet.androidlibrary.widgets.OpenFileDialog;
|
||||
import com.github.axet.androidlibrary.widgets.PopupWindowCompat;
|
||||
|
|
@ -75,12 +80,13 @@ public class RecordingActivity extends AppCompatThemeActivity {
|
|||
public static final String PAUSE_BUTTON = RecordingActivity.class.getCanonicalName() + ".PAUSE_BUTTON";
|
||||
public static final String ACTION_FINISH_RECORDING = BuildConfig.APPLICATION_ID + ".STOP_RECORDING";
|
||||
|
||||
public static String START_RECORDING = RecordingService.class.getCanonicalName() + ".START_RECORDING";
|
||||
public static String STOP_RECORDING = RecordingService.class.getCanonicalName() + ".STOP_RECORDING";
|
||||
public static final String START_RECORDING = RecordingService.class.getCanonicalName() + ".START_RECORDING";
|
||||
public static final String STOP_RECORDING = RecordingService.class.getCanonicalName() + ".STOP_RECORDING";
|
||||
|
||||
PhoneStateChangeListener pscl = new PhoneStateChangeListener();
|
||||
FileEncoder encoder;
|
||||
MediaSessionCompat msc;
|
||||
Intent recordSoundIntent = null;
|
||||
|
||||
boolean start = true; // do we need to start recording immidiatly?
|
||||
|
||||
|
|
@ -208,6 +214,7 @@ public class RecordingActivity extends AppCompatThemeActivity {
|
|||
touchListener(w);
|
||||
}
|
||||
|
||||
@SuppressWarnings("RestrictedApi")
|
||||
public void touchListener(final Window w) {
|
||||
final Window.Callback c = w.getCallback();
|
||||
w.setCallback(new WindowCallbackWrapper(c) {
|
||||
|
|
@ -404,37 +411,14 @@ public class RecordingActivity extends AppCompatThemeActivity {
|
|||
receiver.filter.addAction(ACTION_FINISH_RECORDING);
|
||||
receiver.registerReceiver(this);
|
||||
|
||||
AudioApplication app = AudioApplication.from(this);
|
||||
try {
|
||||
if (app.recording == null)
|
||||
app.recording = new AudioApplication.RecordingStorage(this, pitch.getPitchTime());
|
||||
recording = app.recording;
|
||||
synchronized (recording.handlers) {
|
||||
recording.handlers.add(handler);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.d(TAG, "onCreate", e);
|
||||
Toast.Error(this, e);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
sendBroadcast(new Intent(START_RECORDING));
|
||||
|
||||
edit(false, false);
|
||||
|
||||
title.setText(Storage.getName(this, recording.targetUri));
|
||||
|
||||
final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
if (shared.getBoolean(AudioApplication.PREFERENCE_CALL, false)) {
|
||||
TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
tm.listen(pscl, PhoneStateListener.LISTEN_CALL_STATE);
|
||||
}
|
||||
|
||||
recording.updateBufferSize(false);
|
||||
|
||||
loadSamples();
|
||||
|
||||
final View cancel = findViewById(R.id.recording_cancel);
|
||||
cancel.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
|
|
@ -482,15 +466,19 @@ public class RecordingActivity extends AppCompatThemeActivity {
|
|||
if (encoder != null)
|
||||
return;
|
||||
String msg;
|
||||
if (shared.getBoolean(AudioApplication.PREFERENCE_FLY, false)) {
|
||||
if (shared.getBoolean(AudioApplication.PREFERENCE_FLY, false))
|
||||
msg = getString(R.string.recording_status_recording);
|
||||
} else
|
||||
else
|
||||
msg = getString(R.string.recording_status_encoding);
|
||||
stopRecording(msg);
|
||||
try {
|
||||
encoding(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (recordSoundIntent != null) {
|
||||
recordSoundIntent.setDataAndType(StorageProvider.getProvider().share(recording.targetUri), Storage.getTypeByExt(Storage.getExt(RecordingActivity.this, recording.targetUri)));
|
||||
FileProvider.grantPermissions(RecordingActivity.this, recordSoundIntent, FileProvider.RW);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
|
@ -500,20 +488,83 @@ public class RecordingActivity extends AppCompatThemeActivity {
|
|||
}
|
||||
});
|
||||
|
||||
onCreateRecording();
|
||||
|
||||
Intent intent = getIntent();
|
||||
String a = intent.getAction();
|
||||
if (a != null && a.equals(START_PAUSE)) { // pretend we already start it
|
||||
start = false;
|
||||
stopRecording(getString(R.string.recording_status_pause));
|
||||
}
|
||||
if (a != null && a.equals(ERROR))
|
||||
muted = new ErrorDialog(this, intent.getStringExtra("msg")).setTitle(intent.getStringExtra("title")).show();
|
||||
onIntent(intent);
|
||||
}
|
||||
|
||||
public void onCreateRecording() {
|
||||
final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
Intent intent = getIntent();
|
||||
String a = intent.getAction();
|
||||
|
||||
AudioApplication app = AudioApplication.from(this);
|
||||
try {
|
||||
if (app.recording == null) {
|
||||
Uri targetUri = null;
|
||||
Storage storage = new Storage(this);
|
||||
if (a != null && a.equals(MediaStore.Audio.Media.RECORD_SOUND_ACTION)) {
|
||||
if (storage.recordingPending()) {
|
||||
String file = shared.getString(AudioApplication.PREFERENCE_TARGET, null);
|
||||
if (file != null) // else pending recording comes from intent recording, resume recording
|
||||
throw new RuntimeException("finish pending recording first");
|
||||
}
|
||||
targetUri = storage.getNewIntentRecording();
|
||||
recordSoundIntent = new Intent();
|
||||
} else {
|
||||
if (storage.recordingPending()) {
|
||||
String file = shared.getString(AudioApplication.PREFERENCE_TARGET, null);
|
||||
if (file != null) {
|
||||
if (file.startsWith(ContentResolver.SCHEME_CONTENT))
|
||||
targetUri = Uri.parse(file);
|
||||
else if (file.startsWith(ContentResolver.SCHEME_FILE))
|
||||
targetUri = Uri.parse(file);
|
||||
else
|
||||
targetUri = Uri.fromFile(new File(file));
|
||||
}
|
||||
}
|
||||
if (targetUri == null)
|
||||
targetUri = storage.getNewFile();
|
||||
SharedPreferences.Editor editor = shared.edit();
|
||||
editor.putString(AudioApplication.PREFERENCE_TARGET, targetUri.toString());
|
||||
editor.commit();
|
||||
}
|
||||
Log.d(TAG, "create recording at: " + targetUri);
|
||||
app.recording = new AudioApplication.RecordingStorage(this, pitch.getPitchTime(), targetUri);
|
||||
}
|
||||
recording = app.recording;
|
||||
synchronized (recording.handlers) {
|
||||
recording.handlers.add(handler);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Toast.Error(this, e);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
sendBroadcast(new Intent(START_RECORDING));
|
||||
title.setText(Storage.getName(this, recording.targetUri));
|
||||
recording.updateBufferSize(false);
|
||||
loadSamples();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
onIntent(intent);
|
||||
}
|
||||
|
||||
public void onIntent(Intent intent) {
|
||||
String a = intent.getAction();
|
||||
if (a != null && a.equals(ERROR))
|
||||
muted = new ErrorDialog(this, intent.getStringExtra("msg")).setTitle(intent.getStringExtra("title")).show();
|
||||
}
|
||||
|
||||
void loadSamples() {
|
||||
|
|
@ -1013,8 +1064,16 @@ public class RecordingActivity extends AppCompatThemeActivity {
|
|||
|
||||
@Override
|
||||
public void finish() {
|
||||
super.finish();
|
||||
MainActivity.startActivity(this);
|
||||
if (recordSoundIntent != null) {
|
||||
if (recordSoundIntent.getData() == null)
|
||||
setResult(RESULT_CANCELED);
|
||||
else
|
||||
setResult(Activity.RESULT_OK, recordSoundIntent);
|
||||
super.finish();
|
||||
} else {
|
||||
super.finish();
|
||||
MainActivity.startActivity(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void headset(boolean b, final boolean recording) {
|
||||
|
|
|
|||
|
|
@ -85,34 +85,15 @@ public class AudioApplication extends com.github.axet.audiolibrary.app.MainAppli
|
|||
|
||||
public int pitchTime; // screen width
|
||||
|
||||
public RecordingStorage(Context context, int pitchTime) {
|
||||
public RecordingStorage(Context context, int pitchTime, Uri targetUri) {
|
||||
this.context = context;
|
||||
this.pitchTime = pitchTime;
|
||||
this.targetUri = targetUri;
|
||||
storage = new Storage(context);
|
||||
sound = new Sound(context);
|
||||
|
||||
sampleRate = Sound.getSampleRate(context);
|
||||
samplesUpdate = (int) (pitchTime * sampleRate / 1000f);
|
||||
samplesUpdateStereo = samplesUpdate * Sound.getChannels(context);
|
||||
|
||||
final SharedPreferences shared = android.preference.PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
if (storage.recordingPending()) {
|
||||
String file = shared.getString(AudioApplication.PREFERENCE_TARGET, null);
|
||||
if (file != null) {
|
||||
if (file.startsWith(ContentResolver.SCHEME_CONTENT))
|
||||
targetUri = Uri.parse(file);
|
||||
else if (file.startsWith(ContentResolver.SCHEME_FILE))
|
||||
targetUri = Uri.parse(file);
|
||||
else
|
||||
targetUri = Uri.fromFile(new File(file));
|
||||
}
|
||||
}
|
||||
if (targetUri == null)
|
||||
targetUri = storage.getNewFile();
|
||||
SharedPreferences.Editor editor = shared.edit();
|
||||
editor.putString(AudioApplication.PREFERENCE_TARGET, targetUri.toString());
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
public void startRecording() {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import android.net.Uri;
|
|||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.github.axet.androidlibrary.services.StorageProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
|
@ -15,6 +17,8 @@ import java.util.TimeZone;
|
|||
|
||||
public class Storage extends com.github.axet.audiolibrary.app.Storage {
|
||||
|
||||
public static final String SHARE = "share";
|
||||
|
||||
public static final SimpleDateFormat ISO8601Z = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US) {{
|
||||
setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
}};
|
||||
|
|
@ -36,9 +40,7 @@ public class Storage extends com.github.axet.audiolibrary.app.Storage {
|
|||
SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String ext = shared.getString(AudioApplication.PREFERENCE_ENCODING, "");
|
||||
|
||||
String format = "%s";
|
||||
|
||||
format = shared.getString(AudioApplication.PREFERENCE_FORMAT, format);
|
||||
String format = shared.getString(AudioApplication.PREFERENCE_FORMAT, "%s");
|
||||
|
||||
format = getFormatted(format, new Date());
|
||||
|
||||
|
|
@ -49,14 +51,75 @@ public class Storage extends com.github.axet.audiolibrary.app.Storage {
|
|||
return getNextFile(context, path, format, ext);
|
||||
} else if (s.equals(ContentResolver.SCHEME_FILE)) {
|
||||
File f = getFile(path);
|
||||
if (!f.exists() && !f.mkdirs() && !f.exists())
|
||||
throw new RuntimeException("Unable to create: " + path);
|
||||
if (!Storage.mkdirs(f))
|
||||
throw new RuntimeException("unable to create: " + path);
|
||||
return Uri.fromFile(getNextFile(f, format, ext));
|
||||
} else {
|
||||
throw new UnknownUri();
|
||||
}
|
||||
}
|
||||
|
||||
public File getIntentEncoding() {
|
||||
File internal = getFilesDir(context, SHARE);
|
||||
|
||||
// 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_RW))
|
||||
return internal;
|
||||
}
|
||||
|
||||
File external = context.getExternalFilesDir(SHARE);
|
||||
if (external == null) // some old phones <15API with disabled sdcard return null
|
||||
return internal;
|
||||
|
||||
try {
|
||||
long freeI = getFree(internal);
|
||||
long freeE = getFree(external);
|
||||
if (freeI > freeE)
|
||||
return internal;
|
||||
else
|
||||
return external;
|
||||
} catch (RuntimeException e) { // samsung devices unable to determine external folders
|
||||
return internal;
|
||||
}
|
||||
}
|
||||
|
||||
public Uri getNewIntentRecording() {
|
||||
SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String ext = shared.getString(AudioApplication.PREFERENCE_ENCODING, "");
|
||||
|
||||
String format = shared.getString(AudioApplication.PREFERENCE_FORMAT, "%s");
|
||||
|
||||
format = getFormatted(format, new Date());
|
||||
|
||||
File f = getIntentEncoding();
|
||||
|
||||
if (!Storage.mkdirs(f))
|
||||
throw new RuntimeException("unable to create: " + f);
|
||||
return Uri.fromFile(getNextFile(f, format, ext));
|
||||
}
|
||||
|
||||
public void deleteTmp() {
|
||||
File internal = getFilesDir(context, SHARE);
|
||||
deleteTmp(internal);
|
||||
File external = context.getExternalFilesDir(SHARE);
|
||||
deleteTmp(external);
|
||||
}
|
||||
|
||||
public void deleteTmp(File dir) {
|
||||
if (dir == null)
|
||||
return;
|
||||
long now = System.currentTimeMillis();
|
||||
File[] ff = dir.listFiles();
|
||||
if (ff == null)
|
||||
return;
|
||||
for (File f : ff) {
|
||||
if (f.isFile() && f.lastModified() + StorageProvider.TIMEOUT < now)
|
||||
Storage.delete(f);
|
||||
}
|
||||
}
|
||||
|
||||
public File getNewFile(File f, String ext) {
|
||||
SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
|
|
@ -66,9 +129,14 @@ public class Storage extends com.github.axet.audiolibrary.app.Storage {
|
|||
|
||||
format = getFormatted(format, new Date());
|
||||
|
||||
if (!f.exists() && !f.mkdirs() && !f.exists())
|
||||
if (!Storage.mkdirs(f))
|
||||
throw new RuntimeException("Unable to create: " + f);
|
||||
return getNextFile(f, format, ext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrateLocalStorage() {
|
||||
super.migrateLocalStorage();
|
||||
deleteTmp();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ buildscript {
|
|||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.4.2'
|
||||
classpath 'com.android.tools.build:gradle:3.5.1'
|
||||
classpath 'com.github.axet:gradle-android-dx:0.0.4'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue