summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael W <baddaemon87@gmail.com>2022-12-29 16:27:29 +0100
committerMichael W <baddaemon87@gmail.com>2023-01-21 15:04:12 +0100
commit5f28f280623b24f4732b89132bc884da2dba358f (patch)
tree3c7958cdbac14e53e5316c53288eb153e0f531f5
parentf747fa4fe618194b97c3efae4b821527dc71a0f0 (diff)
DeskClock: Convert AsyncTask(Loader)
* Deprecated and these are easy to convert Change-Id: I839160aa54d28bf23dbb1c2e8e1b70e77927d631
-rw-r--r--src/com/android/deskclock/AlarmSelectionActivity.java30
-rw-r--r--src/com/android/deskclock/HandleApiCalls.java149
-rw-r--r--src/com/android/deskclock/alarms/AlarmUpdateHandler.java177
-rw-r--r--src/com/android/deskclock/data/SilentSettingsModel.java60
-rw-r--r--src/com/android/deskclock/ringtone/RingtoneLoader.java3
-rw-r--r--src/com/android/deskclock/ringtone/RingtonePickerActivity.java231
6 files changed, 302 insertions, 348 deletions
diff --git a/src/com/android/deskclock/AlarmSelectionActivity.java b/src/com/android/deskclock/AlarmSelectionActivity.java
index ab15e69f8..8cee59b8b 100644
--- a/src/com/android/deskclock/AlarmSelectionActivity.java
+++ b/src/com/android/deskclock/AlarmSelectionActivity.java
@@ -15,10 +15,8 @@
*/
package com.android.deskclock;
-import android.app.Activity;
import android.app.ListActivity;
import android.content.Intent;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.view.View;
@@ -28,10 +26,12 @@ import android.widget.ListView;
import com.android.deskclock.provider.Alarm;
import com.android.deskclock.widget.selector.AlarmSelectionAdapter;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
public class AlarmSelectionActivity extends ListActivity {
/** Used by default when an invalid action provided. */
@@ -84,33 +84,21 @@ public class AlarmSelectionActivity extends ListActivity {
// id corresponds to mSelections id because the view adapter used mSelections
final Alarm alarm = mSelections.get((int) id);
if (alarm != null) {
- new ProcessAlarmActionAsync(alarm, this, mAction).execute();
+ processAlarmActionAsync(alarm);
}
finish();
}
- private static class ProcessAlarmActionAsync extends AsyncTask<Void, Void, Void> {
-
- private final Alarm mAlarm;
- private final WeakReference<Activity> mActivity;
- private final int mAction;
-
- public ProcessAlarmActionAsync(Alarm alarm, Activity activity, int action) {
- mAlarm = alarm;
- mActivity = new WeakReference<>(activity);
- mAction = action;
- }
-
- @Override
- protected Void doInBackground(Void... parameters) {
+ void processAlarmActionAsync(Alarm alarm) {
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ executor.execute(() -> {
switch (mAction) {
case ACTION_DISMISS:
- HandleApiCalls.dismissAlarm(mAlarm, mActivity.get());
+ HandleApiCalls.dismissAlarm(alarm, this);
break;
case ACTION_INVALID:
LogUtils.i("Invalid action");
}
- return null;
- }
+ });
}
}
diff --git a/src/com/android/deskclock/HandleApiCalls.java b/src/com/android/deskclock/HandleApiCalls.java
index 28e09a717..5b59d33d4 100644
--- a/src/com/android/deskclock/HandleApiCalls.java
+++ b/src/com/android/deskclock/HandleApiCalls.java
@@ -31,7 +31,6 @@ import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.provider.AlarmClock;
@@ -55,6 +54,8 @@ import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
/**
* This activity is never visible. It processes all public intents defined by {@link AlarmClock}
@@ -165,7 +166,7 @@ public class HandleApiCalls extends Activity {
Events.sendAlarmEvent(R.string.action_dismiss, R.string.label_intent);
}
- private static class DismissAlarmAsync extends AsyncTask<Void, Void, Void> {
+ private static class DismissAlarmAsync {
private final Context mContext;
private final Intent mIntent;
@@ -177,66 +178,69 @@ public class HandleApiCalls extends Activity {
mActivity = activity;
}
- @Override
- protected Void doInBackground(Void... parameters) {
- final ContentResolver cr = mContext.getContentResolver();
- final List<Alarm> alarms = getEnabledAlarms(mContext);
- if (alarms.isEmpty()) {
- final String reason = mContext.getString(R.string.no_scheduled_alarms);
- Controller.getController().notifyVoiceFailure(mActivity, reason);
- LOGGER.i("No scheduled alarms");
- return null;
- }
+ protected void execute() {
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ executor.execute(() -> {
+ final ContentResolver cr = mContext.getContentResolver();
+ final List<Alarm> alarms = getEnabledAlarms(mContext);
+ if (alarms.isEmpty()) {
+ final String reason = mContext.getString(R.string.no_scheduled_alarms);
+ Controller.getController().notifyVoiceFailure(mActivity, reason);
+ LOGGER.i("No scheduled alarms");
+ return;
+ }
- // remove Alarms in MISSED, DISMISSED, and PREDISMISSED states
- for (Iterator<Alarm> i = alarms.iterator(); i.hasNext();) {
- final AlarmInstance instance = AlarmInstance.getNextUpcomingInstanceByAlarmId(
- cr, i.next().id);
- if (instance == null || instance.mAlarmState > FIRED_STATE) {
- i.remove();
+ // remove Alarms in MISSED, DISMISSED, and PREDISMISSED states
+ for (Iterator<Alarm> i = alarms.iterator(); i.hasNext();) {
+ final AlarmInstance instance = AlarmInstance.getNextUpcomingInstanceByAlarmId(
+ cr, i.next().id);
+ if (instance == null || instance.mAlarmState > FIRED_STATE) {
+ i.remove();
+ }
}
- }
- final String searchMode = mIntent.getStringExtra(AlarmClock.EXTRA_ALARM_SEARCH_MODE);
- if (searchMode == null && alarms.size() > 1) {
- // shows the UI where user picks which alarm they want to DISMISS
- final Intent pickSelectionIntent = new Intent(mContext,
- AlarmSelectionActivity.class)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .putExtra(EXTRA_ACTION, ACTION_DISMISS)
- .putExtra(EXTRA_ALARMS, alarms.toArray(new Parcelable[0]));
- mContext.startActivity(pickSelectionIntent);
- final String voiceMessage = mContext.getString(R.string.pick_alarm_to_dismiss);
- Controller.getController().notifyVoiceSuccess(mActivity, voiceMessage);
- return null;
- }
+ final String searchMode = mIntent.getStringExtra(
+ AlarmClock.EXTRA_ALARM_SEARCH_MODE);
+ if (searchMode == null && alarms.size() > 1) {
+ // shows the UI where user picks which alarm they want to DISMISS
+ final Intent pickSelectionIntent = new Intent(mContext,
+ AlarmSelectionActivity.class)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(EXTRA_ACTION, ACTION_DISMISS)
+ .putExtra(EXTRA_ALARMS, alarms.toArray(new Parcelable[0]));
+ mContext.startActivity(pickSelectionIntent);
+ final String voiceMessage = mContext.getString(R.string.pick_alarm_to_dismiss);
+ Controller.getController().notifyVoiceSuccess(mActivity, voiceMessage);
+ return;
+ }
- // fetch the alarms that are specified by the intent
- final FetchMatchingAlarmsAction fmaa =
- new FetchMatchingAlarmsAction(mContext, alarms, mIntent, mActivity);
- fmaa.run();
- final List<Alarm> matchingAlarms = fmaa.getMatchingAlarms();
-
- // If there are multiple matching alarms and it wasn't expected
- // disambiguate what the user meant
- if (!AlarmClock.ALARM_SEARCH_MODE_ALL.equals(searchMode) && matchingAlarms.size() > 1) {
- final Intent pickSelectionIntent = new Intent(mContext, AlarmSelectionActivity.class)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .putExtra(EXTRA_ACTION, ACTION_DISMISS)
- .putExtra(EXTRA_ALARMS,
- matchingAlarms.toArray(new Parcelable[0]));
- mContext.startActivity(pickSelectionIntent);
- final String voiceMessage = mContext.getString(R.string.pick_alarm_to_dismiss);
- Controller.getController().notifyVoiceSuccess(mActivity, voiceMessage);
- return null;
- }
+ // fetch the alarms that are specified by the intent
+ final FetchMatchingAlarmsAction fmaa =
+ new FetchMatchingAlarmsAction(mContext, alarms, mIntent, mActivity);
+ fmaa.run();
+ final List<Alarm> matchingAlarms = fmaa.getMatchingAlarms();
+
+ // If there are multiple matching alarms and it wasn't expected
+ // disambiguate what the user meant
+ if (!AlarmClock.ALARM_SEARCH_MODE_ALL.equals(searchMode) &&
+ matchingAlarms.size() > 1) {
+ final Intent pickSelectionIntent = new Intent(mContext,
+ AlarmSelectionActivity.class)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(EXTRA_ACTION, ACTION_DISMISS)
+ .putExtra(EXTRA_ALARMS, matchingAlarms.toArray(new Parcelable[0]));
+ mContext.startActivity(pickSelectionIntent);
+ final String voiceMessage = mContext.getString(R.string.pick_alarm_to_dismiss);
+ Controller.getController().notifyVoiceSuccess(mActivity, voiceMessage);
+ return;
+ }
- // Apply the action to the matching alarms
- for (Alarm alarm : matchingAlarms) {
- dismissAlarm(alarm, mActivity);
- LOGGER.i("Alarm dismissed: " + alarm);
- }
- return null;
+ // Apply the action to the matching alarms
+ for (Alarm alarm : matchingAlarms) {
+ dismissAlarm(alarm, mActivity);
+ LOGGER.i("Alarm dismissed: " + alarm);
+ }
+ });
}
private static List<Alarm> getEnabledAlarms(Context context) {
@@ -247,36 +251,23 @@ public class HandleApiCalls extends Activity {
}
private void handleSnoozeAlarm() {
- new SnoozeAlarmAsync(this).execute();
- }
-
- private static class SnoozeAlarmAsync extends AsyncTask<Void, Void, Void> {
-
- private final Context mContext;
- private final Activity mActivity;
-
- public SnoozeAlarmAsync(Activity activity) {
- mContext = activity.getApplicationContext();
- mActivity = activity;
- }
-
- @Override
- protected Void doInBackground(Void... parameters) {
- final ContentResolver cr = mContext.getContentResolver();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ executor.execute(() -> {
+ final Context context = getApplicationContext();
+ final ContentResolver cr = context.getContentResolver();
final List<AlarmInstance> alarmInstances = AlarmInstance.getInstancesByState(
cr, FIRED_STATE);
if (alarmInstances.isEmpty()) {
- final String reason = mContext.getString(R.string.no_firing_alarms);
- Controller.getController().notifyVoiceFailure(mActivity, reason);
+ final String reason = context.getString(R.string.no_firing_alarms);
+ Controller.getController().notifyVoiceFailure(this, reason);
LOGGER.i("No firing alarms");
- return null;
+ return;
}
for (AlarmInstance firingAlarmInstance : alarmInstances) {
- snoozeAlarm(firingAlarmInstance, mContext, mActivity);
+ snoozeAlarm(firingAlarmInstance, context, this);
}
- return null;
- }
+ });
}
static void snoozeAlarm(AlarmInstance alarmInstance, Context context, Activity activity) {
diff --git a/src/com/android/deskclock/alarms/AlarmUpdateHandler.java b/src/com/android/deskclock/alarms/AlarmUpdateHandler.java
index f085016a5..1e46f6ee7 100644
--- a/src/com/android/deskclock/alarms/AlarmUpdateHandler.java
+++ b/src/com/android/deskclock/alarms/AlarmUpdateHandler.java
@@ -18,7 +18,8 @@ package com.android.deskclock.alarms;
import android.content.ContentResolver;
import android.content.Context;
-import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Looper;
import android.text.format.DateFormat;
import android.view.View;
import android.view.ViewGroup;
@@ -33,6 +34,8 @@ import com.google.android.material.snackbar.Snackbar;
import java.util.Calendar;
import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
/**
* API for asynchronously mutating a single alarm.
@@ -59,37 +62,34 @@ public final class AlarmUpdateHandler {
* @param alarm The alarm to be added.
*/
public void asyncAddAlarm(final Alarm alarm) {
- final AsyncTask<Void, Void, AlarmInstance> updateTask =
- new AsyncTask<Void, Void, AlarmInstance>() {
- @Override
- protected AlarmInstance doInBackground(Void... parameters) {
- if (alarm != null) {
- Events.sendAlarmEvent(R.string.action_create, R.string.label_deskclock);
- ContentResolver cr = mAppContext.getContentResolver();
-
- // Add alarm to db
- Alarm newAlarm = Alarm.addAlarm(cr, alarm);
-
- // Be ready to scroll to this alarm on UI later.
- mScrollHandler.setSmoothScrollStableId(newAlarm.id);
-
- // Create and add instance to db
- if (newAlarm.enabled) {
- return setupAlarmInstance(newAlarm);
- }
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(AlarmInstance instance) {
- if (instance != null) {
- AlarmUtils.popAlarmSetSnackbar(
- mSnackbarAnchor, instance.getAlarmTime().getTimeInMillis());
- }
- }
- };
- updateTask.execute();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Handler handler = new Handler(Looper.getMainLooper());
+ executor.execute(() -> {
+ AlarmInstance instance = null;
+ if (alarm != null) {
+ Events.sendAlarmEvent(R.string.action_create, R.string.label_deskclock);
+ ContentResolver cr = mAppContext.getContentResolver();
+
+ // Add alarm to db
+ Alarm newAlarm = Alarm.addAlarm(cr, alarm);
+
+ // Be ready to scroll to this alarm on UI later.
+ mScrollHandler.setSmoothScrollStableId(newAlarm.id);
+
+ // Create and add instance to db
+ if (newAlarm.enabled) {
+ instance = setupAlarmInstance(newAlarm);
+ }
+ }
+
+ final AlarmInstance finalInstance = instance;
+ handler.post(() -> {
+ if (finalInstance != null) {
+ AlarmUtils.popAlarmSetSnackbar(
+ mSnackbarAnchor, finalInstance.getAlarmTime().getTimeInMillis());
+ }
+ });
+ });
}
/**
@@ -101,51 +101,47 @@ public final class AlarmUpdateHandler {
*/
public void asyncUpdateAlarm(final Alarm alarm, final boolean popToast,
final boolean minorUpdate) {
- final AsyncTask<Void, Void, AlarmInstance> updateTask =
- new AsyncTask<Void, Void, AlarmInstance>() {
- @Override
- protected AlarmInstance doInBackground(Void... parameters) {
- ContentResolver cr = mAppContext.getContentResolver();
-
- // Update alarm
- Alarm.updateAlarm(cr, alarm);
-
- if (minorUpdate) {
- // just update the instance in the database and update notifications.
- final List<AlarmInstance> instanceList =
- AlarmInstance.getInstancesByAlarmId(cr, alarm.id);
- for (AlarmInstance instance : instanceList) {
- // Make a copy of the existing instance
- final AlarmInstance newInstance = new AlarmInstance(instance);
- // Copy over minor change data to the instance; we don't know
- // exactly which minor field changed, so just copy them all.
- newInstance.mVibrate = alarm.vibrate;
- newInstance.mRingtone = alarm.alert;
- newInstance.mLabel = alarm.label;
- // Since we copied the mId of the old instance and the mId is used
- // as the primary key in the AlarmInstance table, this will replace
- // the existing instance.
- AlarmInstance.updateInstance(cr, newInstance);
- // Update the notification for this instance.
- AlarmNotifications.updateNotification(mAppContext, newInstance);
- }
- return null;
- }
- // Otherwise, this is a major update and we're going to re-create the alarm
- AlarmStateManager.deleteAllInstances(mAppContext, alarm.id);
-
- return alarm.enabled ? setupAlarmInstance(alarm) : null;
- }
-
- @Override
- protected void onPostExecute(AlarmInstance instance) {
- if (popToast && instance != null) {
- AlarmUtils.popAlarmSetSnackbar(
- mSnackbarAnchor, instance.getAlarmTime().getTimeInMillis());
- }
- }
- };
- updateTask.execute();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Handler handler = new Handler(Looper.getMainLooper());
+ executor.execute(() -> {
+ ContentResolver cr = mAppContext.getContentResolver();
+
+ // Update alarm
+ Alarm.updateAlarm(cr, alarm);
+
+ if (minorUpdate) {
+ // just update the instance in the database and update notifications.
+ final List<AlarmInstance> instanceList =
+ AlarmInstance.getInstancesByAlarmId(cr, alarm.id);
+ for (AlarmInstance instance : instanceList) {
+ // Make a copy of the existing instance
+ final AlarmInstance newInstance = new AlarmInstance(instance);
+ // Copy over minor change data to the instance; we don't know
+ // exactly which minor field changed, so just copy them all.
+ newInstance.mVibrate = alarm.vibrate;
+ newInstance.mRingtone = alarm.alert;
+ newInstance.mLabel = alarm.label;
+ // Since we copied the mId of the old instance and the mId is used
+ // as the primary key in the AlarmInstance table, this will replace
+ // the existing instance.
+ AlarmInstance.updateInstance(cr, newInstance);
+ // Update the notification for this instance.
+ AlarmNotifications.updateNotification(mAppContext, newInstance);
+ }
+ return;
+ }
+ // Otherwise, this is a major update and we're going to re-create the alarm
+ AlarmStateManager.deleteAllInstances(mAppContext, alarm.id);
+
+ final AlarmInstance finalInstance = alarm.enabled ? setupAlarmInstance(alarm) : null;
+
+ handler.post(() -> {
+ if (popToast && finalInstance != null) {
+ AlarmUtils.popAlarmSetSnackbar(
+ mSnackbarAnchor, finalInstance.getAlarmTime().getTimeInMillis());
+ }
+ });
+ });
}
/**
@@ -154,27 +150,24 @@ public final class AlarmUpdateHandler {
* @param alarm The alarm to be deleted.
*/
public void asyncDeleteAlarm(final Alarm alarm) {
- final AsyncTask<Void, Void, Boolean> deleteTask = new AsyncTask<Void, Void, Boolean>() {
- @Override
- protected Boolean doInBackground(Void... parameters) {
- // Activity may be closed at this point , make sure data is still valid
- if (alarm == null) {
- // Nothing to do here, just return.
- return false;
- }
- AlarmStateManager.deleteAllInstances(mAppContext, alarm.id);
- return Alarm.deleteAlarm(mAppContext.getContentResolver(), alarm.id);
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Handler handler = new Handler(Looper.getMainLooper());
+ executor.execute(() -> {
+ // Activity may be closed at this point , make sure data is still valid
+ if (alarm == null) {
+ // Nothing to do here, just return.
+ return;
}
+ AlarmStateManager.deleteAllInstances(mAppContext, alarm.id);
+ final boolean deleted = Alarm.deleteAlarm(mAppContext.getContentResolver(), alarm.id);
- @Override
- protected void onPostExecute(Boolean deleted) {
+ handler.post(() -> {
if (deleted) {
mDeletedAlarm = alarm;
showUndoBar();
}
- }
- };
- deleteTask.execute();
+ });
+ });
}
/**
diff --git a/src/com/android/deskclock/data/SilentSettingsModel.java b/src/com/android/deskclock/data/SilentSettingsModel.java
index 79b52f995..10169517d 100644
--- a/src/com/android/deskclock/data/SilentSettingsModel.java
+++ b/src/com/android/deskclock/data/SilentSettingsModel.java
@@ -35,7 +35,6 @@ import android.database.ContentObserver;
import android.media.AudioManager;
import android.media.RingtoneManager;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
@@ -45,6 +44,8 @@ import com.android.deskclock.data.DataModel.SilentSetting;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
/**
* This model fetches and stores reasons that alarms may be suppressed or silenced by system
@@ -112,7 +113,7 @@ final class SilentSettingsModel {
void updateSilentState() {
// Cancel any task in flight, the result is no longer relevant.
if (mCheckSilenceSettingsTask != null) {
- mCheckSilenceSettingsTask.cancel(true);
+ mCheckSilenceSettingsTask.cancel();
mCheckSilenceSettingsTask = null;
}
@@ -143,35 +144,36 @@ final class SilentSettingsModel {
* associated ringtone from playing. If any of them would prevent an alarm from firing or
* making noise, a description of the setting is reported to this model on the main thread.
*/
- private final class CheckSilenceSettingsTask extends AsyncTask<Void, Void, SilentSetting> {
- @Override
- protected SilentSetting doInBackground(Void... parameters) {
- if (!isCancelled() && isDoNotDisturbBlockingAlarms()) {
- return SilentSetting.DO_NOT_DISTURB;
- } else if (!isCancelled() && isAlarmStreamMuted()) {
- return SilentSetting.MUTED_VOLUME;
- } else if (!isCancelled() && isSystemAlarmRingtoneSilent()) {
- return SilentSetting.SILENT_RINGTONE;
- } else if (!isCancelled() && isAppNotificationBlocked()) {
- return SilentSetting.BLOCKED_NOTIFICATIONS;
- }
- return null;
- }
-
- @Override
- protected void onCancelled() {
- super.onCancelled();
- if (mCheckSilenceSettingsTask == this) {
- mCheckSilenceSettingsTask = null;
- }
+ private final class CheckSilenceSettingsTask {
+ ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+ Handler mHandler = new Handler(Looper.getMainLooper());
+
+ private void execute() {
+ mExecutor.execute(() -> {
+ final SilentSetting silentSetting;
+ if (isDoNotDisturbBlockingAlarms()) {
+ silentSetting = SilentSetting.DO_NOT_DISTURB;
+ } else if (isAlarmStreamMuted()) {
+ silentSetting = SilentSetting.MUTED_VOLUME;
+ } else if (isSystemAlarmRingtoneSilent()) {
+ silentSetting = SilentSetting.SILENT_RINGTONE;
+ } else if (isAppNotificationBlocked()) {
+ silentSetting = SilentSetting.BLOCKED_NOTIFICATIONS;
+ } else {
+ silentSetting = null;
+ }
+
+ mHandler.post(() -> {
+ if (mCheckSilenceSettingsTask == this) {
+ mCheckSilenceSettingsTask = null;
+ setSilentState(silentSetting);
+ }
+ });
+ });
}
- @Override
- protected void onPostExecute(SilentSetting silentSetting) {
- if (mCheckSilenceSettingsTask == this) {
- mCheckSilenceSettingsTask = null;
- setSilentState(silentSetting);
- }
+ private void cancel() {
+ mExecutor.shutdownNow();
}
private boolean isDoNotDisturbBlockingAlarms() {
diff --git a/src/com/android/deskclock/ringtone/RingtoneLoader.java b/src/com/android/deskclock/ringtone/RingtoneLoader.java
index 3f5d6d200..515eb915c 100644
--- a/src/com/android/deskclock/ringtone/RingtoneLoader.java
+++ b/src/com/android/deskclock/ringtone/RingtoneLoader.java
@@ -19,13 +19,14 @@ package com.android.deskclock.ringtone;
import static android.media.AudioManager.STREAM_ALARM;
import static com.android.deskclock.Utils.RINGTONE_SILENT;
-import android.content.AsyncTaskLoader;
import android.content.Context;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.media.RingtoneManager;
import android.net.Uri;
+import androidx.loader.content.AsyncTaskLoader;
+
import com.android.deskclock.ItemAdapter;
import com.android.deskclock.LogUtils;
import com.android.deskclock.R;
diff --git a/src/com/android/deskclock/ringtone/RingtonePickerActivity.java b/src/com/android/deskclock/ringtone/RingtonePickerActivity.java
index ba18c85e0..8d2d9de83 100644
--- a/src/com/android/deskclock/ringtone/RingtonePickerActivity.java
+++ b/src/com/android/deskclock/ringtone/RingtonePickerActivity.java
@@ -28,18 +28,17 @@ import static com.android.deskclock.ringtone.RingtoneViewHolder.VIEW_TYPE_SYSTEM
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
-import android.app.LoaderManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.Loader;
import android.database.Cursor;
import android.media.AudioManager;
import android.media.RingtoneManager;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.provider.MediaStore;
import android.view.LayoutInflater;
import android.view.MenuItem;
@@ -47,6 +46,8 @@ import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
+import androidx.loader.content.Loader;
+import androidx.loader.app.LoaderManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -61,6 +62,8 @@ import com.android.deskclock.provider.Alarm;
import com.android.deskclock.widget.CollapsingToolbarBaseActivity;
import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
/**
* This activity presents a set of ringtones from which the user may select one. The set includes:
@@ -190,7 +193,8 @@ public class RingtonePickerActivity extends CollapsingToolbarBaseActivity
final int titleResourceId = intent.getIntExtra(EXTRA_TITLE, 0);
setTitle(context.getString(titleResourceId));
- getLoaderManager().initLoader(0 /* id */, null /* args */, this /* callback */);
+ LoaderManager.getInstance(this).initLoader(0 /* id */, null /* args */,
+ this /* callback */);
registerForContextMenu(recyclerView);
}
@@ -203,26 +207,22 @@ public class RingtonePickerActivity extends CollapsingToolbarBaseActivity
final ContentResolver cr = getContentResolver();
// Start a background task to fetch the alarm whose ringtone must be updated.
- new AsyncTask<Void, Void, Alarm>() {
- @Override
- protected Alarm doInBackground(Void... parameters) {
- final Alarm alarm = Alarm.getAlarm(cr, mAlarmId);
- if (alarm != null) {
- alarm.alert = mSelectedRingtoneUri;
- }
- return alarm;
- }
-
- @Override
- protected void onPostExecute(Alarm alarm) {
- // Update the default ringtone for future new alarms.
- DataModel.getDataModel().setDefaultAlarmRingtoneUri(alarm.alert);
-
- // Start a second background task to persist the updated alarm.
- new AlarmUpdateHandler(context, null, null)
- .asyncUpdateAlarm(alarm, false, true);
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Handler handler = new Handler(Looper.getMainLooper());
+ executor.execute(() -> {
+ final Alarm alarm = Alarm.getAlarm(cr, mAlarmId);
+ if (alarm != null) {
+ alarm.alert = mSelectedRingtoneUri;
+
+ handler.post(() -> {
+ DataModel.getDataModel().setDefaultAlarmRingtoneUri(alarm.alert);
+
+ // Start a second background task to persist the updated alarm.
+ new AlarmUpdateHandler(context, null, null)
+ .asyncUpdateAlarm(alarm, false, true);
+ });
}
- }.execute();
+ });
} else {
DataModel.getDataModel().setTimerRingtoneUri(mSelectedRingtoneUri);
}
@@ -255,8 +255,8 @@ public class RingtonePickerActivity extends CollapsingToolbarBaseActivity
}
@Override
- public void onLoadFinished(Loader<List<ItemAdapter.ItemHolder<Uri>>> loader,
- List<ItemAdapter.ItemHolder<Uri>> itemHolders) {
+ public void onLoadFinished(@NonNull Loader<List<ItemAdapter.ItemHolder<Uri>>> loader,
+ List<ItemAdapter.ItemHolder<Uri>> itemHolders) {
// Update the adapter with fresh data.
mRingtoneAdapter.setItems(itemHolders);
@@ -301,7 +301,7 @@ public class RingtonePickerActivity extends CollapsingToolbarBaseActivity
}
// Start a task to fetch the display name of the audio content and add the custom ringtone.
- new AddCustomRingtoneTask(uri).execute();
+ addCustomRingtoneAsync(uri);
}
@Override
@@ -377,15 +377,6 @@ public class RingtonePickerActivity extends CollapsingToolbarBaseActivity
}
/**
- * Proceeds with removing the custom ringtone with the given uri.
- *
- * @param toRemove identifies the custom ringtone to be removed
- */
- private void removeCustomRingtone(Uri toRemove) {
- new RemoveCustomRingtoneTask(toRemove).execute();
- }
-
- /**
* This DialogFragment informs the user of the side-effects of removing a custom ringtone while
* it is in use by alarms and/or timers and prompts them to confirm the removal.
*/
@@ -415,7 +406,7 @@ public class RingtonePickerActivity extends CollapsingToolbarBaseActivity
final Uri toRemove = arguments.getParcelable(ARG_RINGTONE_URI_TO_REMOVE);
final DialogInterface.OnClickListener okListener = (dialog, which) ->
- ((RingtonePickerActivity) getActivity()).removeCustomRingtone(toRemove);
+ ((RingtonePickerActivity) getActivity()).removeCustomRingtoneAsync(toRemove);
if (arguments.getBoolean(ARG_RINGTONE_HAS_PERMISSIONS)) {
return new AlertDialog.Builder(getActivity())
@@ -482,64 +473,61 @@ public class RingtonePickerActivity extends CollapsingToolbarBaseActivity
* This task locates a displayable string in the background that is fit for use as the title of
* the audio content. It adds a custom ringtone using the uri and title on the main thread.
*/
- private final class AddCustomRingtoneTask extends AsyncTask<Void, Void, String> {
+ private void addCustomRingtoneAsync(Uri uri) {
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Handler handler = new Handler(Looper.getMainLooper());
- private final Uri mUri;
- private final Context mContext;
-
- private AddCustomRingtoneTask(Uri uri) {
- mUri = uri;
- mContext = getApplicationContext();
- }
-
- @Override
- protected String doInBackground(Void... voids) {
- final ContentResolver contentResolver = mContext.getContentResolver();
+ executor.execute(() -> {
+ final Context context = getApplicationContext();
+ final ContentResolver contentResolver = context.getContentResolver();
+ String name = null;
// Take the long-term permission to read (playback) the audio at the uri.
- contentResolver.takePersistableUriPermission(mUri, FLAG_GRANT_READ_URI_PERMISSION);
+ contentResolver.takePersistableUriPermission(uri, FLAG_GRANT_READ_URI_PERMISSION);
- try (Cursor cursor = contentResolver.query(mUri, null, null, null, null)) {
+ try (Cursor cursor = contentResolver.query(uri, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
// If the file was a media file, return its title.
final int titleIndex = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
if (titleIndex != -1) {
- return cursor.getString(titleIndex);
- }
-
- // If the file was a simple openable, return its display name.
- final int displayNameIndex = cursor.getColumnIndex(DISPLAY_NAME);
- if (displayNameIndex != -1) {
- String title = cursor.getString(displayNameIndex);
- final int dotIndex = title.lastIndexOf(".");
- if (dotIndex > 0) {
- title = title.substring(0, dotIndex);
+ name = cursor.getString(titleIndex);
+ } else {
+ // If the file was a simple openable, return its display name.
+ final int displayNameIndex = cursor.getColumnIndex(DISPLAY_NAME);
+ if (displayNameIndex != -1) {
+ String displayName = cursor.getString(displayNameIndex);
+ final int dotIndex = displayName.lastIndexOf(".");
+ if (dotIndex > 0) {
+ displayName = displayName.substring(0, dotIndex);
+ }
+ name = displayName;
}
- return title;
}
} else {
- LogUtils.e("No ringtone for uri: %s", mUri);
+ LogUtils.e("No ringtone for uri: %s", uri);
}
} catch (Exception e) {
- LogUtils.e("Unable to locate title for custom ringtone: " + mUri, e);
+ LogUtils.e("Unable to locate title for custom ringtone: " + uri, e);
}
- return mContext.getString(R.string.unknown_ringtone_title);
- }
+ if (name == null) {
+ name = context.getString(R.string.unknown_ringtone_title);
+ }
- @Override
- protected void onPostExecute(String title) {
- // Add the new custom ringtone to the data model.
- DataModel.getDataModel().addCustomRingtone(mUri, title);
+ final String title = name;
+ handler.post(() -> {
+ // Add the new custom ringtone to the data model.
+ DataModel.getDataModel().addCustomRingtone(uri, title);
- // When the loader completes, it must play the new ringtone.
- mSelectedRingtoneUri = mUri;
- mIsPlaying = true;
+ // When the loader completes, it must play the new ringtone.
+ mSelectedRingtoneUri = uri;
+ mIsPlaying = true;
- // Reload the data to reflect the change in the UI.
- getLoaderManager().restartLoader(0 /* id */, null /* args */,
- RingtonePickerActivity.this /* callback */);
- }
+ // Reload the data to reflect the change in the UI.
+ LoaderManager.getInstance(this).restartLoader(0 /* id */, null /* args */,
+ RingtonePickerActivity.this /* callback */);
+ });
+ });
}
/**
@@ -549,25 +537,18 @@ public class RingtonePickerActivity extends CollapsingToolbarBaseActivity
* Android system default alarm ringtone. If the application's timer ringtone is being removed,
* it is reset to the application's default timer ringtone.
*/
- private final class RemoveCustomRingtoneTask extends AsyncTask<Void, Void, Void> {
-
- private final Uri mRemoveUri;
- private Uri mSystemDefaultRingtoneUri;
-
- private RemoveCustomRingtoneTask(Uri removeUri) {
- mRemoveUri = removeUri;
- }
-
- @Override
- protected Void doInBackground(Void... voids) {
- mSystemDefaultRingtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
-
+ private void removeCustomRingtoneAsync(Uri removeUri) {
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Handler handler = new Handler(Looper.getMainLooper());
+ executor.execute(() -> {
+ final Uri systemDefaultRingtoneUri =
+ RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
// Update all alarms that use the custom ringtone to use the system default.
final ContentResolver cr = getContentResolver();
final List<Alarm> alarms = Alarm.getAlarms(cr, null);
for (Alarm alarm : alarms) {
- if (mRemoveUri.equals(alarm.alert)) {
- alarm.alert = mSystemDefaultRingtoneUri;
+ if (removeUri.equals(alarm.alert)) {
+ alarm.alert = systemDefaultRingtoneUri;
// Start a second background task to persist the updated alarm.
new AlarmUpdateHandler(RingtonePickerActivity.this, null, null)
.asyncUpdateAlarm(alarm, false, true);
@@ -576,51 +557,49 @@ public class RingtonePickerActivity extends CollapsingToolbarBaseActivity
try {
// Release the permission to read (playback) the audio at the uri.
- cr.releasePersistableUriPermission(mRemoveUri, FLAG_GRANT_READ_URI_PERMISSION);
+ cr.releasePersistableUriPermission(removeUri, FLAG_GRANT_READ_URI_PERMISSION);
} catch (SecurityException ignore) {
// If the file was already deleted from the file system, a SecurityException is
// thrown indicating this app did not hold the read permission being released.
- LogUtils.w("SecurityException while releasing read permission for " + mRemoveUri);
+ LogUtils.w("SecurityException while releasing read permission for " + removeUri);
}
- return null;
- }
-
- @Override
- protected void onPostExecute(Void v) {
- // Reset the default alarm ringtone if it was just removed.
- if (mRemoveUri.equals(DataModel.getDataModel().getDefaultAlarmRingtoneUri())) {
- DataModel.getDataModel().setDefaultAlarmRingtoneUri(mSystemDefaultRingtoneUri);
- }
+ handler.post(() -> {
+ // Reset the default alarm ringtone if it was just removed.
+ if (removeUri.equals(DataModel.getDataModel().getDefaultAlarmRingtoneUri())) {
+ DataModel.getDataModel().setDefaultAlarmRingtoneUri(systemDefaultRingtoneUri);
+ }
- // Reset the timer ringtone if it was just removed.
- if (mRemoveUri.equals(DataModel.getDataModel().getTimerRingtoneUri())) {
- final Uri timerRingtoneUri = DataModel.getDataModel().getDefaultTimerRingtoneUri();
- DataModel.getDataModel().setTimerRingtoneUri(timerRingtoneUri);
- }
+ // Reset the timer ringtone if it was just removed.
+ if (removeUri.equals(DataModel.getDataModel().getTimerRingtoneUri())) {
+ final Uri timerRingtoneUri = DataModel.getDataModel()
+ .getDefaultTimerRingtoneUri();
+ DataModel.getDataModel().setTimerRingtoneUri(timerRingtoneUri);
+ }
- // Remove the corresponding custom ringtone.
- DataModel.getDataModel().removeCustomRingtone(mRemoveUri);
+ // Remove the corresponding custom ringtone.
+ DataModel.getDataModel().removeCustomRingtone(removeUri);
- // Find the ringtone to be removed from the adapter.
- final RingtoneHolder toRemove = getRingtoneHolder(mRemoveUri);
- if (toRemove == null) {
- return;
- }
+ // Find the ringtone to be removed from the adapter.
+ final RingtoneHolder toRemove = getRingtoneHolder(removeUri);
+ if (toRemove == null) {
+ return;
+ }
- // If the ringtone to remove is also the selected ringtone, adjust the selection.
- if (toRemove.isSelected()) {
- stopPlayingRingtone(toRemove, false);
- final RingtoneHolder defaultRingtone = getRingtoneHolder(mDefaultRingtoneUri);
- if (defaultRingtone != null) {
- defaultRingtone.setSelected(true);
- mSelectedRingtoneUri = defaultRingtone.getUri();
- defaultRingtone.notifyItemChanged();
+ // If the ringtone to remove is also the selected ringtone, adjust the selection.
+ if (toRemove.isSelected()) {
+ stopPlayingRingtone(toRemove, false);
+ final RingtoneHolder defaultRingtone = getRingtoneHolder(mDefaultRingtoneUri);
+ if (defaultRingtone != null) {
+ defaultRingtone.setSelected(true);
+ mSelectedRingtoneUri = defaultRingtone.getUri();
+ defaultRingtone.notifyItemChanged();
+ }
}
- }
- // Remove the ringtone from the adapter.
- mRingtoneAdapter.removeItem(toRemove);
- }
+ // Remove the ringtone from the adapter.
+ mRingtoneAdapter.removeItem(toRemove);
+ });
+ });
}
}