lockscreen control only during lock screen

This commit is contained in:
Alexey Kuznetsov 2020-12-10 23:11:10 +03:00
commit 966e90339f
10 changed files with 279 additions and 53 deletions

View file

@ -25,6 +25,7 @@
android:theme="@style/RecThemeLight">
<service android:name=".services.RecordingService" />
<service android:name=".services.EncodingService" />
<service android:name=".services.ControlsService" />
<service
android:name=".services.TileService"
android:icon="@drawable/ic_mic_24dp"

View file

@ -46,6 +46,7 @@ import com.github.axet.audiorecorder.app.AudioApplication;
import com.github.axet.audiorecorder.app.EncodingStorage;
import com.github.axet.audiorecorder.app.Recordings;
import com.github.axet.audiorecorder.app.Storage;
import com.github.axet.audiorecorder.services.ControlsService;
import com.github.axet.audiorecorder.services.EncodingService;
import com.github.axet.audiorecorder.services.RecordingService;
@ -466,6 +467,7 @@ public class MainActivity extends AppCompatThemeActivity {
RecordingService.startIfPending(this);
EncodingService.startIfPending(this);
ControlsService.startIfEnabled(this);
try {
new Recordings.ExoLoader(this, false);

View file

@ -52,6 +52,7 @@ import com.github.axet.audiorecorder.app.AudioApplication;
import com.github.axet.audiorecorder.app.RecordingStorage;
import com.github.axet.audiorecorder.app.Storage;
import com.github.axet.audiorecorder.services.BluetoothReceiver;
import com.github.axet.audiorecorder.services.ControlsService;
import com.github.axet.audiorecorder.services.EncodingService;
import com.github.axet.audiorecorder.services.RecordingService;
@ -906,6 +907,7 @@ public class RecordingActivity extends AppCompatThemeActivity {
}
RecordingService.stopRecording(this);
ControlsService.startIfEnabled(this);
if (pscl != null) {
TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
@ -941,6 +943,7 @@ public class RecordingActivity extends AppCompatThemeActivity {
recording.startRecording();
RecordingService.startService(this, Storage.getName(this, recording.targetUri), true, duration);
ControlsService.hideIcon(this);
} catch (RuntimeException e) {
Toast.Error(RecordingActivity.this, e);
finish();

View file

@ -29,6 +29,7 @@ import com.github.axet.audiolibrary.widgets.RecordingVolumePreference;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiorecorder.app.AudioApplication;
import com.github.axet.audiorecorder.app.Storage;
import com.github.axet.audiorecorder.services.ControlsService;
import com.github.axet.audiorecorder.services.RecordingService;
import java.lang.reflect.Array;
@ -98,9 +99,9 @@ public class SettingsActivity extends AppCompatSettingsThemeActivity implements
super.onSharedPreferenceChanged(sharedPreferences, key);
if (key.equals(AudioApplication.PREFERENCE_CONTROLS)) {
if (sharedPreferences.getBoolean(AudioApplication.PREFERENCE_CONTROLS, false))
RecordingService.start(this);
ControlsService.start(this);
else
RecordingService.stop(this);
ControlsService.stop(this);
}
if (key.equals(AudioApplication.PREFERENCE_STORAGE))
storage.migrateLocalStorageDialog(this);
@ -249,6 +250,9 @@ public class SettingsActivity extends AppCompatSettingsThemeActivity implements
super.onResume();
SilencePreferenceCompat silent = (SilencePreferenceCompat) findPreference(AudioApplication.PREFERENCE_SILENT);
silent.onResume();
Preference controls = findPreference(AudioApplication.PREFERENCE_CONTROLS);
if (Build.VERSION.SDK_INT < 21)
controls.setVisible(false);
}
}
}

View file

@ -32,6 +32,7 @@ public class AudioApplication extends com.github.axet.audiolibrary.app.MainAppli
public static final String PREFERENCE_NEXT = "next";
public NotificationChannelCompat channelStatus;
public NotificationChannelCompat channelPersistent;
public RecordingStorage recording;
public EncodingStorage encodings;
@ -45,6 +46,7 @@ public class AudioApplication extends com.github.axet.audiolibrary.app.MainAppli
Log.d(TAG, "onCreate");
channelStatus = new NotificationChannelCompat(this, "status", "Status", NotificationManagerCompat.IMPORTANCE_LOW);
channelPersistent = new NotificationChannelCompat(this, "persistent", "Persistent", NotificationManagerCompat.IMPORTANCE_LOW);
encodings = new EncodingStorage(this);
switch (getVersion(PREFERENCE_VERSION, R.xml.pref_general)) {

View file

@ -0,0 +1,236 @@
package com.github.axet.audiorecorder.services;
import android.annotation.SuppressLint;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.widget.RemoteViews;
import com.github.axet.androidlibrary.app.AlarmManager;
import com.github.axet.androidlibrary.app.ProximityShader;
import com.github.axet.androidlibrary.preferences.OptimizationPreferenceCompat;
import com.github.axet.androidlibrary.services.PersistentService;
import com.github.axet.androidlibrary.widgets.NotificationChannelCompat;
import com.github.axet.androidlibrary.widgets.RemoteNotificationCompat;
import com.github.axet.androidlibrary.widgets.RemoteViewsCompat;
import com.github.axet.audiolibrary.app.Storage;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiorecorder.activities.MainActivity;
import com.github.axet.audiorecorder.activities.RecordingActivity;
import com.github.axet.audiorecorder.app.AudioApplication;
import java.io.File;
public class ControlsService extends PersistentService {
public static final String TAG = ControlsService.class.getSimpleName();
public static final int NOTIFICATION_CONTROLS_ICON = 3;
public static final int NOTIFICATION_PERSISTENT_ICON = 4;
Storage storage;
OptimizationPreferenceCompat.NotificationIcon controls;
public static String SHOW_ACTIVITY = ControlsService.class.getCanonicalName() + ".SHOW_ACTIVITY";
public static String RECORD_BUTTON = ControlsService.class.getCanonicalName() + ".RECORD_BUTTON";
public static String HIDE_ICON = ControlsService.class.getCanonicalName() + ".HIDE_ICON";
public static void startIfEnabled(Context context) { // notification controls enabled?
SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
if (!shared.getBoolean(AudioApplication.PREFERENCE_CONTROLS, false))
return;
start(context);
}
public static void start(Context context) { // start persistent icon service
start(context, new Intent(context, ControlsService.class));
}
public static void stop(Context context) {
stop(context, new Intent(context, ControlsService.class));
}
public static void hideIcon(Context context) {
SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
if (!shared.getBoolean(AudioApplication.PREFERENCE_CONTROLS, false))
return;
start(context, new Intent(context, ControlsService.class).setAction(HIDE_ICON));
}
public ControlsService() {
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onCreateOptimization() {
storage = new Storage(this);
optimization = new OptimizationPreferenceCompat.ServiceReceiver(this, NOTIFICATION_PERSISTENT_ICON, null, AudioApplication.PREFERENCE_NEXT) {
@Override
public void onCreateIcon(Service service, int id) {
controls = new OptimizationPreferenceCompat.NotificationIcon(ControlsService.this, NOTIFICATION_CONTROLS_ICON) {
@Override
public void updateIcon(Intent intent) {
KeyguardManager myKM = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
if (myKM.inKeyguardRestrictedInputMode() && !storage.recordingPending())
intent = new Intent();
else
intent = null;
super.updateIcon(intent);
}
@Override
public Notification build(Intent intent) {
PendingIntent main;
RemoteNotificationCompat.Builder builder;
String title;
String text;
title = getString(R.string.app_name);
Uri f = storage.getStoragePath();
long free = Storage.getFree(context, f);
long sec = Storage.average(context, free);
text = AudioApplication.formatFree(context, free, sec);
builder = new RemoteNotificationCompat.Low(context, R.layout.notifictaion);
builder.setViewVisibility(R.id.notification_record, View.VISIBLE);
builder.setViewVisibility(R.id.notification_pause, View.GONE);
main = PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent re = PendingIntent.getService(context, 0,
new Intent(context, ControlsService.class).setAction(RECORD_BUTTON),
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setOnClickPendingIntent(R.id.notification_record, re);
builder.setTheme(AudioApplication.getTheme(context, R.style.RecThemeLight, R.style.RecThemeDark))
.setChannel(AudioApplication.from(context).channelStatus)
.setImageViewTint(R.id.icon_circle, builder.getThemeColor(R.attr.colorButtonNormal))
.setTitle(title)
.setText(text)
.setWhen(controls.notification)
.setMainIntent(main)
.setAdaptiveIcon(R.drawable.ic_launcher_foreground)
.setSmallIcon(R.drawable.ic_launcher_notification)
.setOngoing(true);
return builder.build();
}
@Override
public boolean isOptimization() {
return false;
}
};
controls.create();
icon = new OptimizationPreferenceCompat.OptimizationIcon(service, id, key) {
@Override
public void updateIcon(Intent intent) {
super.updateIcon(intent);
}
@SuppressLint("RestrictedApi")
public Notification build(Intent intent) {
PendingIntent main;
RemoteNotificationCompat.Builder builder;
String title;
String text;
title = getString(R.string.app_name);
text = "Persistent Controls Icon";
builder = new RemoteNotificationCompat.Low(context, R.layout.notifictaion);
builder.setViewVisibility(R.id.notification_record, View.GONE);
builder.setViewVisibility(R.id.notification_pause, View.GONE);
main = PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
builder.setTheme(AudioApplication.getTheme(context, R.style.RecThemeLight, R.style.RecThemeDark))
.setChannel(AudioApplication.from(context).channelPersistent)
.setImageViewTint(R.id.icon_circle, builder.getThemeColor(R.attr.colorButtonNormal))
.setTitle(title)
.setText(text)
.setWhen(icon.notification)
.setMainIntent(main)
.setAdaptiveIcon(R.drawable.ic_launcher_foreground)
.setSmallIcon(R.drawable.ic_launcher_notification)
.setOngoing(true);
return builder.build();
}
};
icon.create();
}
@Override
public void updateIcon() {
super.updateIcon();
controls.updateIcon(null);
}
@Override
public boolean isOptimization() {
return true; // we not using optimization preference
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
String a = intent.getAction();
if (a == null)
return;
switch (a) {
case Intent.ACTION_USER_PRESENT:
optimization.updateIcon();
break;
case Intent.ACTION_SCREEN_ON:
optimization.updateIcon();
break;
case Intent.ACTION_SCREEN_OFF:
optimization.updateIcon();
break;
}
}
};
optimization.filters.addAction(Intent.ACTION_USER_PRESENT);
optimization.filters.addAction(Intent.ACTION_SCREEN_ON);
optimization.filters.addAction(Intent.ACTION_SCREEN_OFF);
optimization.create();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onStartCommand(Intent intent) {
String a = intent.getAction();
if (a == null) {
optimization.updateIcon();
} else if (a.equals(HIDE_ICON)) {
controls.hideIcon();
} else if (a.equals(RECORD_BUTTON)) {
RecordingActivity.startActivity(this, false);
} else if (a.equals(SHOW_ACTIVITY)) {
ProximityShader.closeSystemDialogs(this);
MainActivity.startActivity(this);
}
}
}

View file

@ -13,5 +13,6 @@ public class OnBootReceiver extends BroadcastReceiver {
Log.d(TAG, "onReceive");
RecordingService.startIfPending(context);
EncodingService.startIfPending(context);
ControlsService.startIfEnabled(context);
}
}

View file

@ -30,5 +30,6 @@ public class OnExternalReceiver extends BroadcastReceiver {
return;
RecordingService.startIfPending(context);
ControlsService.startIfEnabled(context);
}
}

View file

@ -15,5 +15,6 @@ public class OnUpgradeReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive");
RecordingService.startIfPending(context);
ControlsService.startIfEnabled(context);
}
}

View file

@ -48,13 +48,6 @@ public class RecordingService extends PersistentService {
Storage storage; // for storage path
public static void startIfEnabled(Context context) { // notification controls enabled?
SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
if (!shared.getBoolean(AudioApplication.PREFERENCE_CONTROLS, false))
return;
start(context);
}
public static void startIfPending(Context context) { // if recording pending or controls enabled
Storage storage = new Storage(context);
if (storage.recordingPending()) {
@ -75,7 +68,6 @@ public class RecordingService extends PersistentService {
startService(context, d, false, null);
return;
}
startIfEnabled(context);
}
public static void start(Context context) { // start persistent icon service
@ -91,11 +83,6 @@ public class RecordingService extends PersistentService {
}
public static void stopRecording(Context context) {
SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
if (shared.getBoolean(AudioApplication.PREFERENCE_CONTROLS, false)) {
start(context);
return;
}
stop(context);
}
@ -115,7 +102,7 @@ public class RecordingService extends PersistentService {
public void onCreateOptimization() {
storage = new Storage(this);
optimization = new OptimizationPreferenceCompat.ServiceReceiver(this, NOTIFICATION_RECORDING_ICON, null, AudioApplication.PREFERENCE_NEXT) {
Intent notificationIntent;
Intent notificationIntent; // speed up, update notification text without calling notify()
@Override
public void onCreateIcon(Service service, int id) {
@ -144,48 +131,36 @@ public class RecordingService extends PersistentService {
String title;
String text;
if (targetFile == null) { // buildPersistentIcon();
title = getString(R.string.app_name);
Uri f = storage.getStoragePath();
long free = Storage.getFree(context, f);
long sec = Storage.average(context, free);
text = AudioApplication.formatFree(context, free, sec);
builder = new RemoteNotificationCompat.Low(context, R.layout.notifictaion);
builder.setViewVisibility(R.id.notification_record, View.VISIBLE);
builder.setViewVisibility(R.id.notification_pause, View.GONE);
main = PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
} else { // buildRecordingIcon();
if (recording)
title = getString(R.string.recording_title);
else
title = getString(R.string.pause_title);
if (duration != null) {
title += " (" + duration + ")";
if (recording && notificationIntent != null && notificationIntent.hasExtra("duration") && notificationIntent.getBooleanExtra("recording", false)) { // speed up
try {
RemoteViews a = new RemoteViews(getPackageName(), icon.notification.contentView.getLayoutId());
if (recording)
title = getString(R.string.recording_title);
else
title = getString(R.string.pause_title);
if (duration != null) {
title += " (" + duration + ")";
if (recording && notificationIntent != null && notificationIntent.hasExtra("duration") && notificationIntent.getBooleanExtra("recording", false)) {
try {
RemoteViews a = new RemoteViews(getPackageName(), icon.notification.contentView.getLayoutId());
a.setTextViewText(R.id.title, title);
RemoteViewsCompat.mergeRemoteViews(icon.notification.contentView, a);
if (Build.VERSION.SDK_INT >= 16 && icon.notification.bigContentView != null) {
a = new RemoteViews(getPackageName(), icon.notification.bigContentView.getLayoutId());
a.setTextViewText(R.id.title, title);
RemoteViewsCompat.mergeRemoteViews(icon.notification.contentView, a);
if (Build.VERSION.SDK_INT >= 16 && icon.notification.bigContentView != null) {
a = new RemoteViews(getPackageName(), icon.notification.bigContentView.getLayoutId());
a.setTextViewText(R.id.title, title);
RemoteViewsCompat.mergeRemoteViews(icon.notification.bigContentView, a);
}
return icon.notification;
} catch (RuntimeException e) {
Log.d(TAG, "merge failed", e);
RemoteViewsCompat.mergeRemoteViews(icon.notification.bigContentView, a);
}
return icon.notification;
} catch (RuntimeException e) {
Log.d(TAG, "merge failed", e);
}
}
text = ".../" + targetFile;
builder = new RemoteNotificationCompat.Builder(context, R.layout.notifictaion);
builder.setViewVisibility(R.id.notification_record, View.GONE);
builder.setViewVisibility(R.id.notification_pause, View.VISIBLE);
main = PendingIntent.getService(context, 0, new Intent(context, RecordingService.class)
.setAction(SHOW_ACTIVITY)
.putExtra("targetFile", targetFile)
.putExtra("recording", recording), PendingIntent.FLAG_UPDATE_CURRENT);
}
text = ".../" + targetFile;
builder = new RemoteNotificationCompat.Builder(context, R.layout.notifictaion);
builder.setViewVisibility(R.id.notification_record, View.GONE);
builder.setViewVisibility(R.id.notification_pause, View.VISIBLE);
main = PendingIntent.getService(context, 0, new Intent(context, RecordingService.class)
.setAction(SHOW_ACTIVITY)
.putExtra("targetFile", targetFile)
.putExtra("recording", recording), PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pe = PendingIntent.getService(context, 0,
new Intent(context, RecordingService.class).setAction(PAUSE_BUTTON),