Simplify Zen mode voice activity.

Zen mode voice activity now only sets the notification mode to alarms mode
or off. A duration may be specified if it was in the original intent.

Change-Id: Ica472ca9c6dcbce473832f4f922baf225df4951b
Bug: 21024455
This commit is contained in:
Barnaby James
2015-05-10 16:24:05 -07:00
parent 69a03f7517
commit 0474b723e1
10 changed files with 31 additions and 634 deletions

View File

@@ -1064,8 +1064,8 @@
</activity>
<activity android:name=".notification.ZenModeVoiceActivity"
android:theme="@android:style/Theme.Material.Light"
android:label="@string/zen_mode_interruptions_voice_title">
android:theme="@android:style/Theme.Material.Light.Voice"
android:label="@string/zen_mode_settings_title">
<intent-filter>
<action android:name="android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE" />
<category android:name="android.intent.category.DEFAULT" />

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/voice_interaction_highlight" />
</shape>

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="8dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/voice_interaction_highlight"
android:id="@+id/voice_fragment_header" />
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/voice_fragment_root"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View File

@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/row_one"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginTop="15dp"
android:layout_marginBottom="15dp">
<TextView
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/voice_item_label" />
<TextView
android:layout_width="80px"
android:layout_height="80px"
android:gravity="center_horizontal|center_vertical"
android:background="@drawable/bg_voice_position"
android:textAppearance="?android:attr/textAppearanceMediumInverse"
android:textStyle="bold"
android:id="@+id/voice_item_position" />
</LinearLayout>
</LinearLayout>

View File

