diff options
7 files changed, 187 insertions, 120 deletions
diff --git a/src/com/android/deskclock/FetchMatchingAlarmsAction.java b/src/com/android/deskclock/FetchMatchingAlarmsAction.java index 9b797b479..667b64da4 100644 --- a/src/com/android/deskclock/FetchMatchingAlarmsAction.java +++ b/src/com/android/deskclock/FetchMatchingAlarmsAction.java @@ -24,6 +24,7 @@ import android.os.Looper; import android.provider.AlarmClock; import com.android.deskclock.alarms.AlarmStateManager; +import com.android.deskclock.controller.Controller; import com.android.deskclock.provider.Alarm; import com.android.deskclock.provider.AlarmInstance; @@ -175,6 +176,6 @@ class FetchMatchingAlarmsAction implements Runnable { private void notifyFailureAndLog(String reason, Activity activity) { LogUtils.e(reason); - Voice.notifyFailure(activity, reason); + Controller.getController().notifyVoiceFailure(activity, reason); } } diff --git a/src/com/android/deskclock/HandleApiCalls.java b/src/com/android/deskclock/HandleApiCalls.java index b4bef3a6c..8bf0aef39 100644 --- a/src/com/android/deskclock/HandleApiCalls.java +++ b/src/com/android/deskclock/HandleApiCalls.java @@ -32,6 +32,7 @@ import android.text.TextUtils; import android.text.format.DateFormat; import com.android.deskclock.alarms.AlarmStateManager; +import com.android.deskclock.controller.Controller; import com.android.deskclock.data.DataModel; import com.android.deskclock.data.Timer; import com.android.deskclock.data.Weekdays; @@ -127,7 +128,7 @@ public class HandleApiCalls extends Activity { context.getContentResolver(), alarm.id); if (instance == null) { final String reason = context.getString(R.string.no_alarm_scheduled_for_this_time); - Voice.notifyFailure(activity, reason); + Controller.getController().notifyVoiceFailure(activity, reason); LogUtils.i(reason); return; } @@ -152,18 +153,17 @@ public class HandleApiCalls extends Activity { // Otherwise the alarm cannot be dismissed at this time. final String reason = context.getString( R.string.alarm_cant_be_dismissed_still_more_than_24_hours_away, time); - Voice.notifyFailure(activity, reason); + Controller.getController().notifyVoiceFailure(activity, reason); LogUtils.i(reason); } // Log the successful dismissal. final String reason = context.getString(R.string.alarm_is_dismissed, time); LogUtils.i(reason); - Voice.notifySuccess(activity, reason); + Controller.getController().notifyVoiceSuccess(activity, reason); Events.sendAlarmEvent(R.string.action_dismiss, R.string.label_intent); } - private static class DismissAlarmAsync extends AsyncTask<Void, Void, Void> { private final Context mContext; @@ -186,7 +186,7 @@ public class HandleApiCalls extends Activity { if (instance == null) { final String reason = mContext.getString(R.string.cannot_locate_alarm); LogUtils.i(reason); - Voice.notifyFailure(mActivity, reason); + Controller.getController().notifyVoiceFailure(mActivity, reason); return null; } @@ -194,14 +194,14 @@ public class HandleApiCalls extends Activity { if (state == MISSED_STATE) { final String reason = mContext.getString(R.string.alarm_is_already_missed); LogUtils.i(reason); - Voice.notifyFailure(mActivity, reason); + Controller.getController().notifyVoiceFailure(mActivity, reason); return null; } if (state == PREDISMISSED_STATE || state == DISMISSED_STATE) { final String reason = mContext.getString(R.string.alarm_is_already_dismissed); LogUtils.i(reason); - Voice.notifyFailure(mActivity, reason); + Controller.getController().notifyVoiceFailure(mActivity, reason); return null; } @@ -213,7 +213,7 @@ public class HandleApiCalls extends Activity { if (alarms.isEmpty()) { final String reason = mContext.getString(R.string.no_scheduled_alarms); LogUtils.i(reason); - Voice.notifyFailure(mActivity, reason); + Controller.getController().notifyVoiceFailure(mActivity, reason); return null; } @@ -235,7 +235,8 @@ public class HandleApiCalls extends Activity { .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)); + final String voiceMessage = mContext.getString(R.string.pick_alarm_to_dismiss); + Controller.getController().notifyVoiceSuccess(mActivity, voiceMessage); return null; } @@ -254,7 +255,8 @@ public class HandleApiCalls extends Activity { .putExtra(EXTRA_ALARMS, matchingAlarms.toArray(new Parcelable[matchingAlarms.size()])); mContext.startActivity(pickSelectionIntent); - Voice.notifySuccess(mActivity, mContext.getString(R.string.pick_alarm_to_dismiss)); + final String voiceMessage = mContext.getString(R.string.pick_alarm_to_dismiss); + Controller.getController().notifyVoiceSuccess(mActivity, voiceMessage); return null; } @@ -299,7 +301,7 @@ public class HandleApiCalls extends Activity { if (instance == null) { final String reason = mContext.getString(R.string.cannot_locate_alarm); LogUtils.i(reason); - Voice.notifyFailure(mActivity, reason); + Controller.getController().notifyVoiceFailure(mActivity, reason); return null; } @@ -332,7 +334,7 @@ public class HandleApiCalls extends Activity { final String reason = mContext.getString(failureMessageId); LogUtils.i(reason); - Voice.notifyFailure(mActivity, reason); + Controller.getController().notifyVoiceFailure(mActivity, reason); return null; } @@ -341,7 +343,7 @@ public class HandleApiCalls extends Activity { if (alarmInstances.isEmpty()) { final String reason = mContext.getString(R.string.no_firing_alarms); LogUtils.i(reason); - Voice.notifyFailure(mActivity, reason); + Controller.getController().notifyVoiceFailure(mActivity, reason); return null; } @@ -359,7 +361,7 @@ public class HandleApiCalls extends Activity { alarmInstance.getAlarmTime().getTime()); final String reason = context.getString(R.string.alarm_is_snoozed, time); LogUtils.i(reason); - Voice.notifySuccess(activity, reason); + Controller.getController().notifyVoiceSuccess(activity, reason); AlarmStateManager.setSnoozeState(context, alarmInstance, true); LogUtils.i("Snooze %d:%d", alarmInstance.mHour, alarmInstance.mMinute); Events.sendAlarmEvent(R.string.action_snooze, R.string.label_intent); @@ -376,7 +378,7 @@ public class HandleApiCalls extends Activity { context.getContentResolver(), alarm.id); if (instance == null) { final String reason = context.getString(R.string.no_alarm_scheduled_for_this_time); - Voice.notifyFailure(activity, reason); + Controller.getController().notifyVoiceFailure(activity, reason); LogUtils.i(reason); return; } @@ -393,7 +395,7 @@ public class HandleApiCalls extends Activity { final String reason = context.getString(R.string.alarm_is_deleted, time); LogUtils.i(reason); - Voice.notifySuccess(activity, reason); + Controller.getController().notifyVoiceSuccess(activity, reason); AlarmStateManager.deleteInstanceAndUpdateParent(context, instance); Events.sendAlarmEvent(R.string.action_delete, R.string.label_intent); } @@ -420,7 +422,7 @@ public class HandleApiCalls extends Activity { if (instance == null) { final String reason = mContext.getString(R.string.cannot_locate_alarm); LogUtils.i(reason); - Voice.notifyFailure(mActivity, reason); + Controller.getController().notifyVoiceFailure(mActivity, reason); return null; } @@ -432,7 +434,7 @@ public class HandleApiCalls extends Activity { if (alarms.isEmpty()) { final String reason = mContext.getString(R.string.no_alarms); LogUtils.i(reason); - Voice.notifyFailure(mActivity, reason); + Controller.getController().notifyVoiceFailure(mActivity, reason); return null; } @@ -445,7 +447,8 @@ public class HandleApiCalls extends Activity { .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)); + final String voiceMessage = mContext.getString(R.string.pick_alarm_to_delete); + Controller.getController().notifyVoiceSuccess(mActivity, voiceMessage); return null; } @@ -465,7 +468,8 @@ public class HandleApiCalls extends Activity { .putExtra(EXTRA_ALARMS, matchingAlarms.toArray(new Parcelable[matchingAlarms.size()])); mContext.startActivity(pickSelectionIntent); - Voice.notifySuccess(mActivity, mContext.getString(R.string.pick_alarm_to_delete)); + final String voiceMessage = mContext.getString(R.string.pick_alarm_to_delete); + Controller.getController().notifyVoiceSuccess(mActivity, voiceMessage); return null; } @@ -484,7 +488,7 @@ public class HandleApiCalls extends Activity { if (!matches) { final String reason = mContext.getString(R.string.no_alarm_scheduled_for_this_time); - Voice.notifyFailure(mActivity, reason); + Controller.getController().notifyVoiceFailure(mActivity, reason); LogUtils.i(reason); } @@ -507,7 +511,8 @@ public class HandleApiCalls extends Activity { hour = intent.getIntExtra(AlarmClock.EXTRA_HOUR, hour); if (hour < 0 || hour > 23) { final int mins = intent.getIntExtra(AlarmClock.EXTRA_MINUTES, 0); - Voice.notifyFailure(this, getString(R.string.invalid_time, hour, mins, " ")); + final String voiceMessage = getString(R.string.invalid_time, hour, mins, " "); + Controller.getController().notifyVoiceFailure(this, voiceMessage); LogUtils.i("HandleApiCalls given illegal hour: " + hour); return; } @@ -516,7 +521,8 @@ public class HandleApiCalls extends Activity { // Validate the minute, if one was given. final int minutes = intent.getIntExtra(AlarmClock.EXTRA_MINUTES, 0); if (minutes < 0 || minutes > 59) { - Voice.notifyFailure(this, getString(R.string.invalid_time, hour, minutes, " ")); + final String voiceMessage = getString(R.string.invalid_time, hour, minutes, " "); + Controller.getController().notifyVoiceFailure(this, voiceMessage); LogUtils.i("HandleApiCalls given illegal minute: " + minutes); return; } @@ -529,7 +535,8 @@ public class HandleApiCalls extends Activity { // Attempt to locate the alarm via the deeplink. final Alarm alarm = Alarm.getAlarm(cr, deeplink); if (alarm == null) { - Voice.notifyFailure(this, getString(R.string.cannot_locate_alarm)); + final String voiceMessage = getString(R.string.cannot_locate_alarm); + Controller.getController().notifyVoiceFailure(this, voiceMessage); LogUtils.i(String.format("HandleApiCalls cannot locate alarm using: %s", deeplink)); return; } @@ -549,7 +556,8 @@ public class HandleApiCalls extends Activity { final String time = DateFormat.getTimeFormat(this).format( alarmInstance.getAlarmTime().getTime()); - Voice.notifySuccess(this, getString(R.string.alarm_is_set, time)); + final String voiceMessage = getString(R.string.alarm_is_set, time); + Controller.getController().notifyVoiceSuccess(this, voiceMessage); Events.sendAlarmEvent(R.string.action_update, R.string.label_intent); LogUtils.i("HandleApiCalls updated existing alarm: %s", alarm); return; @@ -568,7 +576,8 @@ public class HandleApiCalls extends Activity { // Open DeskClock which is now positioned on the alarms tab. startActivity(createAlarm); - Voice.notifyFailure(this, getString(R.string.invalid_time, hour, minutes, " ")); + final String voiceMessage = getString(R.string.invalid_time, hour, minutes, " "); + Controller.getController().notifyVoiceFailure(this, voiceMessage); LogUtils.i("HandleApiCalls not given time information; opening UI"); return; } @@ -609,7 +618,7 @@ public class HandleApiCalls extends Activity { Events.sendAlarmEvent(R.string.action_create, R.string.label_intent); final String time = DateFormat.getTimeFormat(this).format( alarmInstance.getAlarmTime().getTime()); - Voice.notifySuccess(this, getString(R.string.alarm_is_set, time)); + Controller.getController().notifyVoiceSuccess(this, getString(R.string.alarm_is_set, time)); LogUtils.i("HandleApiCalls created alarm: %s", alarm); } @@ -648,7 +657,8 @@ public class HandleApiCalls extends Activity { // Verify that the timer length is between one second and one day. final long lengthMillis = SECOND_IN_MILLIS * intent.getIntExtra(AlarmClock.EXTRA_LENGTH, 0); if (lengthMillis < Timer.MIN_LENGTH || lengthMillis > Timer.MAX_LENGTH) { - Voice.notifyFailure(this, getString(R.string.invalid_timer_length)); + final String voiceMessage = getString(R.string.invalid_timer_length); + Controller.getController().notifyVoiceFailure(this, voiceMessage); LogUtils.i("Invalid timer length requested: " + lengthMillis); return; } @@ -676,7 +686,7 @@ public class HandleApiCalls extends Activity { // Start the selected timer. DataModel.getDataModel().startTimer(timer); Events.sendTimerEvent(R.string.action_start, R.string.label_intent); - Voice.notifySuccess(this, getString(R.string.timer_created)); + Controller.getController().notifyVoiceSuccess(this, getString(R.string.timer_created)); // If not instructed to skip the UI, display the running timer. if (!skipUi) { diff --git a/src/com/android/deskclock/HandleDeskClockApiCalls.java b/src/com/android/deskclock/HandleDeskClockApiCalls.java index 23be9b81e..0ac6670df 100644 --- a/src/com/android/deskclock/HandleDeskClockApiCalls.java +++ b/src/com/android/deskclock/HandleDeskClockApiCalls.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; +import com.android.deskclock.controller.Controller; import com.android.deskclock.data.City; import com.android.deskclock.data.DataModel; import com.android.deskclock.data.Timer; @@ -164,9 +165,9 @@ public class HandleDeskClockApiCalls extends Activity { } if (fail) { - Voice.notifyFailure(this, reason); + Controller.getController().notifyVoiceFailure(this, reason); } else { - Voice.notifySuccess(this, reason); + Controller.getController().notifyVoiceSuccess(this, reason); } LogUtils.i(reason); } @@ -211,7 +212,7 @@ public class HandleDeskClockApiCalls extends Activity { } if (timer == null) { - Voice.notifyFailure(this, reason); + Controller.getController().notifyVoiceFailure(this, reason); } else { timerId = timer.getId(); @@ -243,7 +244,7 @@ public class HandleDeskClockApiCalls extends Activity { throw new IllegalArgumentException("unknown timer action: " + action); } - Voice.notifySuccess(this, reason); + Controller.getController().notifyVoiceSuccess(this, reason); } LogUtils.i(reason); @@ -285,7 +286,7 @@ public class HandleDeskClockApiCalls extends Activity { if (cityName == null) { reason = getString(R.string.no_city_selected); LogUtils.i(reason); - Voice.notifySuccess(this, reason); + Controller.getController().notifyVoiceSuccess(this, reason); startActivity(new Intent(this, CitySelectionActivity.class) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); return; @@ -296,7 +297,7 @@ public class HandleDeskClockApiCalls extends Activity { if (city == null) { reason = getString(R.string.the_city_you_specified_is_not_available); LogUtils.i(reason); - Voice.notifyFailure(this, reason); + Controller.getController().notifyVoiceFailure(this, reason); startActivity(new Intent(this, CitySelectionActivity.class) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); return; @@ -337,9 +338,9 @@ public class HandleDeskClockApiCalls extends Activity { } if (fail) { - Voice.notifyFailure(this, reason); + Controller.getController().notifyVoiceFailure(this, reason); } else { - Voice.notifySuccess(this, reason); + Controller.getController().notifyVoiceSuccess(this, reason); } LogUtils.i(reason); } diff --git a/src/com/android/deskclock/Voice.java b/src/com/android/deskclock/Voice.java deleted file mode 100644 index f33bbe7ab..000000000 --- a/src/com/android/deskclock/Voice.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.deskclock; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.VoiceInteractor; -import android.os.Build; - -/** - * Notifies Voice Interactor about whether the action - * was successful. Voice Interactor is called only if - * the build version is post-Lollipop. - */ -public final class Voice { - - private static Delegate sDelegate = new VoiceInteractorDelegate(); - - private Voice() { } - - public static void setDelegate(Delegate delegate) { - sDelegate = delegate; - } - - public static Delegate getDelegate() { - return sDelegate; - } - - public static void notifySuccess(Activity activity, String message) { - if (Utils.isMOrLater()) { - sDelegate.notifySuccess(activity.getVoiceInteractor(), message); - } - } - - public static void notifyFailure(Activity activity, String message) { - if (Utils.isMOrLater()) { - sDelegate.notifyFailure(activity.getVoiceInteractor(), message); - } - } - - public interface Delegate { - void notifySuccess(VoiceInteractor vi, String message); - - void notifyFailure(VoiceInteractor vi, String message); - } - - @TargetApi(Build.VERSION_CODES.M) - private static class VoiceInteractorDelegate implements Delegate { - @Override - public void notifySuccess(VoiceInteractor vi, String message) { - if (vi != null) { - final VoiceInteractor.Prompt prompt = new VoiceInteractor.Prompt(message); - vi.submitRequest(new VoiceInteractor.CompleteVoiceRequest(prompt, null)); - } - } - - @Override - public void notifyFailure(VoiceInteractor vi, String message) { - if (vi != null) { - final VoiceInteractor.Prompt prompt = new VoiceInteractor.Prompt(message); - vi.submitRequest(new VoiceInteractor.AbortVoiceRequest(prompt, null)); - } - } - } -}
\ No newline at end of file diff --git a/src/com/android/deskclock/controller/Controller.java b/src/com/android/deskclock/controller/Controller.java index ad15db6e4..82487e0f7 100644 --- a/src/com/android/deskclock/controller/Controller.java +++ b/src/com/android/deskclock/controller/Controller.java @@ -16,16 +16,27 @@ package com.android.deskclock.controller; +import android.app.Activity; import android.content.Context; import com.android.deskclock.Utils; -public final class Controller { +import static com.android.deskclock.Utils.enforceMainLooper; + +/** + * Interactions with Android framework components responsible for part of the user experience are + * handled via this singleton. + */ +public final class Controller implements VoiceController { private static final Controller sController = new Controller(); private Context mContext; + /** The controller that interacts with voice interaction sessions on M+. */ + private VoiceController mVoiceController; + + /** The controller that creates and updates launcher shortcuts on N MR1+ */ private ShortcutController mShortcutController; private Controller() {} @@ -39,15 +50,50 @@ public final class Controller { throw new IllegalStateException("context has already been set"); } mContext = context; + if (Utils.isMOrLater()) { + mVoiceController = new DefaultVoiceController(); + } if (Utils.isNMR1OrLater()) { mShortcutController = new ShortcutController(mContext); } } + // + // Voice Interaction + // + + /** + * @param voiceController the new delegate to control future voice interaction sessions + * @return the old delegate that controlled prior voice interaction sessions + */ + public VoiceController setVoiceController(VoiceController voiceController) { + final VoiceController oldVoiceController = mVoiceController; + mVoiceController = voiceController; + return oldVoiceController; + } + + @Override + public void notifyVoiceSuccess(Activity activity, String message) { + if (mVoiceController != null) { + mVoiceController.notifyVoiceSuccess(activity, message); + } + } + + @Override + public void notifyVoiceFailure(Activity activity, String message) { + if (mVoiceController != null) { + mVoiceController.notifyVoiceFailure(activity, message); + } + } + + // + // Shortcuts + // + public void updateShortcuts() { - Utils.enforceMainLooper(); + enforceMainLooper(); if (mShortcutController != null) { mShortcutController.updateShortcuts(); } } -} +}
\ No newline at end of file diff --git a/src/com/android/deskclock/controller/DefaultVoiceController.java b/src/com/android/deskclock/controller/DefaultVoiceController.java new file mode 100644 index 000000000..4329120b4 --- /dev/null +++ b/src/com/android/deskclock/controller/DefaultVoiceController.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.deskclock.controller; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.VoiceInteractor; +import android.app.VoiceInteractor.AbortVoiceRequest; +import android.app.VoiceInteractor.CompleteVoiceRequest; +import android.app.VoiceInteractor.Prompt; +import android.os.Build; + +@TargetApi(Build.VERSION_CODES.M) +class DefaultVoiceController implements VoiceController { + @Override + public void notifyVoiceSuccess(Activity activity, String message) { + final VoiceInteractor voiceInteractor = activity.getVoiceInteractor(); + if (voiceInteractor != null) { + final Prompt prompt = new Prompt(message); + voiceInteractor.submitRequest(new CompleteVoiceRequest(prompt, null)); + } + } + + @Override + public void notifyVoiceFailure(Activity activity, String message) { + final VoiceInteractor voiceInteractor = activity.getVoiceInteractor(); + if (voiceInteractor != null) { + final Prompt prompt = new Prompt(message); + voiceInteractor.submitRequest(new AbortVoiceRequest(prompt, null)); + } + } +}
\ No newline at end of file diff --git a/src/com/android/deskclock/controller/VoiceController.java b/src/com/android/deskclock/controller/VoiceController.java new file mode 100644 index 000000000..c4327e309 --- /dev/null +++ b/src/com/android/deskclock/controller/VoiceController.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.deskclock.controller; + +import android.app.Activity; + +/** + * Implementations of this interface are consulted to terminate a voice interaction session. + */ +public interface VoiceController { + /** + * If the {@code activity} is currently hosting a voice interaction session, indicate the voice + * command was processed successfully. + * + * @param activity an Activity that may be hosting a voice interaction session + * @param message to be spoken to the user to indicate success + */ + void notifyVoiceSuccess(Activity activity, String message); + + /** + * If the {@code activity} is currently hosting a voice interaction session, indicate the voice + * command failed and must be aborted. + * + * @param activity an Activity that may be hosting a voice interaction session + * @param message to be spoken to the user to indicate failure + */ + void notifyVoiceFailure(Activity activity, String message); +}
\ No newline at end of file |