Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bec77202 authored by Sean Stout's avatar Sean Stout
Browse files

Support delete alarm

Bug: 30076796
Change-Id: I977ddd642216bb1d5082130c88e751f149d2d414
parent eea5acbb
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -921,6 +921,12 @@
    -->
    <string name="alarm_is_dismissed"><xliff:g id="alarm_time" example="14:20">%s</xliff:g> alarm dismissed</string>

    <!-- String that represents that the user has deleted an alarm through a voice action.
    %s represents alarm time, e.g. 14:20
    [CHAR LIMIT=NONE]
    -->
    <string name="alarm_is_deleted"><xliff:g id="alarm_time" example="14:20">%s</xliff:g> alarm deleted</string>

    <!-- String that represents that the user has dismissed an alarm through a voice action.
    %s represents alarm time, e.g. 14:20
    [CHAR LIMIT=NONE]
@@ -1026,6 +1032,13 @@
   -->
    <string name="pick_alarm_to_dismiss">Pick which alarm to dismiss</string>

    <!-- String that represents that further action is needed from the user in case their
    voice command was ambiguous or there are more than 1 alarms that match their request.
    The user needs to choose an alarm they want to delete through the UI
   [CHAR LIMIT=NONE]
   -->
    <string name="pick_alarm_to_delete">Pick which alarm to delete</string>

    <!-- String that represents that the user doesn't have any alarms firing at the moment.
    [CHAR LIMIT=NONE]
    -->
+27 −3
Original line number Diff line number Diff line
@@ -34,10 +34,22 @@ import java.util.List;

public class AlarmSelectionActivity extends ListActivity {

    /** Used by default when neither ACTION_DISMISS nor ACTION_DELETE are provided */
    private static final int ACTION_INVALID = -1;

    /** Action used to signify alarm should be dismissed on selection */
    public static final int ACTION_DISMISS = 0;

    /** Action used to signify alarm should be deleted on selection */
    public static final int ACTION_DELETE = 1;

    public static final String EXTRA_ACTION = "com.android.deskclock.EXTRA_ACTION";
    public static final String EXTRA_ALARMS = "com.android.deskclock.EXTRA_ALARMS";

    private final List<AlarmSelection> mSelections = new ArrayList<>();

