diff options
Diffstat (limited to 'src/com/android/settings/utils')
4 files changed, 344 insertions, 0 deletions
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/utils/VoiceSettingsActivity.java b/src/com/android/settings/utils/VoiceSettingsActivity.java new file mode 100644 index 0000000..ac5b8be --- /dev/null +++ b/src/com/android/settings/utils/VoiceSettingsActivity.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014 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.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 + * 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 { + + private static final String TAG = "VoiceSettingsActivity"; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (isVoiceInteraction() || savedInstanceState == null) { + // Only permit if this is a voice interaction. + if (onVoiceSettingInteraction(getIntent())) { + // If it's complete, finish. + finish(); + } + } else { + Log.v(TAG, "Cannot modify settings without voice interaction"); + finish(); + } + } + + /** + * 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 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)); + } +} |