@@ -6223,72 +6223,6 @@
<!-- [CHAR LIMIT=60] Zen mode settings: End time option: Summary text value format when end time = next day -->
<string name="zen_mode_end_time_next_day_summary_format"><xliff:g id="formatted_time" example="7:00 AM">%s</xliff:g> next day</string>
<!-- [CHAR LIMIT=NONE] Zen mode voice: Activity title for interruption level -->
<string name="zen_mode_interruptions_voice_title">Interruptions</string>
<!-- [CHAR LIMIT=NONE] Zen mode voice: Header for interruption level -->
<string name="zen_mode_interruptions_voice_header">When calls and notifications arrive</string>
<!-- [CHAR LIMIT=NONE] Zen mode voice: Prompt read for interruption type -->
<string name="zen_mode_interruptions_voice_prompt">When would you like to be interrupted?</string>
<!-- [CHAR LIMIT=NONE] Zen mode voice: Prompt read for zen mode duration -->
<string name="zen_mode_duration_voice_prompt">For how long?</string>
<!-- [CHAR LIMIT=80] Zen mode voice: All interruptions -->
<string name="zen_mode_option_voice_all_interruptions">Always interrupt</string>
<!-- [CHAR LIMIT=NONE] Zen mode voice: Comma delimited synonyms for all interriuptions -->
<string name="zen_mode_option_voice_all_interruptions_synonyms">off,all,everything</string>
<!-- [CHAR LIMIT=80] Zen mode voice: Important interruptions -->
<string name="zen_mode_option_voice_important_interruptions">Allow only priority interruptions</string>
<!-- [CHAR LIMIT=NONE] Zen mode voice: Comma delimited synonyms for important interriuptions -->
<string name="zen_mode_option_voice_important_synonyms">important,priority,priority only,only priority,priority notifications</string>
<!-- [CHAR LIMIT=80] Zen mode voice option: Alarms only -->
<string name="zen_mode_option_voice_alarms">Allow only alarms</string>
<!-- [CHAR LIMIT=NONE] Zen mode voice: Comma delimited synonyms for alarm interriuptions -->
<string name="zen_mode_option_voice_alarms_synonyms">alarms,alarms only,only alarms</string>
<!-- [CHAR LIMIT=80] Zen mode voice: No interruptions -->
<string name="zen_mode_option_voice_no_interruptions">Don\u2019t interrupt</string>
<!-- [CHAR LIMIT=NONE] Zen mode voice: Comma delimited synonyms for no interriuptions -->
<string name="zen_mode_option_voice_no_interruptions_synonyms">none,never,nothing,no interruptions</string>
<!-- [CHAR LIMIT=40] Zen mode voice: Label for indefinite mode duration -->
<string name="zen_mode_duration_indefinte_voice_label">Indefinitely</string>
<!-- [CHAR LIMIT=40] Zen mode voice: Label for duration in minutes -->
<plurals name="zen_mode_duration_minutes_voice_label">
<item quantity="one"><xliff:g id="count" example="1">%d</xliff:g> minute</item>
<item quantity="other"><xliff:g id="count" example="10">%d</xliff:g> minutes</item>
</plurals>
<!-- [CHAR LIMIT=40] Zen mode voice: Label for duration in hours -->
<plurals name="zen_mode_duration_hours_voice_label">
<item quantity="one"><xliff:g id="count" example="1">%d</xliff:g> hour</item>
<item quantity="other"><xliff:g id="count" example="10">%d</xliff:g> hours</item>
</plurals>
<!-- [CHAR LIMIT=NONE] Zen mode voice - spoken summary: important only duration indefinite. -->
<string name="zen_mode_summary_priority_indefinitely">Change to priority notifications only indefinitely</string>
<!-- [CHAR LIMIT=NONE] Zen mode voice- spoken summary: important only duration minutes. -->
<plurals name="zen_mode_summary_priority_by_minute">
<item quantity="one">Change to priority notifications only for one minute until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
<item quantity="other">Change to priority notifications only for <xliff:g id="duration" example="2">%1$d</xliff:g> minutes until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
</plurals>
<!-- [CHAR LIMIT=NONE] Zen mode voice- spoken summary: important only duration hours. -->
<plurals name="zen_mode_summary_priority_by_hour">
<item quantity="one">Change to priority notifications only for one hour until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
<item quantity="other">Change to priority notifications only for <xliff:g id="duration" example="2">%1$d</xliff:g> hours (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
</plurals>
<!-- [CHAR LIMIT=NONE] Zen mode voice - spoken summary: alarms only duration indefinite. -->
<string name="zen_mode_summary_alarams_only_indefinite">Change to alarms only indefinitely</string>
@@ -6304,27 +6238,9 @@
<item quantity="other">Change to alarms only for <xliff:g id="duration" example="2">%1$d</xliff:g> hours until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
</plurals>
<!-- [CHAR LIMIT=NONE] Zen mode voice - spoken summary: no interruptions duration indefinite. -->
<string name="zen_mode_summary_no_interruptions_indefinite">Change to don\u2019t interrupt indefinitely</string>
<!-- [CHAR LIMIT=NONE] Zen mode voice- spoken summary: alarms only duration minutes. -->
<plurals name="zen_mode_summary_no_interruptions_by_minute">
<item quantity="one">Change to don\u2019t interrupt for one minute until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
<item quantity="other">Change to don\u2019t interrupt for <xliff:g id="duration" example="2">%1$d</xliff:g> minutes (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
</plurals>
<!-- [CHAR LIMIT=NONE] Zen mode voice- spoken summary: alarms only duration hours. -->
<plurals name="zen_mode_summary_no_interruptions_by_hour">
<item quantity="one">Change to don\u2019t interrupt for one hour until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
<item quantity="other">Change to don\u2019t interrupt for <xliff:g id="duration" example="2">%1$d</xliff:g> hours until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
</plurals>
<!-- [CHAR LIMIT=NONE] Zen mode voice - spoken summary: off. -->
<string name="zen_mode_summary_always">Change to always interrupt</string>
<!-- [CHAR LIMIT=NONE] Zen mode voice: Comma delimited synonyms for indefinte duration -->
<string name="zen_mode_duration_indefinite_voice_synonyms">forever</string>
<!-- [CHAR LIMIT=20] Notifications settings: Apps section header -->
<string name="notification_settings_apps_title">App notifications</string>

View File

@@ -20,24 +20,20 @@ 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.media.AudioManager;
import android.provider.Settings.Global;
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.text.format.DateFormat;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
@@ -50,97 +46,31 @@ public class ZenModeVoiceActivity extends VoiceSettingsActivity {
@Override
protected boolean onVoiceSettingInteraction(Intent intent) {
setContentView(R.layout.voice_interaction);
pickNotificationMode(intent);
return false;
}
if (intent.hasExtra(EXTRA_DO_NOT_DISTURB_MODE_ENABLED)) {
int minutes = intent.getIntExtra(EXTRA_DO_NOT_DISTURB_MODE_MINUTES, -1);
Condition condition = null;
int mode = Global.ZEN_MODE_OFF;
/**
* 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);
setHeader(getString(R.string.zen_mode_interruptions_voice_header));
List<VoiceSelection> states = new ArrayList<VoiceSelection>();
if (!specified || enabled) {
states.add(new ModeSelection(this, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
R.string.zen_mode_option_voice_important_interruptions,
R.string.zen_mode_option_voice_important_synonyms));
states.add(new ModeSelection(this, Global.ZEN_MODE_ALARMS,
R.string.zen_mode_option_voice_alarms,
R.string.zen_mode_option_voice_alarms_synonyms));
states.add(new ModeSelection(this, Global.ZEN_MODE_NO_INTERRUPTIONS,
R.string.zen_mode_option_voice_no_interruptions,
R.string.zen_mode_option_voice_no_interruptions_synonyms));
}
if (!specified || !enabled) {
states.add(new ModeSelection(this, Global.ZEN_MODE_OFF,
R.string.zen_mode_option_voice_all_interruptions,
R.string.zen_mode_option_voice_all_interruptions_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);
} else {
setZenModeConfig(Global.ZEN_MODE_OFF, null);
if (intent.getBooleanExtra(EXTRA_DO_NOT_DISTURB_MODE_ENABLED, false)) {
if (minutes > 0) {
condition = ZenModeConfig.toTimeCondition(this, minutes, UserHandle.myUserId());
}
notifySuccess(getChangeSummary(mode, conditionSelection));
finish();
mode = Global.ZEN_MODE_ALARMS;
}
});
showFragment(fragment, "pick_mode_fragment");
}
setZenModeConfig(mode, condition);
notifySuccess(getChangeSummary(mode, minutes));
/**
* Start a voice interaction to ask for the zen mode duration.
*/
private void pickDuration(CharSequence label, final int mode) {
setTitle(label.toString());
setHeader(null);
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]));
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (audioManager != null) {
// Show the current Zen Mode setting.
audioManager.adjustStreamVolume(AudioManager.STREAM_NOTIFICATION,
AudioManager.ADJUST_SAME,
AudioManager.FLAG_SHOW_UI);
}
} else {
Log.v(TAG, "Missing extra android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_ENABLED");
}
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");
return true;
}
private void setZenModeConfig(int mode, Condition condition) {
@@ -149,12 +79,12 @@ public class ZenModeVoiceActivity extends VoiceSettingsActivity {
} 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) {
private CharSequence getChangeSummary(int mode, int minutes) {
int indefinite = -1;
int byMinute = -1;
int byHour = -1;
@@ -165,76 +95,26 @@ public class ZenModeVoiceActivity extends VoiceSettingsActivity {
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) {
if (minutes < 0 || mode == Global.ZEN_MODE_OFF) {
return getString(indefinite);
}
long time = System.currentTimeMillis() + duration.mMinutes * MINUTES_MS;
long time = System.currentTimeMillis() + minutes * 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);
if (minutes < 60) {
return res.getQuantityString(byMinute, minutes, minutes, formattedTime);
} else {
int hours = duration.mMinutes / 60;
int hours = minutes / 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;
}
}
}

