summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBarnaby James <bjames@google.com>2015-04-13 14:33:53 -0700
committerBarnaby James <bjames@google.com>2015-04-13 14:38:51 -0700
commitc55ea15bc0d9297417a4f1d886b9c188b6bf19b5 (patch)
tree7b9297db70fdc767b9a84bbd42ab6ef536ae3874 /src
parentcdba01b11981acb1153de27208722821a6b419e6 (diff)
downloadpackages_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.java10
-rw-r--r--src/com/android/settings/fuelgauge/BatterySaverModeVoiceActivity.java51
-rw-r--r--src/com/android/settings/notification/ZenModeVoiceActivity.java241
-rw-r--r--src/com/android/settings/utils/VoiceSelection.java74
-rw-r--r--src/com/android/settings/utils/VoiceSelectionAdapter.java63
-rw-r--r--src/com/android/settings/utils/VoiceSelectionFragment.java133
-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));
+ }
}