Merge "String changes for Location services Settings screen Bug: 5098817"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4118f32..2b0902e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -356,7 +356,6 @@
<action android:name="android.settings.INPUT_METHOD_SETTINGS" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
- <category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.inputmethod.InputMethodAndLanguageSettings" />
@@ -372,7 +371,6 @@
<action android:name="com.android.settings.VOICE_INPUT_OUTPUT_SETTINGS" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
- <category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.inputmethod.SpellCheckersSettings" />
@@ -392,7 +390,6 @@
<action android:name="android.settings.INPUT_METHOD_SUBTYPE_SETTINGS" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
- <category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
</activity>
@@ -412,7 +409,6 @@
<action android:name="com.android.settings.USER_DICTIONARY_INSERT" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
- <category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.UserDictionarySettings" />
@@ -467,7 +463,6 @@
<action android:name="com.android.settings.DOCK_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
- <category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.DockSettings" />
@@ -510,7 +505,7 @@
</activity>
<activity android:name="Settings$ManageApplicationsActivity"
- android:label="@string/manageapplications_settings_title"
+ android:label="@string/applications_settings"
android:clearTaskOnLaunch="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -561,7 +556,6 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
- <category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.applications.ManageApplications" />
@@ -578,7 +572,6 @@
<action android:name="android.intent.action.MANAGE_PACKAGE_STORAGE" />
<category android:name="android.intent.category.MONKEY" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
- <category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.applications.ManageApplications" />
@@ -614,7 +607,6 @@
<action android:name="android.credentials.UNLOCK" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
- <category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.SecuritySettings" />
@@ -662,7 +654,6 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
- <category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.DeviceAdminSettings" />
@@ -696,7 +687,7 @@
</activity>
<activity android:name="Settings$AccessibilitySettingsActivity"
- android:label="@string/accessibility_settings_title"
+ android:label="@string/accessibility_settings"
android:configChanges="orientation|keyboardHidden|screenSize"
android:clearTaskOnLaunch="true">
<intent-filter>
diff --git a/res/layout/data_usage_chart.xml b/res/layout/data_usage_chart.xml
index 3409d64..3ae8a03 100644
--- a/res/layout/data_usage_chart.xml
+++ b/res/layout/data_usage_chart.xml
@@ -56,6 +56,7 @@
android:layout_height="wrap_content"
settings:sweepDrawable="@drawable/data_sweep_warning"
settings:followAxis="vertical"
+ settings:neighborMargin="40dip"
settings:labelSize="60dip"
settings:labelTemplate="@string/data_usage_sweep_warning"
settings:labelColor="#f7931d" />
@@ -66,6 +67,7 @@
android:layout_height="wrap_content"
settings:sweepDrawable="@drawable/data_sweep_limit"
settings:followAxis="vertical"
+ settings:neighborMargin="40dip"
settings:labelSize="60dip"
settings:labelTemplate="@string/data_usage_sweep_limit"
settings:labelColor="#c01a2c" />
@@ -75,13 +77,15 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
settings:sweepDrawable="@drawable/data_sweep_left"
- settings:followAxis="horizontal" />
+ settings:followAxis="horizontal"
+ settings:neighborMargin="5dip" />
<com.android.settings.widget.ChartSweepView
android:id="@+id/sweep_right"
android:layout_width="wrap_content"
android:layout_height="match_parent"
settings:sweepDrawable="@drawable/data_sweep_right"
- settings:followAxis="horizontal" />
+ settings:followAxis="horizontal"
+ settings:neighborMargin="5dip" />
</com.android.settings.widget.DataUsageChartView>
diff --git a/res/layout/data_usage_header.xml b/res/layout/data_usage_header.xml
index 52f56c1..9602898 100644
--- a/res/layout/data_usage_header.xml
+++ b/res/layout/data_usage_header.xml
@@ -45,6 +45,18 @@
android:paddingBottom="8dip"
android:textAppearance="?android:attr/textAppearanceSmall" />
+ <TextView
+ android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:paddingTop="8dip"
+ android:paddingBottom="8dip"
+ android:text="@string/data_usage_empty"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
<include layout="@layout/data_usage_detail" />
</LinearLayout>
diff --git a/res/layout/preference_spellchecker.xml b/res/layout/preference_spellchecker.xml
new file mode 100644
index 0000000..e804f17
--- /dev/null
+++ b/res/layout/preference_spellchecker.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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:id="@+id/pref_all"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical">
+ <LinearLayout
+ android:id="@+id/pref_left_button"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_vertical"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground">
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="15dip"
+ android:layout_marginRight="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1">
+ <TextView
+ android:id="@+android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"/>
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignLeft="@android:id/title"
+ android:visibility="gone"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textSize="13sp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="4" />
+ </RelativeLayout>
+ </LinearLayout>
+ <View
+ android:layout_width="2dip"
+ android:layout_height="match_parent"
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"
+ android:background="@android:drawable/divider_horizontal_dark" />
+ <ImageView
+ android:id="@+id/pref_right_button"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:paddingLeft="15dip"
+ android:paddingRight="?android:attr/scrollbarSize"
+ android:src="@drawable/ic_sysbar_quicksettings"
+ android:contentDescription="@string/input_method_settings_button"
+ android:layout_gravity="center"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground" />
+</LinearLayout>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index a0a6c77..6c63d13 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -56,6 +56,7 @@
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
</attr>
+ <attr name="neighborMargin" format="dimension" />
<attr name="labelSize" format="dimension" />
<attr name="labelTemplate" format="reference" />
<attr name="labelColor" format="color" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c0adcf0..bdb86a6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -230,6 +230,8 @@
<string name="bluetooth_disconnect_title">Disconnect?</string>
<!-- Bluetooth settings. Message for disconnecting from all profiles of a bluetooth device. [CHAR LIMIT=NONE] -->
<string name="bluetooth_disconnect_all_profiles">This will end your connection with:<br><b><xliff:g id="device_name">%1$s</xliff:g></b></string>
+ <!-- Bluetooth settings. Message for disconnecting from all profiles of a bluetooth device. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_disconnect_blank">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> will be disconnected."</string>
<!-- Bluetooth settings. Message when connected to a device -->
<string name="bluetooth_connected">Connected</string>
<!-- Bluetooth settings. Message when a device is disconnected -->
@@ -539,7 +541,7 @@
<!-- Title of the Settings activity shown in the Launcher. [CHAR LIMIT=20] -->
<string name="settings_label_launcher">Settings</string>
<!-- Label for option to select a settings panel as a shortcut -->
- <string name="settings_shortcut">Select settings shortcut</string>
+ <string name="settings_shortcut">Settings shortcut</string>
<!-- Wireless controls settings screen, setting check box label -->
<string name="airplane_mode">Airplane mode</string>
<!-- Main Settings screen settings title for things like airplane mode, tethering, NFC, VPN. This will take you to another screen with those settings. -->
@@ -1392,12 +1394,9 @@
<string name="config_list_label" translatable="false">Configured Networks</string>
<!-- Sound and alerts settings -->
- <!-- Main Settings screen setting option name to go into the sound settings screen -->
- <string name="sound_settings_title">Sound</string>
- <!-- Main Settings screen setting option name to go into the display settings screen -->
- <string name="display_settings_title">Display</string>
+ <skip/>
<!-- Sound settings screen heading -->
- <string name="sound_settings">Sound settings</string>
+ <string name="sound_settings">Sound</string>
<!-- Sound settings screen, setting option name checkbox -->
<string name="silent_mode_title">Silent mode</string>
<!-- Sound settings screen, setting option summary text when going into silent mode. Media and alarms sounds WILL NOT be silenced in silent mode. -->
@@ -1521,9 +1520,9 @@
<!-- Main Settings screen, setting option summary to go into search settings -->
<string name="search_settings_summary">Manage search settings and history</string>
- <!-- Display settings -->
+ <!-- Display settings --><skip/>
<!-- Sound & display settings screen, section header for settings related to display -->
- <string name="display_settings">Screen settings</string>
+ <string name="display_settings">Display</string>
<!-- Sound & display settings screen, accelerometer-based rotation check box label -->
<string name="accelerometer_title">Auto-rotate screen</string>
<!-- Sound & display settings screen, accelerometer-based rotation summary text when check box is selected -->
@@ -1564,8 +1563,8 @@
<string name="automatic_brightness">Automatic brightness</string>
<!-- [CHAR LIMIT=30] Sound & display settings screen, setting option name to change font size -->
<string name="title_font_size">Font size</string>
- <!-- [CHAR LIMIT=40] Sound & display settings screen, setting option summary to change font size -->
- <string name="summary_font_size">Overall size of fonts</string>
+ <!-- [CHAR LIMIT=30] Sound & display settings screen, setting option summary displaying the currently selected font size -->
+ <string name="summary_font_size">Current font size: %1$s</string>
<!-- [CHAR LIMIT=40] Sound & display settings screen, title of dialog for picking font size -->
<string name="dialog_title_font_size">Select font size</string>
@@ -1780,23 +1779,21 @@
<string name="sd_ejecting_summary">Unmount in progress</string>
<!-- Storage setting. Menu option for USB transfer settings [CHAR LIMIT=30]-->
- <string name="storage_menu_usb">USB transfer settings</string>
+ <string name="storage_menu_usb">USB computer connection</string>
<!-- Storage setting. Title for USB transfer settings [CHAR LIMIT=30]-->
- <string name="storage_title_usb">USB transfer settings</string>
+ <string name="storage_title_usb">USB computer connection</string>
<!-- Storage setting. USB connection category [CHAR LIMIT=30]-->
<string name="usb_connection_category">Connect as</string>
- <!-- Storage setting. Label for MTP setting [CHAR LIMIT=30]-->
- <string name="usb_label_mtp">Media device (MTP)</string>
- <!-- Storage setting. Label for PTP setting [CHAR LIMIT=30]-->
- <string name="usb_label_ptp">Camera (PTP)</string>
+ <!-- Storage setting. Title for MTP checkbox [CHAR LIMIT=30]-->
+ <string name="usb_mtp_title">Media device (MTP)</string>
+ <!-- Storage setting. Summary for MTP checkbox [CHAR LIMIT=NONE]-->
+ <string name="usb_mtp_summary">Lets you transfer media files on Windows, or using Android File Transfer on Mac (see www.android.com/filetransfer)</string>
+ <!-- Storage setting. Title for PTP checkbox [CHAR LIMIT=30]-->
+ <string name="usb_ptp_title">Camera (PTP)</string>
<!-- Storage setting. Label for installer CD [CHAR LIMIT=30]-->
- <string name="usb_label_installer_cd_done">Done installing Android File Transfer application for Mac</string>
- <!-- Installer CD dialog title [CHAR LIMIT=30] -->
- <string name="dlg_installer_cd_title">Android File Transfer app for Mac</string>
- <!-- Installer CD dialog text [CHAR LIMIT=NONE] -->
- <string name="dlg_installer_cd_text">Step 1:\nOn your Mac, double-click androidfiletransfer.msg\n\nStep 2:\nIn the Installer window, drag Android File Transfer to Applications.</string>
- <!-- Installer CD dialog OK button text [CHAR LIMIT=NONE] -->
- <string name="dlg_installer_cd_ok">Done following these steps</string>
+ <string name="usb_ptp_summary">Lets you transfer photos using camera software, and transfer any files on computers that don\'t support MTP</string>
+ <!-- Storage setting. Summary for PTP checkbox [CHAR LIMIT=NONE]-->
+ <string name="usb_label_installer_cd">"Install file-transfer tools"</string>
<!-- Phone info screen, section titles: -->
<string name="battery_status_title">Battery status</string>
@@ -2660,8 +2657,6 @@
<!-- Settings title in main settings screen for accessibility settings -->
<string name="accessibility_settings">Accessibility</string>
- <!-- Settings title for accessibility settings screen -->
- <string name="accessibility_settings_title">Accessibility settings</string>
<!-- Title for the accessibility preference category of accessibility services. [CHAR LIMIT=25] -->
<string name="accessibility_services_title">Services</string>
@@ -2675,9 +2670,8 @@
<!-- Title for accessibility preference to enable touch exploration mode. [CHAR LIMIT=35] -->
<string name="accessibility_touch_exploration_title">Explore by touch</string>
<!-- Summary for accessibility of the touch exploration mode. [CHAR LIMIT=NONE] -->
- <string name="accessibility_touch_exploration_summary" >Allows exploring screen content and interacting with the device.\n\n
- Touch the screen to receive feedback of the content under your finger.\n\n Tap on the last explored location to activate.\n\n
- Use two fingers to drag. </string>
+ <string name="accessibility_touch_exploration_summary" >When Explore by Touch is turned on,
+ you can hear or see descriptions of what\'s under your finger.\n\n This feature is for low-vision users.</string>
<!-- Title for accessibility preference to choose long-press delay i.e. timeout before it is detected. [CHAR LIMIT=35] -->
<string name="accessibility_long_press_timeout_title">Touch & hold delay</string>
<!-- Title for accessibility preference to install accessibility scripts from Google. [CHAR LIMIT=35] -->
@@ -2704,31 +2698,37 @@
<string name="accessibility_script_injection_button_disallow">Don\'t Allow</string>
<!-- Warning message about security implications of enabling an accessibility service,
- displayed as a dialog message when the user selects to enable an accessibility service. [CHAR LIMIT=NONE] -->
- <string name="accessibility_service_security_warning">This accessibility service may be able to collect
- all the text you type, including personal data credit card numbers except passwords.
- It may also log your user interface interactions. It comes from the application
- <xliff:g id="accessibility_service_name">%1$s</xliff:g>. Use this accessibility service?</string>
- <!-- Warning about disabling accessibility displayed as a dialog message when the user
+ displayed as a dialog message when the user selects to enable an accessibility service (tablet). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_service_security_warning">
+ <xliff:g id="accessibility_service_name">%1$s</xliff:g> can
+ collect all of the text you type, except passwords. This includes personal data such as credit card
+ numbers. It can also collect data about your interactions with the device.</string>
+ <!-- Title for a warning about disabling accessibility displayed as a dialog message when the user
+ selects to disable accessibility. This avoids accidental disabling. [CHAR LIMIT=30] -->
+ <string name="accessibility_disable_warning_title">Turn accessibility off?</string>
+ <!-- Summary for a warning about disabling accessibility displayed as a dialog message when the user
selects to disable accessibility. This avoids accidental disabling. [CHAR LIMIT=NONE] -->
- <string name="accessibility_service_disable_warning">Disable accessibility?</string>
+ <string name="accessibility_disable_warning_summary">Touching OK will stop spoken
+ descriptions and all other accessibility features you\'ve been using.</string>
<!-- Title for the prompt that lets users know that they have no accessibility related apps
installed and that they can install TalkBack from Market. [CHAR LIMIT=50] -->
- <string name="accessibility_service_no_apps_title">No accessibility related applications found
+ <string name="accessibility_service_no_apps_title">No accessibility applications
</string>
<!-- Message for the prompt that lets users know that they have no accessibility related apps
installed and that they can install TalkBack from Market. [CHAR LIMIT=NONE] -->
- <string name="accessibility_service_no_apps_message">You do not have any accessibility-related
- applications installed.\n\nYou can download a screen reader for your device from Android
- Market.\n\nClick "OK" to install the screen reader.</string>
+ <string name="accessibility_service_no_apps_message">You don\'t have accessibility
+ applications installed. Do you want to download a screen reader from the Android Market?</string>
<!-- Warning message about security implications of downloading accessibility scripts,
displayed as a dialog message when the user selects to enable script downloading. [CHAR LIMIT=NONE] -->
- <string name="accessibility_script_injection_security_warning">Some applications can ask Google
- to download scripts to your device that make their content more accessible. Are you sure you
- want to allow Google to install accessibility scripts on your device?</string>
+ <string name="accessibility_script_injection_security_warning">Do you want applications to install
+ scripts from Google that will make their content more accessible?</string>
<!-- Warning message that the interaction model changes on enabling touch exploration. [CHAR LIMIT=NONE] -->
<string name="accessibility_touch_exploration_warning">Enabling explore by touch
- changes the interation model. Enable explore by touch?</string>
+ changes how the devices respons to touch. Enable explore by touch?</string>
+ <!-- Default description for an accessiiblity serivice if the latter doesn't provide one. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_service_default_description">This accessibility service has no
+ description.\n\nAccessibility services provide various types of feedback when you interact
+ with the device. </string>
<!-- App Fuel Gauge strings -->
<skip />
@@ -3407,6 +3407,8 @@
<string name="data_usage_change_cycle">Change cycle\u2026</string>
<!-- Body of dialog prompting user to change numerical day of month that data usage cycle should reset. [CHAR LIMIT=64] -->
<string name="data_usage_pick_cycle_day">Day of month to reset data usage cycle:</string>
+ <!-- Label shown when no applications used data during selected time period. [CHAR LIMIT=48] -->
+ <string name="data_usage_empty">No applications used data during this period.</string>
<!-- Checkbox label that will disable mobile network data connection when user-defined limit is reached. [CHAR LIMIT=32] -->
<string name="data_usage_disable_mobile_limit">Disable mobile data at limit</string>
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index 78a857b..4dbca6d 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -30,12 +30,12 @@
<CheckBoxPreference
android:key="toggle_large_text_preference"
android:title="@string/accessibility_toggle_large_text_title"
- android:persistent="false"/>
+ android:persistent="true"/>
<CheckBoxPreference
android:key="toggle_power_button_ends_call_preference"
android:title="@string/accessibility_power_button_ends_call_title"
- android:persistent="false">
+ android:persistent="true">
</CheckBoxPreference>
<PreferenceScreen
@@ -55,10 +55,15 @@
android:entryValues="@array/long_press_timeout_selector_values"
android:persistent="true" />
- <Preference
+ <com.android.settings.AccessibilityEnableScriptInjectionPreference
android:key="toggle_script_injection_preference"
android:title="@string/accessibility_script_injection_title"
- android:persistent="false" />
+ android:dialogTitle="@android:string/dialog_alert_title"
+ android:dialogIcon="@android:drawable/ic_dialog_alert"
+ android:dialogMessage="@string/accessibility_script_injection_security_warning"
+ android:positiveButtonText="@string/accessibility_script_injection_button_allow"
+ android:negativeButtonText="@string/accessibility_script_injection_button_disallow"
+ android:persistent="true" />
</PreferenceCategory>
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index c13a107..a399828 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -40,10 +40,12 @@
android:entries="@array/screen_timeout_entries"
android:entryValues="@array/screen_timeout_values" />
+ <!--
<PreferenceScreen
android:title="@string/dream_settings_title"
android:summary="@string/dream_settings_summary"
android:fragment="com.android.settings.DreamSettings" />
+ -->
<ListPreference
android:key="font_size"
diff --git a/res/xml/settings_headers.xml b/res/xml/settings_headers.xml
index cd6191f..40e1880 100644
--- a/res/xml/settings_headers.xml
+++ b/res/xml/settings_headers.xml
@@ -66,14 +66,14 @@
android:id="@+id/sound_settings"
android:icon="@drawable/ic_settings_sound"
android:fragment="com.android.settings.SoundSettings"
- android:title="@string/sound_settings_title" />
+ android:title="@string/sound_settings" />
<!-- Display -->
<header
android:id="@+id/display_settings"
android:icon="@drawable/ic_settings_display"
android:fragment="com.android.settings.DisplaySettings"
- android:title="@string/display_settings_title" />
+ android:title="@string/display_settings" />
<!-- Storage -->
<header
diff --git a/res/xml/usb_settings.xml b/res/xml/usb_settings.xml
index 28ef99b..4d6ccc9 100644
--- a/res/xml/usb_settings.xml
+++ b/res/xml/usb_settings.xml
@@ -22,12 +22,14 @@
<CheckBoxPreference
android:key="usb_mtp"
- android:title="@string/usb_label_mtp"
+ android:title="@string/usb_mtp_title"
+ android:summary="@string/usb_mtp_summary"
/>
<CheckBoxPreference
android:key="usb_ptp"
- android:title="@string/usb_label_ptp"
+ android:title="@string/usb_ptp_title"
+ android:summary="@string/usb_ptp_summary"
/>
</PreferenceScreen>
diff --git a/src/com/android/settings/AccessibilityEnableScriptInjectionPreference.java b/src/com/android/settings/AccessibilityEnableScriptInjectionPreference.java
new file mode 100644
index 0000000..a9338ed
--- /dev/null
+++ b/src/com/android/settings/AccessibilityEnableScriptInjectionPreference.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011 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;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.preference.DialogPreference;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+
+/**
+ * Preference for enabling accessibility script injection. It displays a warning
+ * dialog before enabling the preference.
+ */
+public class AccessibilityEnableScriptInjectionPreference extends DialogPreference {
+
+ private boolean mInjectionAllowed;
+ private boolean mSendClickAccessibilityEvent;
+
+ public AccessibilityEnableScriptInjectionPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ updateSummary();
+ }
+
+ public void setInjectionAllowed(boolean injectionAllowed) {
+ if (mInjectionAllowed != injectionAllowed) {
+ mInjectionAllowed = injectionAllowed;
+ persistBoolean(injectionAllowed);
+ updateSummary();
+ }
+ }
+
+ public boolean isInjectionAllowed() {
+ return mInjectionAllowed;
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+ View summaryView = view.findViewById(com.android.internal.R.id.summary);
+ sendAccessibilityEvent(summaryView);
+ }
+
+ private void sendAccessibilityEvent(View view) {
+ // Since the view is still not attached we create, populate,
+ // and send the event directly since we do not know when it
+ // will be attached and posting commands is not as clean.
+ AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getContext());
+ if (mSendClickAccessibilityEvent && accessibilityManager.isEnabled()) {
+ AccessibilityEvent event = AccessibilityEvent.obtain();
+ event.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED);
+ view.onInitializeAccessibilityEvent(event);
+ view.dispatchPopulateAccessibilityEvent(event);
+ accessibilityManager.sendAccessibilityEvent(event);
+ }
+ mSendClickAccessibilityEvent = false;
+ }
+
+ @Override
+ protected void onClick() {
+ if (isInjectionAllowed()) {
+ setInjectionAllowed(false);
+ // Update the system setting only upon user action.
+ setSystemSetting(false);
+ mSendClickAccessibilityEvent = true;
+ } else {
+ super.onClick();
+ mSendClickAccessibilityEvent = false;
+ }
+ }
+
+ @Override
+ protected Object onGetDefaultValue(TypedArray a, int index) {
+ return a.getBoolean(index, false);
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ setInjectionAllowed(restoreValue
+ ? getPersistedBoolean(mInjectionAllowed)
+ : (Boolean) defaultValue);
+ }
+
+ @Override
+ protected void onDialogClosed(boolean result) {
+ setInjectionAllowed(result);
+ if (result) {
+ // Update the system setting only upon user action.
+ setSystemSetting(true);
+ }
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ return superState;
+ }
+ SavedState myState = new SavedState(superState);
+ myState.mInjectionAllowed = mInjectionAllowed;
+ return myState;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (state == null || !state.getClass().equals(SavedState.class)) {
+ super.onRestoreInstanceState(state);
+ return;
+ }
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ setInjectionAllowed(myState.mInjectionAllowed);
+ }
+
+ private void updateSummary() {
+ setSummary(mInjectionAllowed
+ ? getContext().getString(R.string.accessibility_script_injection_allowed)
+ : getContext().getString(R.string.accessibility_script_injection_disallowed));
+ }
+
+ private void setSystemSetting(boolean enabled) {
+ Settings.Secure.putInt(getContext().getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, enabled ? 1 : 0);
+ }
+
+ private static class SavedState extends BaseSavedState {
+ private boolean mInjectionAllowed;
+
+ public SavedState(Parcel source) {
+ super(source);
+ mInjectionAllowed = (source.readInt() == 1);
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ super.writeToParcel(parcel, flags);
+ parcel.writeInt(mInjectionAllowed ? 1 : 0);
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ @SuppressWarnings("all")
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+}
diff --git a/src/com/android/settings/AccessibilitySettings.java b/src/com/android/settings/AccessibilitySettings.java
index beef902..cb56e63 100644
--- a/src/com/android/settings/AccessibilitySettings.java
+++ b/src/com/android/settings/AccessibilitySettings.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.net.Uri;
@@ -37,6 +38,7 @@
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
+import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.provider.Settings;
@@ -49,6 +51,7 @@
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Switch;
import android.widget.TextView;
@@ -73,6 +76,8 @@
private static final float LARGE_FONT_SCALE = 1.3f;
+ private static final String SYSTEM_PROPERTY_MARKET_URL = "ro.screenreader.market";
+
// Timeout before we update the services if packages are added/removed since
// the AccessibilityManagerService has to do that processing first to generate
// the AccessibilityServiceInfo we need for proper presentation.
@@ -80,8 +85,15 @@
private static final char ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':';
+ private static final String KEY_ACCESSIBILITY_TUTORIAL_LAUNCHED_ONCE =
+ "key_accessibility_tutorial_launched_once";
+
+ private static final String KEY_INSTALL_ACCESSIBILITY_SERVICE_OFFERED_ONCE =
+ "key_install_accessibility_service_offered_once";
+
// Preference categories
private static final String SERVICES_CATEGORY = "services_category";
+ private static final String SYSTEM_CATEGORY = "system_category";
// Preferences
private static final String TOGGLE_LARGE_TEXT_PREFERENCE = "toggle_large_text_preference";
@@ -95,18 +107,17 @@
"toggle_script_injection_preference";
// Extras passed to sub-fragments.
- static final String EXTRA_PREFERENCE_KEY = "preference_key";
- static final String EXTRA_CHECKED = "checked";
- static final String EXTRA_TITLE = "title";
- static final String EXTRA_SUMMARY = "summary";
- static final String EXTRA_WARNING_MESSAGE = "warning_message";
- static final String EXTRA_SETTINGS_TITLE = "settings_title";
- static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
+ private static final String EXTRA_PREFERENCE_KEY = "preference_key";
+ private static final String EXTRA_CHECKED = "checked";
+ private static final String EXTRA_TITLE = "title";
+ private static final String EXTRA_SUMMARY = "summary";
+ private static final String EXTRA_WARNING_MESSAGE = "warning_message";
+ private static final String EXTRA_SETTINGS_TITLE = "settings_title";
+ private static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
// Dialog IDs.
private static final int DIALOG_ID_DISABLE_ACCESSIBILITY = 1;
- private static final int DIALOG_ID_ENABLE_SCRIPT_INJECTION = 2;
- private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 3;
+ private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 2;
// Auxiliary members.
private final SimpleStringSplitter mStringColonSplitter =
@@ -123,7 +134,7 @@
@Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
- updateServicesPreferences();
+ updateServicesPreferences(mToggleAccessibilitySwitch.isChecked());
}
};
@@ -131,103 +142,96 @@
private ToggleSwitch mToggleAccessibilitySwitch;
private PreferenceCategory mServicesCategory;
+ private PreferenceCategory mSystemsCategory;
private CheckBoxPreference mToggleLargeTextPreference;
private CheckBoxPreference mTogglePowerButtonEndsCallPreference;
- private Preference mTouchExplorationEnabledPreference;
+ private Preference mToggleTouchExplorationPreference;
private ListPreference mSelectLongPressTimeoutPreference;
- private Preference mToggleScriptInjectionPreference;
+ private AccessibilityEnableScriptInjectionPreference mToggleScriptInjectionPreference;
+
+ private int mLongPressTimeoutDefault;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.accessibility_settings);
- installToggleAccessibilitySwitch();
- findPreferences();
+ initializeAllPreferences();
}
@Override
public void onResume() {
super.onResume();
- updateServicesPreferences();
- updateSystemPreferences();
- updatePreferencesForAccessibilityState();
+ final boolean accessibilityEnabled = mToggleAccessibilitySwitch.isChecked();
+ updateAllPreferences(accessibilityEnabled);
+ if (accessibilityEnabled) {
+ offerInstallAccessibilitySerivceOnce();
+ }
mSettingsPackageMonitor.register(getActivity(), false);
}
@Override
public void onPause() {
- super.onPause();
mSettingsPackageMonitor.unregister();
+ super.onPause();
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ addToggleAccessibilitySwitch();
+ super.onViewCreated(view, savedInstanceState);
+ }
+
+ @Override
+ public void onDestroyView() {
+ removeToggleAccessibilitySwitch();
+ super.onDestroyView();
}
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == mSelectLongPressTimeoutPreference) {
- final int intValue = Integer.parseInt((String) newValue);
+ String stringValue = (String) newValue;
Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.LONG_PRESS_TIMEOUT, intValue);
+ Settings.Secure.LONG_PRESS_TIMEOUT, Integer.parseInt(stringValue));
mSelectLongPressTimeoutPreference.setSummary(
- mLongPressTimeoutValuetoTitleMap.get(String.valueOf(intValue)));
+ mLongPressTimeoutValuetoTitleMap.get(stringValue));
return true;
}
return false;
}
- private void updatePreferencesForAccessibilityState() {
- final boolean accessibilityEnabled = (Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1);
- mServicesCategory.setEnabled(accessibilityEnabled);
- mTouchExplorationEnabledPreference.setEnabled(accessibilityEnabled);
- mToggleScriptInjectionPreference.setEnabled(accessibilityEnabled);
- }
-
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
final String key = preference.getKey();
if (mToggleLargeTextPreference == preference) {
- handleToggleLargeTextPreference((CheckBoxPreference) preference);
+ handleToggleLargeTextPreferenceClick();
return true;
} else if (mTogglePowerButtonEndsCallPreference == preference) {
- handleTogglePowerButtonEndsCallPreference((CheckBoxPreference) preference);
- return true;
- } else if (mToggleScriptInjectionPreference == preference) {
- handleToggleAccessibilityScriptInjectionPreference(preference);
+ handleTogglePowerButtonEndsCallPreferenceClick();
return true;
}
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
- private void handleTogglePowerButtonEndsCallPreference(CheckBoxPreference preference) {
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
- (preference.isChecked() ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP
- : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF));
- }
-
- private void handleToggleLargeTextPreference(CheckBoxPreference preference) {
+ private void handleToggleLargeTextPreferenceClick() {
try {
- mCurConfig.fontScale = preference.isChecked() ? LARGE_FONT_SCALE : 1;
+ mCurConfig.fontScale = mToggleLargeTextPreference.isChecked() ? LARGE_FONT_SCALE : 1;
ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig);
- } catch (RemoteException e) {
+ } catch (RemoteException re) {
/* ignore */
}
}
- private void handleToggleAccessibilityScriptInjectionPreference(Preference preference) {
- String allowed = getString(R.string.accessibility_script_injection_disallowed);
- if (preference.getSummary().equals(allowed)) {
- // set right enabled state since the user may press back.
- showDialog(DIALOG_ID_ENABLE_SCRIPT_INJECTION);
- } else {
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0);
- mToggleScriptInjectionPreference.setSummary(
- getString(R.string.accessibility_script_injection_disallowed));
- }
+ private void handleTogglePowerButtonEndsCallPreferenceClick() {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+ (mTogglePowerButtonEndsCallPreference.isChecked()
+ ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP
+ : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF));
}
- private void installToggleAccessibilitySwitch() {
- mToggleAccessibilitySwitch = createActionBarToggleSwitch(getActivity());
+ private void addToggleAccessibilitySwitch() {
+ mToggleAccessibilitySwitch = createAndAddActionBarToggleSwitch(getActivity());
final boolean checked = (Settings.Secure.getInt(getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1);
mToggleAccessibilitySwitch.setChecked(checked);
@@ -236,34 +240,126 @@
@Override
public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
if (!checked) {
- toggleSwitch.setCheckedNoBeforeCheckedChangeListener(true);
+ toggleSwitch.setCheckedInternal(true);
showDialog(DIALOG_ID_DISABLE_ACCESSIBILITY);
return true;
}
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 1);
- updatePreferencesForAccessibilityState();
+ updateAllPreferences(true);
+ offerInstallAccessibilitySerivceOnce();
return false;
}
});
}
- private void findPreferences() {
- mServicesCategory = (PreferenceCategory) findPreference(SERVICES_CATEGORY);
-
- mToggleLargeTextPreference = (CheckBoxPreference) findPreference(
- TOGGLE_LARGE_TEXT_PREFERENCE);
- mTogglePowerButtonEndsCallPreference = (CheckBoxPreference) findPreference(
- TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE);
- mTouchExplorationEnabledPreference = findPreference(TOGGLE_TOUCH_EXPLORATION_PREFERENCE);
- mSelectLongPressTimeoutPreference = (ListPreference) findPreference(
- SELECT_LONG_PRESS_TIMEOUT_PREFERENCE);
- mSelectLongPressTimeoutPreference.setOnPreferenceChangeListener(this);
- mToggleScriptInjectionPreference = findPreference(TOGGLE_SCRIPT_INJECTION_PREFERENCE);
- mToggleScriptInjectionPreference.setOnPreferenceChangeListener(this);
+ public void removeToggleAccessibilitySwitch() {
+ getActivity().getActionBar().setCustomView(null);
}
- private void updateServicesPreferences() {
+ private void initializeAllPreferences() {
+ // The basic logic here is if accessibility is not enabled all accessibility
+ // settings will have no effect but still their selected state should be kept
+ // unchanged, so the user can see what settings will be enabled when turning
+ // on accessibility.
+
+ final boolean accessibilityEnabled = (Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1);
+
+ mServicesCategory = (PreferenceCategory) findPreference(SERVICES_CATEGORY);
+ mSystemsCategory = (PreferenceCategory) findPreference(SYSTEM_CATEGORY);
+
+ // Large text.
+ mToggleLargeTextPreference =
+ (CheckBoxPreference) findPreference(TOGGLE_LARGE_TEXT_PREFERENCE);
+ if (accessibilityEnabled) {
+ try {
+ mCurConfig.updateFrom(ActivityManagerNative.getDefault().getConfiguration());
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ mToggleLargeTextPreference.setChecked(mCurConfig.fontScale == LARGE_FONT_SCALE);
+ }
+
+ // Power button ends calls.
+ mTogglePowerButtonEndsCallPreference =
+ (CheckBoxPreference) findPreference(TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE);
+ if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
+ && Utils.isVoiceCapable(getActivity())) {
+ if (accessibilityEnabled) {
+ final int incallPowerBehavior = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+ Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
+ final boolean powerButtonEndsCall =
+ (incallPowerBehavior == Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP);
+ mTogglePowerButtonEndsCallPreference.setChecked(powerButtonEndsCall);
+ }
+ } else {
+ mSystemsCategory.removePreference(mTogglePowerButtonEndsCallPreference);
+ }
+
+ // Touch exploration enabled.
+ mToggleTouchExplorationPreference = findPreference(TOGGLE_TOUCH_EXPLORATION_PREFERENCE);
+ final boolean touchExplorationEnabled = (Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1);
+ if (touchExplorationEnabled) {
+ mToggleTouchExplorationPreference.setSummary(
+ getString(R.string.accessibility_service_state_on));
+ mToggleTouchExplorationPreference.getExtras().putBoolean(EXTRA_CHECKED, true);
+ } else {
+ mToggleTouchExplorationPreference.setSummary(
+ getString(R.string.accessibility_service_state_off));
+ mToggleTouchExplorationPreference.getExtras().putBoolean(EXTRA_CHECKED, false);
+ }
+
+ // Long press timeout.
+ mSelectLongPressTimeoutPreference =
+ (ListPreference) findPreference(SELECT_LONG_PRESS_TIMEOUT_PREFERENCE);
+ mSelectLongPressTimeoutPreference.setOnPreferenceChangeListener(this);
+ if (mLongPressTimeoutValuetoTitleMap.size() == 0) {
+ String[] timeoutValues = getResources().getStringArray(
+ R.array.long_press_timeout_selector_values);
+ mLongPressTimeoutDefault = Integer.parseInt(timeoutValues[0]);
+ String[] timeoutTitles = getResources().getStringArray(
+ R.array.long_press_timeout_selector_titles);
+ final int timeoutValueCount = timeoutValues.length;
+ for (int i = 0; i < timeoutValueCount; i++) {
+ mLongPressTimeoutValuetoTitleMap.put(timeoutValues[i], timeoutTitles[i]);
+ }
+ }
+ if (accessibilityEnabled) {
+ final int longPressTimeout = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.LONG_PRESS_TIMEOUT, mLongPressTimeoutDefault);
+ String value = String.valueOf(longPressTimeout);
+ mSelectLongPressTimeoutPreference.setValue(value);
+ mSelectLongPressTimeoutPreference.setSummary(
+ mLongPressTimeoutValuetoTitleMap.get(value));
+ } else {
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.LONG_PRESS_TIMEOUT,
+ mLongPressTimeoutDefault);
+ }
+
+ // Script injection.
+ mToggleScriptInjectionPreference = (AccessibilityEnableScriptInjectionPreference)
+ findPreference(TOGGLE_SCRIPT_INJECTION_PREFERENCE);
+ if (accessibilityEnabled) {
+ final boolean scriptInjectionAllowed = (Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1);
+ mToggleScriptInjectionPreference.setInjectionAllowed(scriptInjectionAllowed);
+ }
+ }
+
+ private void updateAllPreferences(boolean accessibilityEnabled) {
+ updateServicesPreferences(accessibilityEnabled);
+ updateSystemPreferences(accessibilityEnabled);
+ }
+
+ private void updateServicesPreferences(boolean accessibilityEnabled) {
+ // Since services category is auto generated we have to do a pass
+ // to generate it since services can come and go and then based on
+ // the global accessibility state to decided whether it is enabled.
+
+ // Generate.
mServicesCategory.removeAll();
AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getActivity());
@@ -271,17 +367,6 @@
List<AccessibilityServiceInfo> installedServices =
accessibilityManager.getInstalledAccessibilityServiceList();
- if (installedServices.isEmpty() && accessibilityManager.isEnabled()) {
- // no service and accessibility is enabled => disable
- Settings.Secure.putInt(getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED, 0);
- mToggleAccessibilitySwitch.setChecked(false);
- mToggleAccessibilitySwitch.setEnabled(false);
- // Notify user that they do not have any accessibility
- // services installed and direct them to Market to get TalkBack.
- showDialog(DIALOG_ID_NO_ACCESSIBILITY_SERVICES);
- return;
- }
-
Set<ComponentName> enabledComponentNames = new HashSet<ComponentName>();
String settingValue = Settings.Secure.getString(getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
@@ -317,12 +402,19 @@
preference.setOrder(i);
preference.setFragment(ToggleAccessibilityServiceFragment.class.getName());
+ preference.setPersistent(true);
Bundle extras = preference.getExtras();
extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey());
extras.putBoolean(EXTRA_CHECKED, enabled);
extras.putString(EXTRA_TITLE, title);
- extras.putString(EXTRA_SUMMARY, info.getDescription());
+
+ String description = info.getDescription();
+ if (TextUtils.isEmpty(description)) {
+ description = getString(R.string.accessibility_service_default_description);
+ }
+ extras.putString(EXTRA_SUMMARY, description);
+
extras.putString(EXTRA_WARNING_MESSAGE, getString(
R.string.accessibility_service_security_warning,
info.getResolveInfo().loadLabel(getPackageManager())));
@@ -338,69 +430,100 @@
mServicesCategory.addPreference(preference);
}
+
+ // Update enabled state.
+ mServicesCategory.setEnabled(accessibilityEnabled);
}
- public void updateSystemPreferences() {
+ private void updateSystemPreferences(boolean accessibilityEnabled) {
+ // The basic logic here is if accessibility is not enabled all accessibility
+ // settings will have no effect but still their selected state should be kept
+ // unchanged, so the user can see what settings will be enabled when turning
+ // on accessibility.
+
// Large text.
+ mToggleLargeTextPreference.setEnabled(accessibilityEnabled);
+ if (accessibilityEnabled) {
+ mCurConfig.fontScale =
+ mToggleLargeTextPreference.isChecked() ? LARGE_FONT_SCALE : 1;
+ } else {
+ mCurConfig.fontScale = 1;
+ }
try {
- mCurConfig.updateFrom(ActivityManagerNative.getDefault().getConfiguration());
+ ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig);
} catch (RemoteException re) {
/* ignore */
}
- mToggleLargeTextPreference.setChecked(Float.compare(mCurConfig.fontScale,
- LARGE_FONT_SCALE) == 0);
- // Power button ends call.
- if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
- && Utils.isVoiceCapable(getActivity())) {
- final int incallPowerBehavior = Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
- Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
- final boolean powerButtonEndsCall =
- (incallPowerBehavior == Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP);
- mTogglePowerButtonEndsCallPreference.setChecked(powerButtonEndsCall);
- } else {
- getPreferenceScreen().removePreference(mTogglePowerButtonEndsCallPreference);
+ // Power button ends calls.
+ if (mTogglePowerButtonEndsCallPreference != null) {
+ mTogglePowerButtonEndsCallPreference.setEnabled(accessibilityEnabled);
+ final int powerButtonEndsCall;
+ if (accessibilityEnabled) {
+ powerButtonEndsCall = mTogglePowerButtonEndsCallPreference.isChecked()
+ ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP
+ : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF;
+ } else {
+ powerButtonEndsCall = Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF;
+ }
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+ powerButtonEndsCall);
}
// Touch exploration enabled.
+ mToggleTouchExplorationPreference.setEnabled(accessibilityEnabled);
final boolean touchExplorationEnabled = (Settings.Secure.getInt(getContentResolver(),
Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1);
if (touchExplorationEnabled) {
- mTouchExplorationEnabledPreference.setSummary(
+ mToggleTouchExplorationPreference.setSummary(
getString(R.string.accessibility_service_state_on));
- mTouchExplorationEnabledPreference.getExtras().putBoolean(EXTRA_CHECKED, true);
+ mToggleTouchExplorationPreference.getExtras().putBoolean(EXTRA_CHECKED, true);
} else {
- mTouchExplorationEnabledPreference.setSummary(
+ mToggleTouchExplorationPreference.setSummary(
getString(R.string.accessibility_service_state_off));
- mTouchExplorationEnabledPreference.getExtras().putBoolean(EXTRA_CHECKED, false);
+ mToggleTouchExplorationPreference.getExtras().putBoolean(EXTRA_CHECKED, false);
}
// Long press timeout.
- if (mLongPressTimeoutValuetoTitleMap.isEmpty()) {
- String[] timeoutValues = getResources().getStringArray(
- R.array.long_press_timeout_selector_values);
- String[] timeoutTitles = getResources().getStringArray(
- R.array.long_press_timeout_selector_titles);
- final int timeoutValueCount = timeoutValues.length;
- for (int i = 0;i < timeoutValueCount; i++) {
- mLongPressTimeoutValuetoTitleMap.put(timeoutValues[i], timeoutTitles[i]);
- }
+ mSelectLongPressTimeoutPreference.setEnabled(accessibilityEnabled);
+ final int longPressTimeout;
+ if (accessibilityEnabled) {
+ String value = mSelectLongPressTimeoutPreference.getValue();
+ longPressTimeout = (value != null) ? Integer.parseInt(value) : mLongPressTimeoutDefault;
+ } else {
+ longPressTimeout = mLongPressTimeoutDefault;
}
- String longPressTimeout = String.valueOf(Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.LONG_PRESS_TIMEOUT, 0));
- mSelectLongPressTimeoutPreference.setSummary(
- mLongPressTimeoutValuetoTitleMap.get(longPressTimeout));
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.LONG_PRESS_TIMEOUT,
+ longPressTimeout);
+ String value = mSelectLongPressTimeoutPreference.getValue();
+ mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValuetoTitleMap.get(value));
// Script injection.
- final boolean scriptInjectionAllowed = (Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1);
- if (scriptInjectionAllowed) {
- mToggleScriptInjectionPreference.setSummary(
- getString(R.string.accessibility_script_injection_allowed));
+ mToggleScriptInjectionPreference.setEnabled(accessibilityEnabled);
+ final boolean scriptInjectionAllowed;
+ if (accessibilityEnabled) {
+ scriptInjectionAllowed = mToggleScriptInjectionPreference.isInjectionAllowed();
} else {
- mToggleScriptInjectionPreference.setSummary(
- getString(R.string.accessibility_script_injection_disallowed));
+ scriptInjectionAllowed = false;
+ }
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
+ scriptInjectionAllowed ? 1 : 0);
+ }
+
+ private void offerInstallAccessibilitySerivceOnce() {
+ if (mServicesCategory.getPreferenceCount() > 0) {
+ return;
+ }
+ SharedPreferences preferences = getActivity().getPreferences(Context.MODE_PRIVATE);
+ final boolean offerInstallService = !preferences.getBoolean(
+ KEY_INSTALL_ACCESSIBILITY_SERVICE_OFFERED_ONCE, false);
+ if (offerInstallService) {
+ preferences.edit().putBoolean(KEY_INSTALL_ACCESSIBILITY_SERVICE_OFFERED_ONCE,
+ true).commit();
+ // Notify user that they do not have any accessibility
+ // services installed and direct them to Market to get TalkBack.
+ showDialog(DIALOG_ID_NO_ACCESSIBILITY_SERVICES);
}
}
@@ -409,48 +532,29 @@
switch (dialogId) {
case DIALOG_ID_DISABLE_ACCESSIBILITY:
return (new AlertDialog.Builder(getActivity()))
- .setTitle(android.R.string.dialog_alert_title)
+ .setTitle(R.string.accessibility_disable_warning_title)
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(getResources().
- getString(R.string.accessibility_service_disable_warning))
+ getString(R.string.accessibility_disable_warning_summary))
.setCancelable(true)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0);
- mToggleAccessibilitySwitch.setCheckedNoBeforeCheckedChangeListener(
+ mToggleAccessibilitySwitch.setCheckedInternal(
false);
- updatePreferencesForAccessibilityState();
+ updateAllPreferences(false);
}
})
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
- mToggleAccessibilitySwitch.setCheckedNoBeforeCheckedChangeListener(
+ mToggleAccessibilitySwitch.setCheckedInternal(
true);
}
})
.create();
- case DIALOG_ID_ENABLE_SCRIPT_INJECTION:
- return new AlertDialog.Builder(getActivity())
- .setTitle(android.R.string.dialog_alert_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(getActivity().getString(
- R.string.accessibility_script_injection_security_warning))
- .setCancelable(true)
- .setPositiveButton(R.string.accessibility_script_injection_button_allow,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1);
- mToggleScriptInjectionPreference.setSummary(
- getString(R.string.accessibility_script_injection_allowed));
- }
- })
-
- .setNegativeButton(R.string.accessibility_script_injection_button_disallow, null)
- .create();
case DIALOG_ID_NO_ACCESSIBILITY_SERVICES:
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.accessibility_service_no_apps_title)
@@ -461,9 +565,10 @@
// dismiss the dialog before launching the activity otherwise
// the dialog removal occurs after onSaveInstanceState which
// triggers an exception
- dialog.dismiss();
+ removeDialog(DIALOG_ID_NO_ACCESSIBILITY_SERVICES);
String screenreaderMarketLink = SystemProperties.get(
- "ro.screenreader.market", DEFAULT_SCREENREADER_MARKET_LINK);
+ SYSTEM_PROPERTY_MARKET_URL,
+ DEFAULT_SCREENREADER_MARKET_LINK);
Uri marketUri = Uri.parse(screenreaderMarketLink);
Intent marketIntent = new Intent(Intent.ACTION_VIEW, marketUri);
startActivity(marketIntent);
@@ -503,7 +608,7 @@
}
}
- private static ToggleSwitch createActionBarToggleSwitch(Activity activity) {
+ private static ToggleSwitch createAndAddActionBarToggleSwitch(Activity activity) {
ToggleSwitch toggleSwitch = new ToggleSwitch(activity);
final int padding = activity.getResources().getDimensionPixelSize(
R.dimen.action_bar_switch_padding);
@@ -542,7 +647,7 @@
super.setChecked(checked);
}
- public void setCheckedNoBeforeCheckedChangeListener(boolean checked) {
+ public void setCheckedInternal(boolean checked) {
super.setChecked(checked);
}
}
@@ -590,6 +695,17 @@
public void onPreferenceToggled(String preferenceKey, boolean enabled) {
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.TOUCH_EXPLORATION_ENABLED, enabled ? 1 : 0);
+ if (enabled) {
+ SharedPreferences preferences = getActivity().getPreferences(Context.MODE_PRIVATE);
+ final boolean launchAccessibilityTutorial = !preferences.getBoolean(
+ KEY_ACCESSIBILITY_TUTORIAL_LAUNCHED_ONCE, false);
+ if (launchAccessibilityTutorial) {
+ preferences.edit().putBoolean(KEY_ACCESSIBILITY_TUTORIAL_LAUNCHED_ONCE,
+ true).commit();
+ Intent intent = new Intent(AccessibilityTutorialActivity.ACTION);
+ getActivity().startActivity(intent);
+ }
+ }
}
}
@@ -608,14 +724,9 @@
private CharSequence mSettingsTitle;
private Intent mSettingsIntent;
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- installActionBarToggleSwitch();
- processArguments();
- getListView().setDivider(null);
- getListView().setEnabled(false);
- super.onActivityCreated(savedInstanceState);
- }
+ // TODO: Showing sub-sub fragment does not handle the activity title
+ // so we do it but this is wrong. Do a real fix when there is time.
+ private CharSequence mOldActivityTitle;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -629,6 +740,22 @@
super.onBindView(view);
TextView summaryView = (TextView) view.findViewById(R.id.summary);
summaryView.setText(getSummary());
+ sendAccessibilityEvent(summaryView);
+ }
+
+ private void sendAccessibilityEvent(View view) {
+ // Since the view is still not attached we create, populate,
+ // and send the event directly since we do not know when it
+ // will be attached and posting commands is not as clean.
+ AccessibilityManager accessibilityManager =
+ AccessibilityManager.getInstance(getActivity());
+ if (accessibilityManager.isEnabled()) {
+ AccessibilityEvent event = AccessibilityEvent.obtain();
+ event.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ view.onInitializeAccessibilityEvent(event);
+ view.dispatchPopulateAccessibilityEvent(event);
+ accessibilityManager.sendAccessibilityEvent(event);
+ }
}
};
mSummaryPreference.setPersistent(false);
@@ -636,13 +763,31 @@
preferenceScreen.addPreference(mSummaryPreference);
}
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ installActionBarToggleSwitch();
+ processArguments();
+ getListView().setDivider(null);
+ getListView().setEnabled(false);
+ }
+
+ @Override
+ public void onDestroyView() {
+ getActivity().getActionBar().setCustomView(null);
+ if (mOldActivityTitle != null) {
+ getActivity().getActionBar().setTitle(mOldActivityTitle);
+ }
+ super.onDestroyView();
+ }
+
public abstract void onPreferenceToggled(String preferenceKey, boolean value);
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
MenuItem menuItem = menu.add(mSettingsTitle);
- menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menuItem.setIntent(mSettingsIntent);
}
@@ -668,7 +813,7 @@
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
// OK, we got the user consent so set checked.
- mToggleSwitch.setCheckedNoBeforeCheckedChangeListener(true);
+ mToggleSwitch.setCheckedInternal(true);
onPreferenceToggled(mPreferenceKey, true);
break;
case DialogInterface.BUTTON_NEGATIVE:
@@ -680,13 +825,13 @@
}
private void installActionBarToggleSwitch() {
- mToggleSwitch = createActionBarToggleSwitch(getActivity());
+ mToggleSwitch = createAndAddActionBarToggleSwitch(getActivity());
mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
@Override
public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
if (checked) {
if (!TextUtils.isEmpty(mWarningMessage)) {
- toggleSwitch.setCheckedNoBeforeCheckedChangeListener(false);
+ toggleSwitch.setCheckedInternal(false);
showDialog(DIALOG_ID_WARNING);
return true;
}
@@ -707,11 +852,15 @@
// Enabled.
final boolean enabled = arguments.getBoolean(EXTRA_CHECKED);
- mToggleSwitch.setCheckedNoBeforeCheckedChangeListener(enabled);
+ mToggleSwitch.setCheckedInternal(enabled);
// Title.
- String title = arguments.getString(EXTRA_TITLE);
- getActivity().getActionBar().setTitle(arguments.getCharSequence(EXTRA_TITLE));
+ PreferenceActivity activity = (PreferenceActivity) getActivity();
+ if (!activity.onIsMultiPane() || activity.onIsHidingHeaders()) {
+ mOldActivityTitle = getActivity().getTitle();
+ String title = arguments.getString(EXTRA_TITLE);
+ getActivity().getActionBar().setTitle(arguments.getCharSequence(EXTRA_TITLE));
+ }
// Summary.
String summary = arguments.getString(EXTRA_SUMMARY);
diff --git a/src/com/android/settings/AccessibilityTutorialActivity.java b/src/com/android/settings/AccessibilityTutorialActivity.java
index 9ea9917..da8350c 100644
--- a/src/com/android/settings/AccessibilityTutorialActivity.java
+++ b/src/com/android/settings/AccessibilityTutorialActivity.java
@@ -47,6 +47,8 @@
import android.widget.TextView;
import android.widget.ViewAnimator;
+import com.android.settings.R;
+
import java.util.List;
/**
@@ -54,6 +56,10 @@
* available in Touch Exploration.
*/
public class AccessibilityTutorialActivity extends Activity {
+
+ /** Intent action for launching this activity. */
+ public static final String ACTION = "android.settings.ACCESSIBILITY_TUTORIAL";
+
/** Instance state saving constant for the active module. */
private static final String KEY_ACTIVE_MODULE = "active_module";
diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java
index d87080f..8581421 100644
--- a/src/com/android/settings/DataUsageSummary.java
+++ b/src/com/android/settings/DataUsageSummary.java
@@ -182,6 +182,7 @@
private DataUsageChartView mChart;
private TextView mUsageSummary;
+ private TextView mEmpty;
private View mAppDetail;
private TextView mAppTitle;
@@ -305,6 +306,7 @@
}
mUsageSummary = (TextView) mHeader.findViewById(R.id.usage_summary);
+ mEmpty = (TextView) mHeader.findViewById(android.R.id.empty);
// only assign layout transitions once first layout is finished
mListView.getViewTreeObserver().addOnGlobalLayoutListener(mFirstLayoutListener);
@@ -986,7 +988,7 @@
final long totalBytes = entry != null ? entry.rxBytes + entry.txBytes : 0;
final String totalPhrase = Formatter.formatFileSize(context, totalBytes);
- final String rangePhrase = formatDateRangeUtc(context, start, end);
+ final String rangePhrase = formatDateRange(context, start, end, null);
mUsageSummary.setText(
getString(R.string.data_usage_total_during_range, totalPhrase, rangePhrase));
@@ -1002,11 +1004,18 @@
/** {@inheritDoc} */
public void onLoadFinished(Loader<NetworkStats> loader, NetworkStats data) {
mAdapter.bindStats(data);
+ updateEmptyVisible();
}
/** {@inheritDoc} */
public void onLoaderReset(Loader<NetworkStats> loader) {
mAdapter.bindStats(null);
+ updateEmptyVisible();
+ }
+
+ private void updateEmptyVisible() {
+ final boolean isEmpty = mAdapter.isEmpty() && !isAppDetailMode();
+ mEmpty.setVisibility(isEmpty ? View.VISIBLE : View.GONE);
}
};
@@ -1063,7 +1072,7 @@
}
public CycleItem(Context context, long start, long end) {
- this.label = formatDateRangeUtc(context, start, end);
+ this.label = formatDateRange(context, start, end, Time.TIMEZONE_UTC);
this.start = start;
this.end = end;
}
@@ -1078,7 +1087,7 @@
private static final java.util.Formatter sFormatter = new java.util.Formatter(
sBuilder, Locale.getDefault());
- private static String formatDateRangeUtc(Context context, long start, long end) {
+ private static String formatDateRange(Context context, long start, long end, String timezone) {
synchronized (sBuilder) {
int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH;
if (Time.getJulianDay(start, 0) == Time.getJulianDay(end, 0)) {
@@ -1087,8 +1096,8 @@
}
sBuilder.setLength(0);
- return DateUtils.formatDateRange(
- context, sFormatter, start, end, flags, Time.TIMEZONE_UTC).toString();
+ return DateUtils
+ .formatDateRange(context, sFormatter, start, end, flags, timezone).toString();
}
}
@@ -1197,7 +1206,7 @@
@Override
public long getItemId(int position) {
- return position;
+ return mItems.get(position).uid;
}
@Override
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index ae7a4ef..7520ab3 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -23,6 +23,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Bundle;
import android.os.Handler;
@@ -150,8 +151,8 @@
screenTimeoutPreference.setEnabled(revisedEntries.size() > 0);
}
- int floatToIndex(float val, int resid) {
- String[] indices = getResources().getStringArray(resid);
+ int floatToIndex(float val) {
+ String[] indices = getResources().getStringArray(R.array.entryvalues_font_size);
float lastVal = Float.parseFloat(indices[0]);
for (int i=1; i<indices.length; i++) {
float thisVal = Float.parseFloat(indices[i]);
@@ -169,7 +170,16 @@
} catch (RemoteException e) {
Log.w(TAG, "Unable to retrieve font size");
}
- pref.setValueIndex(floatToIndex(mCurConfig.fontScale, R.array.entryvalues_font_size));
+
+ // mark the appropriate item in the preferences list
+ int index = floatToIndex(mCurConfig.fontScale);
+ pref.setValueIndex(index);
+
+ // report the current size in the summary text
+ final Resources res = getResources();
+ String[] fontSizeNames = res.getStringArray(R.array.entries_font_size);
+ pref.setSummary(String.format(res.getString(R.string.summary_font_size),
+ fontSizeNames[index]));
}
@Override
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 443705f..5a171e7 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -293,7 +293,7 @@
PowerUsageSummary.class.getName().equals(fragmentName) ||
AccountSyncSettings.class.getName().equals(fragmentName) ||
UserDictionarySettings.class.getName().equals(fragmentName)) {
- intent.putExtra(EXTRA_THEME, android.R.style.Theme_Holo_SolidActionBar);
+ intent.putExtra(EXTRA_THEME, android.R.style.Theme_Holo);
}
intent.setClass(this, SubSettings.class);
diff --git a/src/com/android/settings/deviceinfo/UsbSettings.java b/src/com/android/settings/deviceinfo/UsbSettings.java
index 4820234..538cde7 100644
--- a/src/com/android/settings/deviceinfo/UsbSettings.java
+++ b/src/com/android/settings/deviceinfo/UsbSettings.java
@@ -22,27 +22,19 @@
import android.content.ContentQueryMap;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
-import android.os.storage.StorageManager;
-import android.os.storage.StorageVolume;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
-import java.io.File;
-
/**
* USB storage settings.
*/
@@ -52,22 +44,13 @@
private static final String KEY_MTP = "usb_mtp";
private static final String KEY_PTP = "usb_ptp";
- private static final String KEY_INSTALLER_CD = "usb_installer_cd";
- private static final int MENU_ID_INSTALLER_CD = Menu.FIRST;
-
- private static final int DLG_INSTALLER_CD = 1;
private UsbManager mUsbManager;
- private String mInstallerImagePath;
private CheckBoxPreference mMtp;
private CheckBoxPreference mPtp;
- private MenuItem mInstallerCd;
private final BroadcastReceiver mStateReceiver = new BroadcastReceiver() {
public void onReceive(Context content, Intent intent) {
- if (!intent.getBooleanExtra(UsbManager.USB_CONNECTED, false)) {
- removeDialog(DLG_INSTALLER_CD);
- }
updateToggles();
}
};
@@ -90,11 +73,6 @@
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
- mInstallerImagePath = getString(com.android.internal.R.string.config_isoImagePath);
- if (!(new File(mInstallerImagePath)).exists()) {
- mInstallerImagePath = null;
- }
- setHasOptionsMenu(mInstallerImagePath != null);
}
@Override
@@ -116,47 +94,22 @@
new IntentFilter(UsbManager.ACTION_USB_STATE));
}
- @Override
- public Dialog onCreateDialog(int id) {
- switch (id) {
- case DLG_INSTALLER_CD:
- return new AlertDialog.Builder(getActivity())
- .setTitle(R.string.dlg_installer_cd_title)
- .setMessage(R.string.dlg_installer_cd_text)
- .setPositiveButton(R.string.dlg_installer_cd_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Disable installer CD, return to default function.
- mUsbManager.setCurrentFunction(null, false);
- }})
- .create();
- }
- return null;
- }
-
private void updateToggles() {
- if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_MTP)) {
+ String function = mUsbManager.getDefaultFunction();
+ if (UsbManager.USB_FUNCTION_MTP.equals(function)) {
mMtp.setChecked(true);
mPtp.setChecked(false);
- } else if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP)) {
+ } else if (UsbManager.USB_FUNCTION_PTP.equals(function)) {
mMtp.setChecked(false);
mPtp.setChecked(true);
} else {
mMtp.setChecked(false);
mPtp.setChecked(false);
}
- if (mInstallerCd != null) {
- if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_MASS_STORAGE)) {
- mInstallerCd.setTitle( R.string.usb_label_installer_cd_done);
- } else {
- mInstallerCd.setTitle( R.string.usb_label_installer_cd);
- }
- }
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- Log.d(TAG, "onPreferenceTreeClick " + preference);
// temporary hack - using check boxes as radio buttons
// don't allow unchecking them
@@ -175,31 +128,4 @@
updateToggles();
return true;
}
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- mInstallerCd = menu.add(Menu.NONE, MENU_ID_INSTALLER_CD, 0,
- R.string.usb_label_installer_cd);
- mInstallerCd.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case MENU_ID_INSTALLER_CD:
- if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_MASS_STORAGE)) {
- // Disable installer CD, return to default function.
- mUsbManager.setCurrentFunction(null, false);
- removeDialog(DLG_INSTALLER_CD);
- } else {
- // Enable installer CD. Don't set as default function.
- mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MASS_STORAGE, false);
- mUsbManager.setMassStorageBackingFile(mInstallerImagePath);
- showDialog(DLG_INSTALLER_CD);
- }
- updateToggles();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
}
diff --git a/src/com/android/settings/inputmethod/SingleSpellCheckerPreference.java b/src/com/android/settings/inputmethod/SingleSpellCheckerPreference.java
new file mode 100644
index 0000000..98ca3af
--- /dev/null
+++ b/src/com/android/settings/inputmethod/SingleSpellCheckerPreference.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011 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.inputmethod;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+import android.content.Intent;
+
+import android.preference.Preference;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.textservice.SpellCheckerInfo;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class SingleSpellCheckerPreference extends Preference {
+ private static final float DISABLED_ALPHA = 0.4f;
+
+ private final SpellCheckerInfo mSpellCheckerInfo;
+
+ private SettingsPreferenceFragment mFragment;
+ private TextView mTitleText;
+ private TextView mSummaryText;
+ private View mPrefAll;
+ private View mPrefLeftButton;
+ private ImageView mSetingsButton;
+ private Intent mSettingsIntent;
+ private boolean mSelected;
+
+ public SingleSpellCheckerPreference(SettingsPreferenceFragment fragment, Intent settingsIntent,
+ SpellCheckerInfo sci) {
+ super(fragment.getActivity(), null, 0);
+ setLayoutResource(R.layout.preference_spellchecker);
+ mSpellCheckerInfo = sci;
+ mSelected = false;
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+ mPrefAll = view.findViewById(R.id.pref_all);
+ mPrefLeftButton = view.findViewById(R.id.pref_left_button);
+ mPrefLeftButton.setOnClickListener(
+ new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ onLeftButtonClicked(arg0);
+ }
+ });
+ mSetingsButton = (ImageView)view.findViewById(R.id.pref_right_button);
+ mTitleText = (TextView)view.findViewById(android.R.id.title);
+ mSummaryText = (TextView)view.findViewById(android.R.id.summary);
+ mSetingsButton.setOnClickListener(
+ new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ onSettingsButtonClicked(arg0);
+ }
+ });
+ updateSelectedState(mSelected);
+ }
+
+ private void onLeftButtonClicked(View arg0) {
+ final OnPreferenceClickListener listener = getOnPreferenceClickListener();
+ if (listener != null) {
+ listener.onPreferenceClick(this);
+ }
+ }
+
+ public SpellCheckerInfo getSpellCheckerInfo() {
+ return mSpellCheckerInfo;
+ }
+
+ public void updateSelectedState(boolean selected) {
+ if (mPrefAll != null) {
+ if (selected) {
+ // TODO: Use a color defined by the design guideline.
+ mPrefAll.setBackgroundColor(0x88006666);
+ } else {
+ mPrefAll.setBackgroundColor(0);
+ }
+ enableSettingsButton(selected);
+ }
+ }
+
+ public void setSelected(boolean selected) {
+ mSelected = selected;
+ }
+
+ protected void onSettingsButtonClicked(View arg0) {
+ if (mFragment != null && mSettingsIntent != null) {
+ mFragment.startActivity(mSettingsIntent);
+ }
+ }
+
+ private void enableSettingsButton(boolean enabled) {
+ if (mSetingsButton != null) {
+ if (mSettingsIntent == null) {
+ mSetingsButton.setVisibility(View.GONE);
+ } else {
+ mSetingsButton.setEnabled(enabled);
+ mSetingsButton.setClickable(enabled);
+ mSetingsButton.setFocusable(enabled);
+ if (!enabled) {
+ mSetingsButton.setAlpha(DISABLED_ALPHA);
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/inputmethod/SpellCheckersSettings.java b/src/com/android/settings/inputmethod/SpellCheckersSettings.java
index c8b3ca9..d6c0b1c 100644
--- a/src/com/android/settings/inputmethod/SpellCheckersSettings.java
+++ b/src/com/android/settings/inputmethod/SpellCheckersSettings.java
@@ -26,12 +26,16 @@
import android.view.textservice.SpellCheckerInfo;
import android.view.textservice.TextServicesManager;
+import java.util.ArrayList;
+
public class SpellCheckersSettings extends SettingsPreferenceFragment
- implements Preference.OnPreferenceChangeListener {
+ implements Preference.OnPreferenceClickListener {
private SpellCheckerInfo mCurrentSci;
private SpellCheckerInfo[] mEnabledScis;
private TextServicesManager mTsm;
+ private final ArrayList<SingleSpellCheckerPreference> mSpellCheckers =
+ new ArrayList<SingleSpellCheckerPreference>();
@Override
public void onCreate(Bundle icicle) {
@@ -42,11 +46,6 @@
}
@Override
- public boolean onPreferenceChange(Preference arg0, Object arg1) {
- return false;
- }
-
- @Override
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
return false;
}
@@ -78,12 +77,28 @@
if (mCurrentSci == null || mEnabledScis == null) {
return;
}
- // TODO: implement here
+ mSpellCheckers.clear();
for (int i = 0; i < mEnabledScis.length; ++i) {
final SpellCheckerInfo sci = mEnabledScis[i];
- final PreferenceScreen scs = new PreferenceScreen(getActivity(), null);
- scs.setTitle(sci.getId());
- getPreferenceScreen().addPreference(scs);
+ final SingleSpellCheckerPreference scPref = new SingleSpellCheckerPreference(
+ this, null, sci);
+ mSpellCheckers.add(scPref);
+ scPref.setTitle(sci.getId());
+ scPref.setSelected(mCurrentSci != null && mCurrentSci.getId().equals(sci.getId()));
+ getPreferenceScreen().addPreference(scPref);
}
}
+
+ @Override
+ public boolean onPreferenceClick(Preference arg0) {
+ for (SingleSpellCheckerPreference scp : mSpellCheckers) {
+ if (arg0.equals(scp)) {
+ scp.setSelected(true);
+ mTsm.setCurrentSpellChecker(scp.getSpellCheckerInfo());
+ } else {
+ scp.setSelected(false);
+ }
+ }
+ return true;
+ }
}
diff --git a/src/com/android/settings/nfc/ZeroClick.java b/src/com/android/settings/nfc/ZeroClick.java
index 4d657d9..5c67e52 100644
--- a/src/com/android/settings/nfc/ZeroClick.java
+++ b/src/com/android/settings/nfc/ZeroClick.java
@@ -56,6 +56,7 @@
ActionBar.LayoutParams.WRAP_CONTENT,
ActionBar.LayoutParams.WRAP_CONTENT,
Gravity.CENTER_VERTICAL | Gravity.RIGHT));
+ activity.getActionBar().setTitle(R.string.zeroclick_settings_title);
}
}
diff --git a/src/com/android/settings/widget/ChartAxis.java b/src/com/android/settings/widget/ChartAxis.java
index 463541f..4e0da1d 100644
--- a/src/com/android/settings/widget/ChartAxis.java
+++ b/src/com/android/settings/widget/ChartAxis.java
@@ -25,14 +25,26 @@
*/
public interface ChartAxis {
+ /** Set range of raw values this axis should cover. */
public void setBounds(long min, long max);
+ /** Set range of screen points this axis should cover. */
public void setSize(float size);
+ /** Convert raw value into screen point. */
public float convertToPoint(long value);
+ /** Convert screen point into raw value. */
public long convertToValue(float point);
+ /** Build label that describes given raw value. */
public void buildLabel(Resources res, SpannableStringBuilder builder, long value);
+ /** Return list of tick points for drawing a grid. */
public float[] getTickPoints();
+ /**
+ * Test if given raw value should cause the axis to grow or shrink;
+ * returning positive value to grow and negative to shrink.
+ */
+ public int shouldAdjustAxis(long value);
+
}
diff --git a/src/com/android/settings/widget/ChartNetworkSeriesView.java b/src/com/android/settings/widget/ChartNetworkSeriesView.java
index 51c3c2c..481f7cc 100644
--- a/src/com/android/settings/widget/ChartNetworkSeriesView.java
+++ b/src/com/android/settings/widget/ChartNetworkSeriesView.java
@@ -23,6 +23,7 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
@@ -41,7 +42,7 @@
*/
public class ChartNetworkSeriesView extends View {
private static final String TAG = "ChartNetworkSeriesView";
- private static final boolean LOGD = true;
+ private static final boolean LOGD = false;
private ChartAxis mHoriz;
private ChartAxis mVert;
@@ -60,6 +61,14 @@
private long mPrimaryLeft;
private long mPrimaryRight;
+ /** Series will be extended to reach this end time. */
+ private long mEndTime = Long.MIN_VALUE;
+
+ private boolean mEstimateVisible = false;
+
+ private long mMax;
+ private long mMaxEstimate;
+
public ChartNetworkSeriesView(Context context) {
this(context, null, 0);
}
@@ -116,6 +125,7 @@
mPaintEstimate.setColor(fillSecondary);
mPaintEstimate.setStyle(Style.STROKE);
mPaintEstimate.setAntiAlias(true);
+ mPaintEstimate.setPathEffect(new DashPathEffect(new float[] { 10, 10 }, 1));
}
public void bindNetworkStats(NetworkStatsHistory stats) {
@@ -149,6 +159,7 @@
public void generatePath() {
if (LOGD) Log.d(TAG, "generatePath()");
+ mMax = 0;
mPathStroke.reset();
mPathFill.reset();
mPathEstimate.reset();
@@ -174,8 +185,8 @@
for (int i = 0; i < mStats.size(); i++) {
entry = mStats.getValues(i, entry);
- lastTime = entry.bucketStart;
- final float x = mHoriz.convertToPoint(entry.bucketStart);
+ lastTime = entry.bucketStart + entry.bucketDuration;
+ final float x = mHoriz.convertToPoint(lastTime);
final float y = mVert.convertToPoint(totalData);
// skip until we find first stats on screen
@@ -199,6 +210,16 @@
lastY = y;
}
+ // when data falls short, extend to requested end time
+ if (lastTime < mEndTime) {
+ lastX = mHoriz.convertToPoint(mEndTime);
+
+ if (started) {
+ mPathStroke.lineTo(lastX, lastY);
+ mPathFill.lineTo(lastX, lastY);
+ }
+ }
+
if (LOGD) {
final RectF bounds = new RectF();
mPathFill.computeBounds(bounds, true);
@@ -210,6 +231,8 @@
mPathFill.lineTo(lastX, height);
mPathFill.lineTo(firstX, height);
+ mMax = totalData;
+
// build estimated data
mPathEstimate.moveTo(lastX, lastY);
@@ -234,10 +257,29 @@
totalData += (longWindow * 7 + shortWindow * 3) / 10;
lastX = mHoriz.convertToPoint(lastTime + futureTime);
- final float y = mVert.convertToPoint(totalData);
+ lastY = mVert.convertToPoint(totalData);
- mPathEstimate.lineTo(lastX, y);
+ mPathEstimate.lineTo(lastX, lastY);
}
+
+ mMaxEstimate = totalData;
+ }
+
+ public void setEndTime(long endTime) {
+ mEndTime = endTime;
+ }
+
+ public void setEstimateVisible(boolean estimateVisible) {
+ mEstimateVisible = estimateVisible;
+ invalidate();
+ }
+
+ public long getMaxEstimate() {
+ return mMaxEstimate;
+ }
+
+ public long getMaxVisible() {
+ return mEstimateVisible ? mMaxEstimate : mMax;
}
@Override
@@ -247,10 +289,12 @@
final float primaryLeftPoint = mHoriz.convertToPoint(mPrimaryLeft);
final float primaryRightPoint = mHoriz.convertToPoint(mPrimaryRight);
- save = canvas.save();
- canvas.clipRect(0, 0, getWidth(), getHeight());
- canvas.drawPath(mPathEstimate, mPaintEstimate);
- canvas.restoreToCount(save);
+ if (mEstimateVisible) {
+ save = canvas.save();
+ canvas.clipRect(0, 0, getWidth(), getHeight());
+ canvas.drawPath(mPathEstimate, mPaintEstimate);
+ canvas.restoreToCount(save);
+ }
save = canvas.save();
canvas.clipRect(0, 0, primaryLeftPoint, getHeight());
diff --git a/src/com/android/settings/widget/ChartSweepView.java b/src/com/android/settings/widget/ChartSweepView.java
index 99c35bd..b5e044f 100644
--- a/src/com/android/settings/widget/ChartSweepView.java
+++ b/src/com/android/settings/widget/ChartSweepView.java
@@ -29,6 +29,7 @@
import android.text.SpannableStringBuilder;
import android.text.TextPaint;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.View;
@@ -48,6 +49,7 @@
private Point mSweepOffset = new Point();
private Rect mMargins = new Rect();
+ private float mNeighborMargin;
private int mFollowAxis;
@@ -65,7 +67,6 @@
private long mValidBefore;
private ChartSweepView mValidAfterDynamic;
private ChartSweepView mValidBeforeDynamic;
- private long mValidBufferArea;
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
@@ -93,6 +94,7 @@
setSweepDrawable(a.getDrawable(R.styleable.ChartSweepView_sweepDrawable));
setFollowAxis(a.getInt(R.styleable.ChartSweepView_followAxis, -1));
+ setNeighborMargin(a.getDimensionPixelSize(R.styleable.ChartSweepView_neighborMargin, 0));
setLabelSize(a.getDimensionPixelSize(R.styleable.ChartSweepView_labelSize, 0));
setLabelTemplate(a.getResourceId(R.styleable.ChartSweepView_labelTemplate, 0));
@@ -271,16 +273,18 @@
mValidBefore = validBefore;
}
+ public void setNeighborMargin(float neighborMargin) {
+ mNeighborMargin = neighborMargin;
+ }
+
/**
* Set valid range this sweep can move within, defined by the given
* {@link ChartSweepView}. The most restrictive combination of all valid
* ranges is used.
*/
- public void setValidRangeDynamic(
- ChartSweepView validAfter, ChartSweepView validBefore, long bufferArea) {
+ public void setValidRangeDynamic(ChartSweepView validAfter, ChartSweepView validBefore) {
mValidAfterDynamic = validAfter;
mValidBeforeDynamic = validBefore;
- mValidBufferArea = bufferArea;
}
@Override
@@ -316,9 +320,7 @@
getParent().requestDisallowInterceptTouchEvent(true);
// content area of parent
- final Rect parentContent = new Rect(parent.getPaddingLeft(), parent.getPaddingTop(),
- parent.getWidth() - parent.getPaddingRight(),
- parent.getHeight() - parent.getPaddingBottom());
+ final Rect parentContent = getParentContentRect();
final Rect clampRect = computeClampRect(parentContent);
if (mFollowAxis == VERTICAL) {
@@ -358,6 +360,33 @@
}
}
+ /**
+ * Update {@link #mValue} based on current position, including any
+ * {@link #onTouchEvent(MotionEvent)} in progress. Typically used when
+ * {@link ChartAxis} changes during sweep adjustment.
+ */
+ public void updateValueFromPosition() {
+ final Rect parentContent = getParentContentRect();
+ if (mFollowAxis == VERTICAL) {
+ final float effectiveY = getY() - mMargins.top - parentContent.top;
+ setValue(mAxis.convertToValue(effectiveY));
+ } else {
+ final float effectiveX = getX() - mMargins.left - parentContent.left;
+ setValue(mAxis.convertToValue(effectiveX));
+ }
+ }
+
+ public int shouldAdjustAxis() {
+ return mAxis.shouldAdjustAxis(getValue());
+ }
+
+ private Rect getParentContentRect() {
+ final View parent = (View) getParent();
+ return new Rect(parent.getPaddingLeft(), parent.getPaddingTop(),
+ parent.getWidth() - parent.getPaddingRight(),
+ parent.getHeight() - parent.getPaddingBottom());
+ }
+
@Override
public void addOnLayoutChangeListener(OnLayoutChangeListener listener) {
// ignored to keep LayoutTransition from animating us
@@ -368,18 +397,14 @@
// ignored to keep LayoutTransition from animating us
}
- private long getValidAfterValue() {
+ private long getValidAfterDynamic() {
final ChartSweepView dynamic = mValidAfterDynamic;
- final boolean dynamicEnabled = dynamic != null && dynamic.isEnabled();
- return Math.max(mValidAfter,
- dynamicEnabled ? dynamic.getValue() + mValidBufferArea : Long.MIN_VALUE);
+ return dynamic != null && dynamic.isEnabled() ? dynamic.getValue() : Long.MIN_VALUE;
}
- private long getValidBeforeValue() {
+ private long getValidBeforeDynamic() {
final ChartSweepView dynamic = mValidBeforeDynamic;
- final boolean dynamicEnabled = dynamic != null && dynamic.isEnabled();
- return Math.min(mValidBefore,
- dynamicEnabled ? dynamic.getValue() - mValidBufferArea : Long.MAX_VALUE);
+ return dynamic != null && dynamic.isEnabled() ? dynamic.getValue() : Long.MAX_VALUE;
}
/**
@@ -388,22 +413,36 @@
* style rules.
*/
private Rect computeClampRect(Rect parentContent) {
- final Rect clampRect = new Rect(parentContent);
+ // create two rectangles, and pick most restrictive combination
+ final Rect rect = buildClampRect(parentContent, mValidAfter, mValidBefore, 0f);
+ final Rect dynamicRect = buildClampRect(
+ parentContent, getValidAfterDynamic(), getValidBeforeDynamic(), mNeighborMargin);
- float validAfterPoint = mAxis.convertToPoint(getValidAfterValue());
- float validBeforePoint = mAxis.convertToPoint(getValidBeforeValue());
- if (validAfterPoint > validBeforePoint) {
- float swap = validBeforePoint;
- validBeforePoint = validAfterPoint;
- validAfterPoint = swap;
+ rect.intersect(dynamicRect);
+ return rect;
+ }
+
+ private Rect buildClampRect(
+ Rect parentContent, long afterValue, long beforeValue, float margin) {
+ if (mAxis instanceof InvertedChartAxis) {
+ long temp = beforeValue;
+ beforeValue = afterValue;
+ afterValue = temp;
}
+ final boolean afterValid = afterValue != Long.MIN_VALUE && afterValue != Long.MAX_VALUE;
+ final boolean beforeValid = beforeValue != Long.MIN_VALUE && beforeValue != Long.MAX_VALUE;
+
+ final float afterPoint = mAxis.convertToPoint(afterValue) + margin;
+ final float beforePoint = mAxis.convertToPoint(beforeValue) - margin;
+
+ final Rect clampRect = new Rect(parentContent);
if (mFollowAxis == VERTICAL) {
- clampRect.bottom = clampRect.top + (int) validBeforePoint;
- clampRect.top += validAfterPoint;
+ if (beforeValid) clampRect.bottom = clampRect.top + (int) beforePoint;
+ if (afterValid) clampRect.top += afterPoint;
} else {
- clampRect.right = clampRect.left + (int) validBeforePoint;
- clampRect.left += validAfterPoint;
+ if (beforeValid) clampRect.right = clampRect.left + (int) beforePoint;
+ if (afterValid) clampRect.left += afterPoint;
}
return clampRect;
}
diff --git a/src/com/android/settings/widget/DataUsageChartView.java b/src/com/android/settings/widget/DataUsageChartView.java
index 839171e..b2ad844 100644
--- a/src/com/android/settings/widget/DataUsageChartView.java
+++ b/src/com/android/settings/widget/DataUsageChartView.java
@@ -16,12 +16,12 @@
package com.android.settings.widget;
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-
import android.content.Context;
import android.content.res.Resources;
import android.net.NetworkPolicy;
import android.net.NetworkStatsHistory;
+import android.os.Handler;
+import android.os.Message;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -43,7 +43,8 @@
private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
- // TODO: enforce that sweeps cant cross each other
+ private static final int MSG_UPDATE_AXIS = 100;
+ private static final long DELAY_MILLIS = 250;
private ChartGridView mGrid;
private ChartNetworkSeriesView mSeries;
@@ -56,6 +57,11 @@
private ChartSweepView mSweepWarning;
private ChartSweepView mSweepLimit;
+ private Handler mHandler;
+
+ /** Current maximum value of {@link #mVert}. */
+ private long mVertMax;
+
public interface DataUsageChartListener {
public void onInspectRangeChanged();
public void onWarningChanged();
@@ -75,6 +81,18 @@
public DataUsageChartView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(new TimeAxis(), new InvertedChartAxis(new DataAxis()));
+
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ final ChartSweepView sweep = (ChartSweepView) msg.obj;
+ updateVertAxisBounds(sweep);
+ updateEstimateVisible();
+
+ // we keep dispatching repeating updates until sweep is dropped
+ sendUpdateAxisDelayed(sweep, true);
+ }
+ };
}
@Override
@@ -92,19 +110,15 @@
mSweepWarning = (ChartSweepView) findViewById(R.id.sweep_warning);
// prevent sweeps from crossing each other
- mSweepLeft.setValidRangeDynamic(null, mSweepRight, HOUR_IN_MILLIS);
- mSweepRight.setValidRangeDynamic(mSweepLeft, null, HOUR_IN_MILLIS);
+ mSweepLeft.setValidRangeDynamic(null, mSweepRight);
+ mSweepRight.setValidRangeDynamic(mSweepLeft, null);
+ mSweepWarning.setValidRangeDynamic(null, mSweepLimit);
+ mSweepLimit.setValidRangeDynamic(mSweepWarning, null);
- // TODO: assign these ranges as user changes data axis
- mSweepWarning.setValidRange(0L, 5 * GB_IN_BYTES);
- mSweepWarning.setValidRangeDynamic(null, mSweepLimit, MB_IN_BYTES);
- mSweepLimit.setValidRange(0L, 5 * GB_IN_BYTES);
- mSweepLimit.setValidRangeDynamic(mSweepWarning, null, MB_IN_BYTES);
-
- mSweepLeft.addOnSweepListener(mSweepListener);
- mSweepRight.addOnSweepListener(mSweepListener);
- mSweepWarning.addOnSweepListener(mWarningListener);
- mSweepLimit.addOnSweepListener(mLimitListener);
+ mSweepLeft.addOnSweepListener(mHorizListener);
+ mSweepRight.addOnSweepListener(mHorizListener);
+ mSweepWarning.addOnSweepListener(mVertListener);
+ mSweepLimit.addOnSweepListener(mVertListener);
// tell everyone about our axis
mGrid.init(mHoriz, mVert);
@@ -125,6 +139,8 @@
public void bindNetworkStats(NetworkStatsHistory stats) {
mSeries.bindNetworkStats(stats);
mHistory = stats;
+ updateVertAxisBounds(null);
+ updateEstimateVisible();
updatePrimaryRange();
requestLayout();
}
@@ -132,6 +148,11 @@
public void bindDetailNetworkStats(NetworkStatsHistory stats) {
mDetailSeries.bindNetworkStats(stats);
mDetailSeries.setVisibility(stats != null ? View.VISIBLE : View.GONE);
+ if (mHistory != null) {
+ mDetailSeries.setEndTime(mHistory.getEnd());
+ }
+ updateVertAxisBounds(null);
+ updateEstimateVisible();
updatePrimaryRange();
requestLayout();
}
@@ -139,17 +160,20 @@
public void bindNetworkPolicy(NetworkPolicy policy) {
if (policy == null) {
mSweepLimit.setVisibility(View.INVISIBLE);
+ mSweepLimit.setValue(-1);
mSweepWarning.setVisibility(View.INVISIBLE);
+ mSweepWarning.setValue(-1);
return;
}
if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
mSweepLimit.setVisibility(View.VISIBLE);
- mSweepLimit.setValue(policy.limitBytes);
mSweepLimit.setEnabled(true);
+ mSweepLimit.setValue(policy.limitBytes);
} else {
mSweepLimit.setVisibility(View.VISIBLE);
mSweepLimit.setEnabled(false);
+ mSweepLimit.setValue(-1);
}
if (policy.warningBytes != NetworkPolicy.WARNING_DISABLED) {
@@ -157,12 +181,81 @@
mSweepWarning.setValue(policy.warningBytes);
} else {
mSweepWarning.setVisibility(View.INVISIBLE);
+ mSweepWarning.setValue(-1);
}
+ updateVertAxisBounds(null);
requestLayout();
}
- private OnSweepListener mSweepListener = new OnSweepListener() {
+ /**
+ * Update {@link #mVert} to both show data from {@link NetworkStatsHistory}
+ * and controls from {@link NetworkPolicy}.
+ */
+ private void updateVertAxisBounds(ChartSweepView activeSweep) {
+ final long max = mVertMax;
+ final long newMax;
+ if (activeSweep != null) {
+ final int adjustAxis = activeSweep.shouldAdjustAxis();
+ if (adjustAxis > 0) {
+ // hovering around upper edge, grow axis
+ newMax = max * 11 / 10;
+ } else if (adjustAxis < 0) {
+ // hovering around lower edge, shrink axis
+ newMax = max * 9 / 10;
+ } else {
+ newMax = max;
+ }
+
+ } else {
+ // try showing all known data and policy
+ final long maxSweep = Math.max(mSweepWarning.getValue(), mSweepLimit.getValue());
+ final long maxVisible = Math.max(mSeries.getMaxVisible(), maxSweep) * 12 / 10;
+ newMax = Math.max(maxVisible, 2 * GB_IN_BYTES);
+ }
+
+ // only invalidate when vertMax actually changed
+ if (newMax != mVertMax) {
+ mVertMax = newMax;
+
+ mVert.setBounds(0L, newMax);
+ mSweepWarning.setValidRange(0L, newMax);
+ mSweepLimit.setValidRange(0L, newMax);
+
+ mSeries.generatePath();
+ mDetailSeries.generatePath();
+
+ mGrid.invalidate();
+ mSeries.invalidate();
+ mDetailSeries.invalidate();
+
+ // since we just changed axis, make sweep recalculate its value
+ if (activeSweep != null) {
+ activeSweep.updateValueFromPosition();
+ }
+ }
+ }
+
+ /**
+ * Control {@link ChartNetworkSeriesView#setEstimateVisible(boolean)} based
+ * on how close estimate comes to {@link #mSweepWarning}.
+ */
+ private void updateEstimateVisible() {
+ final long maxEstimate = mSeries.getMaxEstimate();
+
+ // show estimate when near warning/limit
+ long interestLine = Long.MAX_VALUE;
+ if (mSweepWarning.isEnabled()) {
+ interestLine = mSweepWarning.getValue();
+ } else if (mSweepLimit.isEnabled()) {
+ interestLine = mSweepLimit.getValue();
+ }
+
+ final boolean estimateVisible = (maxEstimate >= interestLine * 7 / 10);
+ mSeries.setEstimateVisible(estimateVisible);
+ }
+
+ private OnSweepListener mHorizListener = new OnSweepListener() {
public void onSweep(ChartSweepView sweep, boolean sweepDone) {
updatePrimaryRange();
@@ -173,18 +266,31 @@
}
};
- private OnSweepListener mWarningListener = new OnSweepListener() {
- public void onSweep(ChartSweepView sweep, boolean sweepDone) {
- if (sweepDone && mListener != null) {
- mListener.onWarningChanged();
- }
+ private void sendUpdateAxisDelayed(ChartSweepView sweep, boolean force) {
+ if (force || !mHandler.hasMessages(MSG_UPDATE_AXIS, sweep)) {
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MSG_UPDATE_AXIS, sweep), DELAY_MILLIS);
}
- };
+ }
- private OnSweepListener mLimitListener = new OnSweepListener() {
+ private void clearUpdateAxisDelayed(ChartSweepView sweep) {
+ mHandler.removeMessages(MSG_UPDATE_AXIS, sweep);
+ }
+
+ private OnSweepListener mVertListener = new OnSweepListener() {
public void onSweep(ChartSweepView sweep, boolean sweepDone) {
- if (sweepDone && mListener != null) {
- mListener.onLimitChanged();
+ if (sweepDone) {
+ clearUpdateAxisDelayed(sweep);
+ updateEstimateVisible();
+
+ if (sweep == mSweepWarning && mListener != null) {
+ mListener.onWarningChanged();
+ } else if (sweep == mSweepLimit && mListener != null) {
+ mListener.onLimitChanged();
+ }
+ } else {
+ // while moving, kick off delayed grow/shrink axis updates
+ sendUpdateAxisDelayed(sweep, false);
}
}
};
@@ -252,11 +358,14 @@
mSweepLeft.setValue(sweepMin);
mSweepRight.setValue(sweepMax);
- updatePrimaryRange();
requestLayout();
mSeries.generatePath();
mSeries.invalidate();
+
+ updateVertAxisBounds(null);
+ updateEstimateVisible();
+ updatePrimaryRange();
}
private void updatePrimaryRange() {
@@ -321,6 +430,12 @@
}
return tickPoints;
}
+
+ /** {@inheritDoc} */
+ public int shouldAdjustAxis(long value) {
+ // time axis never adjusts
+ return 0;
+ }
}
public static class DataAxis implements ChartAxis {
@@ -328,12 +443,6 @@
private long mMax;
private float mSize;
- public DataAxis() {
- // TODO: adapt ranges to show when history >5GB, and handle 4G
- // interfaces with higher limits.
- setBounds(0, 5 * GB_IN_BYTES);
- }
-
/** {@inheritDoc} */
public void setBounds(long min, long max) {
mMin = min;
@@ -347,19 +456,19 @@
/** {@inheritDoc} */
public float convertToPoint(long value) {
- // TODO: this assumes range of [0,5]GB
+ // derived polynomial fit to make lower values more visible
+ final double normalized = ((double) value - mMin) / (mMax - mMin);
final double fraction = Math.pow(
- 10, 0.36884343106175160321 * Math.log10(value) + -3.62828151137812282556);
- return (float) fraction * mSize;
+ 10, 0.36884343106175121463 * Math.log10(normalized) + -0.04328199452018252624);
+ return (float) (fraction * mSize);
}
/** {@inheritDoc} */
public long convertToValue(float point) {
- final double y = point / mSize;
- // TODO: this assumes range of [0,5]GB
- final double fraction = 6.869341163271789302 * Math.pow(10, 9)
- * Math.pow(y, 2.71117746931646030774);
- return (long) fraction;
+ final double normalized = point / mSize;
+ final double fraction = 1.3102228476089056629
+ * Math.pow(normalized, 2.7111774693164631640);
+ return (long) (mMin + (fraction * (mMax - mMin)));
}
private static final Object sSpanSize = new Object();
@@ -393,17 +502,31 @@
/** {@inheritDoc} */
public float[] getTickPoints() {
- final float[] tickPoints = new float[16];
+ final long range = mMax - mMin;
+ final long tickJump = 256 * MB_IN_BYTES;
- final long jump = ((mMax - mMin) / tickPoints.length);
+ final int tickCount = (int) (range / tickJump);
+ final float[] tickPoints = new float[tickCount];
long value = mMin;
for (int i = 0; i < tickPoints.length; i++) {
tickPoints[i] = convertToPoint(value);
- value += jump;
+ value += tickJump;
}
return tickPoints;
}
+
+ /** {@inheritDoc} */
+ public int shouldAdjustAxis(long value) {
+ final float point = convertToPoint(value);
+ if (point < mSize * 0.1) {
+ return -1;
+ } else if (point > mSize * 0.85) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
}
private static int[] findOrCreateSpan(
diff --git a/src/com/android/settings/widget/InvertedChartAxis.java b/src/com/android/settings/widget/InvertedChartAxis.java
index e589da9..96aec7b 100644
--- a/src/com/android/settings/widget/InvertedChartAxis.java
+++ b/src/com/android/settings/widget/InvertedChartAxis.java
@@ -64,4 +64,9 @@
}
return points;
}
+
+ /** {@inheritDoc} */
+ public int shouldAdjustAxis(long value) {
+ return mWrapped.shouldAdjustAxis(value);
+ }
}