View File

@@ -1,74 +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.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);
};
}

View File

@@ -1,63 +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.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;
}
};

View File

@@ -1,133 +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.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();
}
};

View File

@@ -16,8 +16,6 @@
package com.android.settings.utils;
import com.android.settings.R;
import android.app.Activity;
import android.app.Fragment;
import android.app.VoiceInteractor;
@@ -27,7 +25,6 @@ import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import android.util.Log;
/**
@@ -67,45 +64,17 @@ abstract public class VoiceSettingsActivity extends Activity {
* not null, then it will be read to the user.
*/
protected void notifySuccess(CharSequence prompt) {
if (prompt != null) {
Toast.makeText(this, prompt, Toast.LENGTH_LONG).show();
}
if (getVoiceInteractor() != null) {
getVoiceInteractor().submitRequest(new CompleteVoiceRequest(prompt, null));
}
}
protected void setHeader(String label) {
TextView header = (TextView) findViewById(R.id.voice_fragment_header);
if (header != null) {
if (label != null) {
header.setText(label);
header.setVisibility(View.VISIBLE);
} else {
header.setVisibility(View.GONE);
}
}
}
/**
* Indicates when the setting could not be changed.
*/
protected void notifyFailure(CharSequence prompt) {
if (prompt != null) {
Toast.makeText(this, prompt, Toast.LENGTH_LONG).show();
}
if (getVoiceInteractor() != null) {
getVoiceInteractor().submitRequest(new AbortVoiceRequest(prompt, null));
}
}
protected void showFragment(Fragment fragment, String tag) {
getFragmentManager()
.beginTransaction()
.replace(R.id.voice_fragment_root, fragment, tag)
.commit();
}
}