    private int mAction;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // this activity is shown if:
@@ -61,6 +73,7 @@ public class AlarmSelectionActivity extends ListActivity {

        final Intent intent = getIntent();
        final Parcelable[] alarmsFromIntent = intent.getParcelableArrayExtra(EXTRA_ALARMS);
        mAction = intent.getIntExtra(EXTRA_ACTION, ACTION_INVALID);

        // reading alarms from intent
        // PickSelection is started only if there are more than 1 relevant alarm
@@ -83,7 +96,7 @@ public class AlarmSelectionActivity extends ListActivity {
        final AlarmSelection selection = mSelections.get((int) id);
        final Alarm alarm = selection.getAlarm();
        if (alarm != null) {
            new ProcessAlarmActionAsync(alarm, this).execute();
            new ProcessAlarmActionAsync(alarm, this, mAction).execute();
        }
        finish();
    }
@@ -92,15 +105,26 @@ public class AlarmSelectionActivity extends ListActivity {

        private final Alarm mAlarm;
        private final Activity mActivity;
        private final int mAction;

        public ProcessAlarmActionAsync(Alarm alarm, Activity activity) {
        public ProcessAlarmActionAsync(Alarm alarm, Activity activity, int action) {
            mAlarm = alarm;
            mActivity = activity;
            mAction = action;
        }

        @Override
        protected Void doInBackground(Void... parameters) {
            switch (mAction) {
                case ACTION_DISMISS:
                    HandleApiCalls.dismissAlarm(mAlarm, mActivity);
                    break;
                case ACTION_DELETE:
                    HandleApiCalls.deleteAlarm(mAlarm, mActivity);
                    break;
                case ACTION_INVALID:
                    LogUtils.i("Invalid action");
            }
            return null;
        }
    }
+148 −3
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.os.Bundle;
import android.os.Parcelable;
import android.provider.AlarmClock;
import android.support.annotation.StringRes;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.text.format.DateFormat;

@@ -47,6 +48,10 @@ import java.util.Iterator;
import java.util.List;

import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static com.android.deskclock.AlarmSelectionActivity.ACTION_DELETE;
import static com.android.deskclock.AlarmSelectionActivity.ACTION_DISMISS;
import static com.android.deskclock.AlarmSelectionActivity.EXTRA_ACTION;
import static com.android.deskclock.AlarmSelectionActivity.EXTRA_ALARMS;
import static com.android.deskclock.provider.AlarmInstance.DISMISSED_STATE;
import static com.android.deskclock.provider.AlarmInstance.FIRED_STATE;
import static com.android.deskclock.provider.AlarmInstance.HIDE_NOTIFICATION_STATE;
@@ -66,6 +71,9 @@ import static com.android.deskclock.uidata.UiDataModel.Tab.TIMERS;
 */
public class HandleApiCalls extends Activity {

    @VisibleForTesting
    static final String ACTION_DELETE_ALARM = "android.intent.action.DELETE_ALARM";

    private Context mAppContext;

    @Override
@@ -93,12 +101,16 @@ public class HandleApiCalls extends Activity {
                    break;
                case AlarmClock.ACTION_SNOOZE_ALARM:
                    handleSnoozeAlarm(intent);
                    break;
                case ACTION_DELETE_ALARM:
                    handleDeleteAlarm(intent);
            }
        } finally {
            finish();
        }
    }


    private void handleDismissAlarm(Intent intent) {
        // Change to the alarms tab.
        UiDataModel.getUiDataModel().setSelectedTab(ALARMS);
@@ -151,6 +163,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 final Context mContext;
@@ -219,8 +232,8 @@ public class HandleApiCalls extends Activity {
                final Intent pickSelectionIntent = new Intent(mContext,
                        AlarmSelectionActivity.class)
                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        .putExtra(AlarmSelectionActivity.EXTRA_ALARMS,
                                alarms.toArray(new Parcelable[alarms.size()]));
                        .putExtra(EXTRA_ACTION, ACTION_DISMISS)
                        .putExtra(EXTRA_ALARMS, alarms.toArray(new Parcelable[alarms.size()]));
                mContext.startActivity(pickSelectionIntent);
                Voice.notifySuccess(mActivity, mContext.getString(R.string.pick_alarm_to_dismiss));
                return null;
@@ -237,7 +250,8 @@ public class HandleApiCalls extends Activity {
            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(AlarmSelectionActivity.EXTRA_ALARMS,
                        .putExtra(EXTRA_ACTION, ACTION_DISMISS)
                        .putExtra(EXTRA_ALARMS,
                                matchingAlarms.toArray(new Parcelable[matchingAlarms.size()]));
                mContext.startActivity(pickSelectionIntent);
                Voice.notifySuccess(mActivity, mContext.getString(R.string.pick_alarm_to_dismiss));
@@ -351,6 +365,137 @@ public class HandleApiCalls extends Activity {
        Events.sendAlarmEvent(R.string.action_snooze, R.string.label_intent);
    }

    private void handleDeleteAlarm(Intent intent) {
        new DeleteAlarmAsync(mAppContext, intent, this).execute();
    }

    public static void deleteAlarm(Alarm alarm, Activity activity) {
        Utils.enforceNotMainLooper();
        final Context context = activity.getApplicationContext();
        final AlarmInstance instance = AlarmInstance.getNextUpcomingInstanceByAlarmId(
                context.getContentResolver(), alarm.id);
        if (instance == null) {
            final String reason = context.getString(R.string.no_alarm_scheduled_for_this_time);
            Voice.notifyFailure(activity, reason);
            LogUtils.i(reason);
            return;
        }

        deleteAlarmInstance(instance, activity);
    }

    public static void deleteAlarmInstance(AlarmInstance instance, Activity activity) {
        Utils.enforceNotMainLooper();

        final Context context = activity.getApplicationContext();
        final Date alarmTime = instance.getAlarmTime().getTime();
        final String time = DateFormat.getTimeFormat(context).format(alarmTime);

        final String reason = context.getString(R.string.alarm_is_deleted, time);
        LogUtils.i(reason);
        Voice.notifySuccess(activity, reason);
        AlarmStateManager.deleteInstanceAndUpdateParent(context, instance);
        Events.sendAlarmEvent(R.string.action_delete, R.string.label_intent);
    }

    private static class DeleteAlarmAsync extends AsyncTask<Void, Void, Void> {

        private final Context mContext;
        private final Intent mIntent;
        private final Activity mActivity;

        public DeleteAlarmAsync(Context context, Intent intent, Activity activity) {
            mContext = context;
            mIntent = intent;
            mActivity = activity;
        }

        @Override
        protected Void doInBackground(Void... params) {
            final ContentResolver cr = mContext.getContentResolver();

            final Uri deepLink = mIntent.getData();
            if (deepLink != null) {
                final AlarmInstance instance = AlarmInstance.getInstance(cr, deepLink);
                if (instance == null) {
                    final String reason = mContext.getString(R.string.cannot_locate_alarm);
                    LogUtils.i(reason);
                    Voice.notifyFailure(mActivity, reason);
                    return null;
                }

                deleteAlarmInstance(instance, mActivity);
                return null;
            }

            final List<Alarm> alarms = getAllAlarms(mContext);
            if (alarms.isEmpty()) {
                final String reason = mContext.getString(R.string.no_alarms);
                LogUtils.i(reason);
                Voice.notifyFailure(mActivity, reason);
                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 ACTION_DELETE
                final Intent pickSelectionIntent = new Intent(mContext,
                        AlarmSelectionActivity.class)
                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        .putExtra(EXTRA_ACTION, ACTION_DELETE)
                        .putExtra(EXTRA_ALARMS, alarms.toArray(new Parcelable[alarms.size()]));
                mContext.startActivity(pickSelectionIntent);
                Voice.notifySuccess(mActivity, mContext.getString(R.string.pick_alarm_to_delete));
                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_DELETE)
                                .putExtra(EXTRA_ALARMS,
                                        matchingAlarms.toArray(new Parcelable[matchingAlarms.size()]));
                mContext.startActivity(pickSelectionIntent);
                Voice.notifySuccess(mActivity, mContext.getString(R.string.pick_alarm_to_delete));
                return null;
            }

            // Apply the action to the matching alarms
            boolean matches = false;
            for (Alarm alarm : matchingAlarms) {
                final AlarmInstance instance =
                        AlarmInstance.getNextUpcomingInstanceByAlarmId(cr, alarm.id);
                if (AlarmClock.ALARM_SEARCH_MODE_ALL.equals(searchMode) && instance == null) {
                    continue;
                }
                matches = true;
                deleteAlarmInstance(instance, mActivity);
                LogUtils.i("Alarm %s is deleted", alarm);
            }

            if (!matches) {
                final String reason = mContext.getString(R.string.no_alarm_scheduled_for_this_time);
                Voice.notifyFailure(mActivity, reason);
                LogUtils.i(reason);
            }

            return null;
        }

        private static List<Alarm> getAllAlarms(Context context) {
            return Alarm.getAlarms(context.getContentResolver(), null, null);
        }
    }

    /***
     * Processes the SET_ALARM intent
     * @param intent Intent passed to the app