diff options
author | Barnaby James <bjames@google.com> | 2015-04-13 14:33:53 -0700 |
---|---|---|
committer | Barnaby James <bjames@google.com> | 2015-04-13 14:38:51 -0700 |
commit | c55ea15bc0d9297417a4f1d886b9c188b6bf19b5 (patch) | |
tree | 7b9297db70fdc767b9a84bbd42ab6ef536ae3874 /src | |
parent | cdba01b11981acb1153de27208722821a6b419e6 (diff) | |
download | packages_apps_Settings-c55ea15bc0d9297417a4f1d886b9c188b6bf19b5.zip packages_apps_Settings-c55ea15bc0d9297417a4f1d886b9c188b6bf19b5.tar.gz packages_apps_Settings-c55ea15bc0d9297417a4f1d886b9c188b6bf19b5.tar.bz2 |
Add activities to support voice settings.
Adds Voice Interaction Activities for:
- Do not disturb mode (with interaction)
- Battery Saver mode
- Airplane mode
Change-Id: I4480dc3a30975d94b71714ff58fbeebddfbc1c58
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/settings/AirplaneModeVoiceActivity.java | 10 | ||||
-rw-r--r-- | src/com/android/settings/fuelgauge/BatterySaverModeVoiceActivity.java | 51 | ||||
-rw-r--r-- | src/com/android/settings/notification/ZenModeVoiceActivity.java | 241 | ||||
-rw-r--r-- | src/com/android/settings/utils/VoiceSelection.java | 74 | ||||
-rw-r--r-- | src/com/android/settings/utils/VoiceSelectionAdapter.java | 63 | ||||
-rw-r--r-- | src/com/android/settings/utils/VoiceSelectionFragment.java | 133 | ||||
-rw-r--r-- | src/com/android/settings/utils/VoiceSettingsActivity.java (renamed from src/com/android/settings/VoiceSettingsActivity.java) | 41 |
7 files changed, 600 insertions, 13 deletions
diff --git a/src/com/android/settings/AirplaneModeVoiceActivity.java b/src/com/android/settings/AirplaneModeVoiceActivity.java index 3ab0c37..e0649e4 100644 --- a/src/com/android/settings/AirplaneModeVoiceActivity.java +++ b/src/com/android/settings/AirplaneModeVoiceActivity.java @@ -20,6 +20,8 @@ import android.content.Intent; import android.provider.Settings; import android.util.Log; +import com.android.settings.utils.VoiceSettingsActivity; + /** * Activity for modifying the {@link Settings.Global#AIRPLANE_MODE_ON AIRPLANE_MODE_ON} * setting using the Voice Interaction API. @@ -27,14 +29,14 @@ import android.util.Log; public class AirplaneModeVoiceActivity extends VoiceSettingsActivity { private static final String TAG = "AirplaneModeVoiceActivity"; - protected void onVoiceSettingInteraction(Intent intent) { + protected boolean onVoiceSettingInteraction(Intent intent) { if (intent.hasExtra(Settings.EXTRA_AIRPLANE_MODE_ENABLED)) { - boolean enabled = - intent.getBooleanExtra(Settings.EXTRA_AIRPLANE_MODE_ENABLED, false); Settings.Global.putInt(getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, enabled ? 1 : 0); + Settings.Global.AIRPLANE_MODE_ON, + intent.getBooleanExtra(Settings.EXTRA_AIRPLANE_MODE_ENABLED, false) ? 1 : 0); } else { Log.v(TAG, "Missing airplane mode extra"); } + return true; } } diff --git a/src/com/android/settings/fuelgauge/BatterySaverModeVoiceActivity.java b/src/com/android/settings/fuelgauge/BatterySaverModeVoiceActivity.java new file mode 100644 index 0000000..4494887 --- /dev/null +++ b/src/com/android/settings/fuelgauge/BatterySaverModeVoiceActivity.java @@ -0,0 +1,51 @@ +/* + * 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.settings.fuelguage; + +import static android.provider.Settings.EXTRA_BATTERY_SAVER_MODE_ENABLED; + +import android.content.Context; +import android.content.Intent; +import android.os.PowerManager; +import android.provider.Settings; +import android.util.Log; + +import com.android.settings.utils.VoiceSettingsActivity; + +/** + * Activity for modifying the {@link android.os.PowerManager} power save mode + * setting using the Voice Interaction API. + */ +public class BatterySaverModeVoiceActivity extends VoiceSettingsActivity { + private static final String TAG = "BatterySaverModeVoiceActivity"; + + protected boolean onVoiceSettingInteraction(Intent intent) { + if (intent.hasExtra(EXTRA_BATTERY_SAVER_MODE_ENABLED)) { + PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); + if (powerManager.setPowerSaveMode( + intent.getBooleanExtra(EXTRA_BATTERY_SAVER_MODE_ENABLED, false))) { + notifySuccess(null); + } else { + Log.v(TAG, "Unable to set power mode"); + notifyFailure(null); + } + } else { + Log.v(TAG, "Missing battery saver mode extra"); + } + return true; + } +} diff --git a/src/com/android/settings/notification/ZenModeVoiceActivity.java b/src/com/android/settings/notification/ZenModeVoiceActivity.java new file mode 100644 index 0000000..c7c1151 --- /dev/null +++ b/src/com/android/settings/notification/ZenModeVoiceActivity.java @@ -0,0 +1,241 @@ +/* + * 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.settings.notification; + +import static android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_MINUTES; +import static android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_ENABLED; + +import com.android.settings.R; +import com.android.settings.utils.VoiceSelectionAdapter; +import com.android.settings.utils.VoiceSelection; +import com.android.settings.utils.VoiceSelectionFragment; +import com.android.settings.utils.VoiceSettingsActivity; + +import android.app.Fragment; +import android.app.NotificationManager; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.os.UserHandle; +import android.provider.Settings.Global; +import android.service.notification.Condition; +import android.service.notification.ZenModeConfig; +import android.text.format.DateFormat; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +/** + * Activity for modifying the Zen mode (Do not disturb) by voice + * using the Voice Interaction API. + */ +public class ZenModeVoiceActivity extends VoiceSettingsActivity { + private static final String TAG = "ZenModeVoiceActivity"; + private static final int MINUTES_MS = 60 * 1000; + + @Override + protected boolean onVoiceSettingInteraction(Intent intent) { + setContentView(R.layout.voice_interaction); + pickNotificationMode(intent); + return false; + } + + /** + * Start a voice interaction to ask what kind of interruptions should + * be permitted. The intent can optionally include extra information about the type + * of interruptions desired or how long interruptions should be limited to that are + * used as hints. + */ + private void pickNotificationMode(final Intent intent) { + boolean enabled = intent.getBooleanExtra(EXTRA_DO_NOT_DISTURB_MODE_ENABLED, false); + boolean specified = intent.hasExtra(EXTRA_DO_NOT_DISTURB_MODE_ENABLED); + + List<VoiceSelection> states = new ArrayList<VoiceSelection>(); + if (!specified || enabled) { + states.add(new ModeSelection(this, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, + R.string.zen_mode_option_important_interruptions, + R.string.zen_mode_option_important_voice_synonyms)); + states.add(new ModeSelection(this, Global.ZEN_MODE_ALARMS, + R.string.zen_mode_option_alarms, + R.string.zen_mode_option_alarms_voice_synonyms)); + states.add(new ModeSelection(this, Global.ZEN_MODE_NO_INTERRUPTIONS, + R.string.zen_mode_option_no_interruptions, + R.string.zen_mode_option_no_interruptions_voice_synonyms)); + } + if (!specified || !enabled) { + states.add(new ModeSelection(this, Global.ZEN_MODE_OFF, + R.string.zen_mode_option_off, + R.string.zen_mode_option_off_voice_synonyms)); + } + VoiceSelectionFragment fragment = new VoiceSelectionFragment(); + fragment.setArguments(VoiceSelectionFragment.createArguments( + getString(R.string.zen_mode_interruptions_voice_prompt))); + fragment.setListAdapter( + new VoiceSelectionAdapter(this, R.layout.voice_item_row, states)); + fragment.setOnItemSelectedHandler(new VoiceSelection.OnItemSelectedListener() { + @Override + public void onItemSelected(int index, VoiceSelection selection) { + int mode = ((ModeSelection) selection).mMode; + ConditionSelection conditionSelection = getConditionSelection( + intent.getIntExtra(EXTRA_DO_NOT_DISTURB_MODE_MINUTES, 0)); + if (mode != Global.ZEN_MODE_OFF) { + if (conditionSelection == null) { + pickDuration(selection.getLabel(), mode); + return; + } + } + setZenModeConfig(mode, conditionSelection.mCondition); + notifySuccess(getChangeSummary(mode, conditionSelection)); + finish(); + } + }); + showFragment(fragment, "pick_mode_fragment"); + } + + /** + * Start a voice interaction to ask for the zen mode duration. + */ + private void pickDuration(CharSequence label, final int mode) { + setTitle(label.toString()); + List<VoiceSelection> states = new ArrayList<VoiceSelection>(); + states.add(new ConditionSelection(null, -1, + getString(R.string.zen_mode_duration_indefinte_voice_label), + getString(R.string.zen_mode_duration_indefinite_voice_synonyms))); + for (int i = ZenModeConfig.MINUTE_BUCKETS.length - 1; i >= 0; --i) { + states.add(getConditionSelection(ZenModeConfig.MINUTE_BUCKETS[i])); + } + + VoiceSelectionFragment fragment = new VoiceSelectionFragment(); + fragment.setArguments(VoiceSelectionFragment.createArguments( + getString(R.string.zen_mode_duration_voice_prompt))); + fragment.setListAdapter( + new VoiceSelectionAdapter(this, R.layout.voice_item_row, states)); + fragment.setOnItemSelectedHandler(new VoiceSelection.OnItemSelectedListener() { + @Override + public void onItemSelected(int index, VoiceSelection item) { + ConditionSelection selection = ((ConditionSelection) item); + setZenModeConfig(mode, selection.mCondition); + notifySuccess(getChangeSummary(mode, selection)); + finish(); + } + }); + showFragment(fragment, "pick_duration_fragment"); + } + + private void showFragment(Fragment fragment, String tag) { + getFragmentManager() + .beginTransaction() + .replace(R.id.fragment_root, fragment, tag) + .commit(); + } + + private void setZenModeConfig(int mode, Condition condition) { + if (condition != null) { + NotificationManager.from(this).setZenMode(mode, condition.id, TAG); + } else { + NotificationManager.from(this).setZenMode(mode, null, TAG); + } + } + + /** + * Produce a summary of the Zen mode change to be read aloud as TTS. + */ + private CharSequence getChangeSummary(int mode, ConditionSelection duration) { + int indefinite = -1; + int byMinute = -1; + int byHour = -1; + + switch (mode) { + case Global.ZEN_MODE_ALARMS: + indefinite = R.string.zen_mode_summary_alarams_only_indefinite; + byMinute = R.plurals.zen_mode_summary_alarms_only_by_minute; + byHour = R.plurals.zen_mode_summary_alarms_only_by_hour; + break; + case Global.ZEN_MODE_NO_INTERRUPTIONS: + indefinite = R.string.zen_mode_summary_no_interruptions_indefinite; + byMinute = R.plurals.zen_mode_summary_no_interruptions_by_minute; + byHour = R.plurals.zen_mode_summary_no_interruptions_by_hour; + break; + case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: + indefinite = R.string.zen_mode_summary_priority_indefinitely; + byMinute = R.plurals.zen_mode_summary_priority_by_minute; + byHour = R.plurals.zen_mode_summary_priority_by_hour; + break; + default: + case Global.ZEN_MODE_OFF: + indefinite = R.string.zen_mode_summary_always; + break; + }; + + if (duration == null || duration.mCondition == null) { + return getString(indefinite); + } + + long time = System.currentTimeMillis() + duration.mMinutes * MINUTES_MS; + String skeleton = DateFormat.is24HourFormat(this, UserHandle.myUserId()) ? "Hm" : "hma"; + String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); + CharSequence formattedTime = DateFormat.format(pattern, time); + Resources res = getResources(); + + if (duration.mMinutes < 60) { + return res.getQuantityString(byMinute, + duration.mMinutes, duration.mMinutes, formattedTime); + } else { + int hours = duration.mMinutes / 60; + return res.getQuantityString(byHour, hours, hours, formattedTime); + } + } + + private ConditionSelection getConditionSelection(int minutes) { + Condition condition = ZenModeConfig.toTimeCondition(this, minutes, UserHandle.myUserId()); + Resources res = getResources(); + if (minutes <= 0) { + return null; + } else if (minutes < 60) { + String label = res.getQuantityString(R.plurals.zen_mode_duration_minutes_voice_label, + minutes, minutes); + return new ConditionSelection(condition, minutes, label, Integer.toString(minutes)); + } else { + int hours = minutes / 60; + String label = res.getQuantityString(R.plurals.zen_mode_duration_hours_voice_label, + hours, hours); + return new ConditionSelection(condition, minutes, label, Integer.toString(hours)); + } + } + + private static class ConditionSelection extends VoiceSelection { + Condition mCondition; + int mMinutes; + + public ConditionSelection(Condition condition, int minutes, CharSequence label, + CharSequence synonyms) { + super(label, synonyms); + mMinutes = minutes; + mCondition = condition; + } + } + + private static class ModeSelection extends VoiceSelection { + int mMode; + + public ModeSelection(Context context, int mode, int label, int synonyms) { + super(context.getString(label), context.getString(synonyms)); + mMode = mode; + } + } +} diff --git a/src/com/android/settings/utils/VoiceSelection.java b/src/com/android/settings/utils/VoiceSelection.java new file mode 100644 index 0000000..997d2cc --- /dev/null +++ b/src/com/android/settings/utils/VoiceSelection.java @@ -0,0 +1,74 @@ +/* + * 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.settings.utils; + +import android.app.VoiceInteractor.PickOptionRequest.Option; +import android.os.Bundle; +import android.text.TextUtils; + +/** + * Model for a single item that can be selected by a {@link VoiceSelectionFragment}. + * Each item consists of a visual label and several alternative synonyms for the item + * that can be used to identify the item by voice. + */ +public class VoiceSelection { + final CharSequence mLabel; + final CharSequence[] mSynonyms; + + /** + * Created a new selectable item with a visual label and a set of synonyms. + */ + public VoiceSelection(CharSequence label, CharSequence synonyms) { + mLabel = label; + mSynonyms = TextUtils.split(synonyms.toString(), ","); + } + + /** + * Created a new selectable item with a visual label and no synonyms. + */ + public VoiceSelection(CharSequence label) { + mLabel = label; + mSynonyms = null; + } + + public CharSequence getLabel() { + return mLabel; + } + + public CharSequence[] getSynonyms() { + return mSynonyms; + } + + Option toOption(int index) { + Option result = new Option(mLabel); + Bundle extras = new Bundle(); + extras.putInt("index", index); + result.setExtras(extras); + + for (CharSequence synonym : mSynonyms) { + result.addSynonym(synonym); + } + return result; + } + + /** + * Listener interface for when an item is selected. + */ + public interface OnItemSelectedListener { + abstract void onItemSelected(int position, VoiceSelection selection); + }; +} diff --git a/src/com/android/settings/utils/VoiceSelectionAdapter.java b/src/com/android/settings/utils/VoiceSelectionAdapter.java new file mode 100644 index 0000000..2c060c2 --- /dev/null +++ b/src/com/android/settings/utils/VoiceSelectionAdapter.java @@ -0,0 +1,63 @@ +/* + * 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.settings.utils; + +import android.content.Context; +import android.widget.ArrayAdapter; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import android.app.Activity; +import com.android.settings.R; + +import java.util.List; +import android.util.Log; + +/** + * Array adapter for selecting an item by voice interaction. Each row includes a visual + * indication of the 1-indexed position of the item so that a user can easily say + * "number 4" to select it. + */ +public class VoiceSelectionAdapter extends ArrayAdapter<VoiceSelection> { + public VoiceSelectionAdapter(Context context, int resource, List<VoiceSelection> objects) { + super(context, resource, objects); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + VoiceSelection item = getItem(position); + View row = convertView; + if (row == null) { + LayoutInflater inflater = ((Activity) getContext()).getLayoutInflater(); + row = inflater.inflate(R.layout.voice_item_row, parent, false); + } + + TextView label = (TextView) row.findViewById(R.id.voice_item_label); + if (label != null) { + label.setText(item.getLabel()); + } + + TextView positionLabel = (TextView) row.findViewById(R.id.voice_item_position); + if (positionLabel != null) { + positionLabel.setText(Integer.toString(position + 1)); + } + + return row; + } +}; diff --git a/src/com/android/settings/utils/VoiceSelectionFragment.java b/src/com/android/settings/utils/VoiceSelectionFragment.java new file mode 100644 index 0000000..c2e80d3 --- /dev/null +++ b/src/com/android/settings/utils/VoiceSelectionFragment.java @@ -0,0 +1,133 @@ +/* + * 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.settings.utils; + +import android.app.ListFragment; +import android.app.VoiceInteractor; +import android.app.VoiceInteractor.PickOptionRequest; +import android.app.VoiceInteractor.PickOptionRequest.Option; +import android.os.Bundle; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListAdapter; +import android.widget.ListView; + +import java.util.List; + +/** + * An Activity fragment that presents a set of options as a visual list and also allows + * items to be selected by the users voice. + */ +public class VoiceSelectionFragment extends ListFragment { + private static final String EXTRA_SELECTION_PROMPT = "selection_prompt"; + + private CharSequence mPrompt = null; + private VoiceInteractor.Request mRequest = null; + private VoiceInteractor mVoiceInteractor = null; + private VoiceSelection.OnItemSelectedListener mOnItemSelectedListener = null; + + /** + * No-args ctor required for fragment. + */ + public VoiceSelectionFragment() {} + + @Override + public void onCreate(Bundle args) { + super.onCreate(args); + mPrompt = getArguments().getCharSequence(EXTRA_SELECTION_PROMPT); + } + + /** + * Set the prompt spoken when the fragment is presented. + */ + static public Bundle createArguments(CharSequence prompt) { + Bundle args = new Bundle(); + args.putCharSequence(EXTRA_SELECTION_PROMPT, prompt); + return args; + } + + private VoiceSelection getSelectionAt(int position) { + return ((ArrayAdapter<VoiceSelection>) getListAdapter()).getItem(position); + } + + @Override + public void onStart() { + super.onStart(); + + final int numItems = getListAdapter().getCount(); + if (numItems <= 0) { + return; + } + + Option[] options = new Option[numItems]; + for (int idx = 0; idx < numItems; idx++) { + options[idx] = getSelectionAt(idx).toOption(idx); + } + mRequest = new PickOptionRequest(mPrompt, options, null) { + @Override + public void onPickOptionResult(boolean isComplete, Option[] options, Bundle args) { + if (!isComplete || options == null) { + return; + } + if (options.length == 1 && mOnItemSelectedListener != null) { + int idx = options[0].getExtras().getInt("index", -1); + mOnItemSelectedListener.onItemSelected(idx, getSelectionAt(idx)); + } else { + onCancel(); + } + } + }; + mVoiceInteractor = getActivity().getVoiceInteractor(); + if (mVoiceInteractor != null) { + mVoiceInteractor.submitRequest(mRequest); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mVoiceInteractor = null; + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + if (mRequest != null) { + mRequest.cancel(); + mRequest = null; + } + + if (mOnItemSelectedListener != null) { + mOnItemSelectedListener.onItemSelected(position, getSelectionAt(position)); + } + } + + + /** + * Sets the selection handler for an item either by voice or by touch. + */ + public void setOnItemSelectedHandler(VoiceSelection.OnItemSelectedListener listener) { + mOnItemSelectedListener = listener; + } + + /** + * Called when the user cancels the interaction. The default implementation is to + * finish the activity. + */ + public void onCancel() { + getActivity().finish(); + } +}; diff --git a/src/com/android/settings/VoiceSettingsActivity.java b/src/com/android/settings/utils/VoiceSettingsActivity.java index b5e8ede..ac5b8be 100644 --- a/src/com/android/settings/VoiceSettingsActivity.java +++ b/src/com/android/settings/utils/VoiceSettingsActivity.java @@ -14,17 +14,20 @@ * limitations under the License. */ -package com.android.settings; +package com.android.settings.utils; import android.app.Activity; +import android.app.VoiceInteractor; +import android.app.VoiceInteractor.CompleteVoiceRequest; import android.content.Intent; import android.os.Bundle; import android.util.Log; /** * Activity for modifying a setting using the Voice Interaction API. This activity - * MUST only modify the setting if the intent was sent using - * {@link android.service.voice.VoiceInteractionSession#startVoiceActivity startVoiceActivity}. + * will only allow modifying the setting if the intent was sent using + * {@link android.service.voice.VoiceInteractionSession#startVoiceActivity startVoiceActivity} + * by the current Voice Interaction Service. */ abstract public class VoiceSettingsActivity extends Activity { @@ -34,18 +37,38 @@ abstract public class VoiceSettingsActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (isVoiceInteraction()) { + if (isVoiceInteraction() || savedInstanceState == null) { // Only permit if this is a voice interaction. - onVoiceSettingInteraction(getIntent()); + if (onVoiceSettingInteraction(getIntent())) { + // If it's complete, finish. + finish(); + } } else { Log.v(TAG, "Cannot modify settings without voice interaction"); + finish(); } - finish(); } /** - * Modify the setting as a voice interaction. The activity will finish - * after this method is called. + * Modify the setting as a voice interaction. Should return true if the + * voice interaction is complete or false if more interaction is required. */ - abstract protected void onVoiceSettingInteraction(Intent intent); + abstract protected boolean onVoiceSettingInteraction(Intent intent); + + /** + * Send a notification that the interaction was successful. If {@link prompt} is + * not null, then it will be read to the user. + */ + protected void notifySuccess(CharSequence prompt) { + if (getVoiceInteractor() != null) { + getVoiceInteractor().submitRequest(new CompleteVoiceRequest(prompt, null)); + } + } + + /** + * Indicates when the setting could not be changed. + */ + protected void notifyFailure(String reason) { + getVoiceInteractor().submitRequest(new VoiceInteractor.AbortVoiceRequest(reason, null)); + } } |