Merge "Use WebViewFactory accessors to find experimental state"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c894453..49fe4d5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -65,6 +65,7 @@
<uses-permission android:name="android.permission.SET_TIME" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
<uses-permission android:name="android.permission.REBOOT" />
+ <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
<application android:label="@string/settings_label"
android:icon="@mipmap/ic_launcher_settings"
@@ -966,7 +967,7 @@
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.AccessibilitySettings" />
+ android:value="com.android.settings.accessibility.AccessibilitySettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
android:resource="@id/accessibility_settings" />
</activity>
diff --git a/res/layout/preference_app_restrictions.xml b/res/layout/preference_app_restrictions.xml
index a8a93d1..753099d 100644
--- a/res/layout/preference_app_restrictions.xml
+++ b/res/layout/preference_app_restrictions.xml
@@ -19,8 +19,7 @@
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
- android:paddingStart="@*android:dimen/preference_item_padding_side"
- android:paddingEnd="?android:attr/scrollbarSize">
+ android:paddingStart="@*android:dimen/preference_item_padding_side">
<LinearLayout
android:layout_width="wrap_content"
@@ -101,7 +100,6 @@
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:paddingRight="?android:attr/scrollbarSize"
android:gravity="center_vertical"
android:orientation="vertical" />
</LinearLayout>
diff --git a/res/layout/user_dictionary_add_word_fullscreen.xml b/res/layout/user_dictionary_add_word_fullscreen.xml
index 57f9184..42bd197 100644
--- a/res/layout/user_dictionary_add_word_fullscreen.xml
+++ b/res/layout/user_dictionary_add_word_fullscreen.xml
@@ -62,22 +62,6 @@
android:imeOptions="flagNoFullscreen"
android:inputType="textNoSuggestions"
android:maxLength="@integer/maximum_user_dictionary_word_length" />
-
- <TextView
- android:id="@+id/user_dictionary_add_locale_label"
- style="?android:attr/textAppearanceSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start|center_vertical"
- android:text="@string/user_dict_settings_add_locale_option_name" />
-
- <Spinner
- android:id="@+id/user_dictionary_add_locale"
- android:layout_width="wrap_content"
- android:layout_gravity="fill_horizontal|center_vertical"
- android:layout_marginBottom="8dip"
- android:layout_marginStart="8dip"
- android:layout_marginTop="8dip" />
</GridLayout>
</LinearLayout>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index a60db45..f7d0f19 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -599,7 +599,7 @@
<string name="wifi_signal" msgid="5514120261628065287">"Síla signálu"</string>
<string name="wifi_status" msgid="4824568012414605414">"Stav"</string>
<string name="wifi_speed" msgid="3526198708812322037">"Rychlost připojení"</string>
- <string name="wifi_ip_address" msgid="1440054061044402918">"Adresa IP"</string>
+ <string name="wifi_ip_address" msgid="1440054061044402918">"IP adresa"</string>
<string name="wifi_eap_method" msgid="8529436133640730382">"Metoda EAP"</string>
<string name="please_select_phase2" msgid="5231074529772044898">"Ověření Phase 2"</string>
<string name="wifi_eap_ca_cert" msgid="3521574865488892851">"Certifikát CA"</string>
@@ -644,7 +644,7 @@
<string name="wifi_setting_frequency_band_summary" msgid="3250740757118009784">"Uveďte provozní frekvenční rozsah"</string>
<string name="wifi_setting_frequency_band_error" msgid="837281974489794378">"Při nastavení frekvenčního pásma došlo k problému."</string>
<string name="wifi_advanced_mac_address_title" msgid="6571335466330978393">"Adresa MAC"</string>
- <string name="wifi_advanced_ip_address_title" msgid="6215297094363164846">"Adresa IP"</string>
+ <string name="wifi_advanced_ip_address_title" msgid="6215297094363164846">"IP adresa"</string>
<string name="wifi_advanced_settings_label" msgid="3654366894867838338">"Nastavení adresy IP"</string>
<string name="wifi_ip_settings_menu_save" msgid="7296724066102908366">"Uložit"</string>
<string name="wifi_ip_settings_menu_cancel" msgid="6582567330136502340">"Zrušit"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index a72e930..4d2ef70 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -1624,7 +1624,7 @@
<string name="background_data_summary" msgid="8328521479872763452">"Synchronisation, envoi et réception de données à tout moment"</string>
<string name="background_data_dialog_title" msgid="6059217698124786537">"Dés. données arr.-plan ?"</string>
<string name="background_data_dialog_message" msgid="6981661606680941633">"La désactivation des données en arrière-plan économise la batterie et réduit l\'utilisation des données. Certaines applications peuvent continuer d\'utiliser la connexion Internet en arrière-plan."</string>
- <string name="sync_automatically" msgid="1682730255435062059">"Synchro auto des données des applis"</string>
+ <string name="sync_automatically" msgid="1682730255435062059">"Synchro auto"</string>
<string name="sync_enabled" msgid="4551148952179416813">"Synchronisation activée"</string>
<string name="sync_disabled" msgid="8511659877596511991">"Synchronisation désactivée"</string>
<string name="sync_error" msgid="5060969083117872149">"Erreur de synchronisation"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 2802756..afe4038 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -353,7 +353,7 @@
<string name="unlock_set_unlock_off_summary" msgid="94361581669110415"></string>
<string name="unlock_set_unlock_none_title" msgid="2871898266296656162">"הסט"</string>
<string name="unlock_set_unlock_none_summary" msgid="8914673583104628191">"אין אבטחה"</string>
- <string name="unlock_set_unlock_biometric_weak_title" msgid="2227215291604628670">"ביטול נעילת פרצוף"</string>
+ <string name="unlock_set_unlock_biometric_weak_title" msgid="2227215291604628670">"זיהוי פרצוף"</string>
<string name="unlock_set_unlock_biometric_weak_summary" msgid="180083326982058964">"אבטחה נמוכה, ניסיוני"</string>
<string name="unlock_set_unlock_pattern_title" msgid="2912067603917311700">"קו"</string>
<string name="unlock_set_unlock_pattern_summary" msgid="7062696666227725593">"אבטחה בינונית"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index ddedb4a..0aaf258 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -1725,7 +1725,7 @@
<string name="show_all_anrs_summary" msgid="641908614413544127">"バックグラウンドアプリが応答しない場合に通知する"</string>
<string name="experimental_webview" msgid="4492200819033780927">"試験運用版WebViewを使用"</string>
<string name="experimental_webview_summary" msgid="3431620080869482446">"アプリは最新(ベータ版)のWebViewを使用します"</string>
- <string name="data_usage_summary_title" msgid="3804110657238092929">"データ使用"</string>
+ <string name="data_usage_summary_title" msgid="3804110657238092929">"データ使用量"</string>
<string name="data_usage_cycle" msgid="5652529796195787949">"データ使用サイクル"</string>
<string name="data_usage_menu_roaming" msgid="8042359966835203296">"データローミング"</string>
<string name="data_usage_menu_restrict_background" msgid="1989394568592253331">"バックグラウンドデータを制限する"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index cf6e195..5fdff24 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -1720,7 +1720,7 @@
<string name="show_all_anrs_summary" msgid="641908614413544127">"Afiş. dialog. Aplic. nu răsp. pt. aplic. de fundal"</string>
<string name="experimental_webview" msgid="4492200819033780927">"WebView experimental"</string>
<string name="experimental_webview_summary" msgid="3431620080869482446">"Aplicațiile vor utiliza cel mai nou WebView (beta)"</string>
- <string name="data_usage_summary_title" msgid="3804110657238092929">"Rata de utilizare a datelor"</string>
+ <string name="data_usage_summary_title" msgid="3804110657238092929">"Utilizarea datelor"</string>
<string name="data_usage_cycle" msgid="5652529796195787949">"Ciclul de util. a datelor"</string>
<string name="data_usage_menu_roaming" msgid="8042359966835203296">"Roaming de date"</string>
<string name="data_usage_menu_restrict_background" msgid="1989394568592253331">"Restricţionaţi datele de fundal"</string>
@@ -1728,7 +1728,7 @@
<string name="data_usage_menu_show_wifi" msgid="5056401102877964564">"Afișați utilizarea Wi-Fi"</string>
<string name="data_usage_menu_show_ethernet" msgid="5181361208532314097">"Afişaţi utiliz. conex. Ethernet"</string>
<string name="data_usage_menu_metered" msgid="5056695223222541863">"Hotspoturi mobile"</string>
- <string name="data_usage_menu_auto_sync" msgid="8203999775948778560">"Sincronizaţi datele în mod automat"</string>
+ <string name="data_usage_menu_auto_sync" msgid="8203999775948778560">"Sincronizați automat datele"</string>
<string name="data_usage_change_cycle" msgid="7776556448920114866">"Schimbaţi data ciclului..."</string>
<string name="data_usage_pick_cycle_day" msgid="4470796861757050966">"Ziua din lună pentru resetarea ciclului de utilizare a datelor:"</string>
<string name="data_usage_empty" msgid="8621855507876539282">"Nicio aplic. nu a utilizat date în ac. perioadă."</string>
diff --git a/res/values-tr/arrays.xml b/res/values-tr/arrays.xml
index 4073c12..e052fd1 100644
--- a/res/values-tr/arrays.xml
+++ b/res/values-tr/arrays.xml
@@ -278,7 +278,7 @@
<item msgid="785049718065337473">"bildirim sesi düzeyi"</item>
<item msgid="6700305533746877052">"Bluetooth sesi düzeyi"</item>
<item msgid="2029227495214047094">"uyanık tut"</item>
- <item msgid="26109888160231211">"monitör konumu"</item>
+ <item msgid="26109888160231211">"konumu izle"</item>
</string-array>
<string-array name="app_ops_labels">
<item msgid="6602854600289714121">"Konum"</item>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 21a4e04..1d2ba38 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3074,6 +3074,10 @@
<string name="keep_screen_on">Stay awake</string>
<!-- setting Checkbox summary whether to keep the screen on when plugged in -->
<string name="keep_screen_on_summary">Screen will never sleep while charging</string>
+ <!-- Setting Checkbox title whether to enable bluetooth HCI snoop log -->
+ <string name="bt_hci_snoop_log">Enable Bluetooth HCI snoop log</string>
+ <!-- setting Checkbox summary whether to capture all bluetooth HCI packets in a file -->
+ <string name="bt_hci_snoop_log_summary">Capture all bluetooth HCI packets in a file</string>
<!-- Runtime selection title, used for debug purposes only. [CHAR LIMIT=25] -->
<string name="select_runtime_title">Select runtime </string>
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index fa447f2..e2328d3 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -28,7 +28,7 @@
android:title="@string/accessibility_system_title">
<PreferenceScreen
- android:fragment="com.android.settings.AccessibilitySettings$ToggleScreenMagnificationPreferenceFragment"
+ android:fragment="com.android.settings.accessibility.ToggleScreenMagnificationPreferenceFragment"
android:key="screen_magnification_preference_screen"
android:title="@string/accessibility_screen_magnification_title"/>
@@ -53,7 +53,7 @@
android:persistent="false"/>
<PreferenceScreen
- android:fragment="com.android.settings.AccessibilitySettings$ToggleGlobalGesturePreferenceFragment"
+ android:fragment="com.android.settings.accessibility.ToggleGlobalGesturePreferenceFragment"
android:key="enable_global_gesture_preference_screen"
android:title="@string/accessibility_global_gesture_preference_title"/>
diff --git a/res/xml/development_prefs.xml b/res/xml/development_prefs.xml
index eddc411..db003d3 100644
--- a/res/xml/development_prefs.xml
+++ b/res/xml/development_prefs.xml
@@ -56,6 +56,11 @@
android:title="@string/enforce_read_external_title"
android:summary="@string/enforce_read_external_summary" />
+ <CheckBoxPreference
+ android:key="bt_hci_snoop_log"
+ android:title="@string/bt_hci_snoop_log"
+ android:summary="@string/bt_hci_snoop_log_summary"/>
+
<PreferenceCategory android:key="debug_debugging_category"
android:title="@string/debug_debugging_category">
diff --git a/res/xml/settings_headers.xml b/res/xml/settings_headers.xml
index b00ecf5..5d3a39f 100644
--- a/res/xml/settings_headers.xml
+++ b/res/xml/settings_headers.xml
@@ -178,7 +178,7 @@
<!-- Accessibility feedback -->
<header
android:id="@+id/accessibility_settings"
- android:fragment="com.android.settings.AccessibilitySettings"
+ android:fragment="com.android.settings.accessibility.AccessibilitySettings"
android:icon="@drawable/ic_settings_accessibility"
android:title="@string/accessibility_settings" />
diff --git a/src/com/android/settings/AccessibilitySettings.java b/src/com/android/settings/AccessibilitySettings.java
deleted file mode 100644
index f4188f1..0000000
--- a/src/com/android/settings/AccessibilitySettings.java
+++ /dev/null
@@ -1,1133 +0,0 @@
-/*
- * Copyright (C) 2009 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.accessibilityservice.AccessibilityServiceInfo;
-import android.app.ActionBar;
-import android.app.Activity;
-import android.app.ActivityManagerNative;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.res.Configuration;
-import android.database.ContentObserver;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-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;
-import android.text.TextUtils;
-import android.text.TextUtils.SimpleStringSplitter;
-import android.view.Gravity;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-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.ImageView;
-import android.widget.LinearLayout;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.view.RotationPolicy;
-import com.android.settings.AccessibilitySettings.ToggleSwitch.OnBeforeCheckedChangeListener;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Activity with the accessibility settings.
- */
-public class AccessibilitySettings extends SettingsPreferenceFragment implements DialogCreatable,
- Preference.OnPreferenceChangeListener {
- private static final String DEFAULT_SCREENREADER_MARKET_LINK =
- "market://search?q=pname:com.google.android.marvin.talkback";
-
- 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.
- private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000;
-
- private static final char ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':';
-
- 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";
- private static final String TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE =
- "toggle_power_button_ends_call_preference";
- private static final String TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE =
- "toggle_lock_screen_rotation_preference";
- private static final String TOGGLE_SPEAK_PASSWORD_PREFERENCE =
- "toggle_speak_password_preference";
- private static final String SELECT_LONG_PRESS_TIMEOUT_PREFERENCE =
- "select_long_press_timeout_preference";
- private static final String ENABLE_ACCESSIBILITY_GESTURE_PREFERENCE_SCREEN =
- "enable_global_gesture_preference_screen";
- private static final String DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN =
- "screen_magnification_preference_screen";
-
- // Extras passed to sub-fragments.
- 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_SETTINGS_TITLE = "settings_title";
- private static final String EXTRA_COMPONENT_NAME = "component_name";
- private static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
-
- // Dialog IDs.
- private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 1;
-
- // Auxiliary members.
- private final static SimpleStringSplitter sStringColonSplitter =
- new SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
-
- private static final Set<ComponentName> sInstalledServices = new HashSet<ComponentName>();
-
- private final Map<String, String> mLongPressTimeoutValuetoTitleMap =
- new HashMap<String, String>();
-
- private final Configuration mCurConfig = new Configuration();
-
- private final PackageMonitor mSettingsPackageMonitor = new SettingsPackageMonitor();
-
- private final Handler mHandler = new Handler() {
- @Override
- public void dispatchMessage(Message msg) {
- super.dispatchMessage(msg);
- loadInstalledServices();
- updateServicesPreferences();
- }
- };
-
- private final SettingsContentObserver mSettingsContentObserver =
- new SettingsContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- loadInstalledServices();
- updateServicesPreferences();
- }
- };
-
- private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
- new RotationPolicy.RotationPolicyListener() {
- @Override
- public void onChange() {
- updateLockScreenRotationCheckbox();
- }
- };
-
- // Preference controls.
- private PreferenceCategory mServicesCategory;
- private PreferenceCategory mSystemsCategory;
-
- private CheckBoxPreference mToggleLargeTextPreference;
- private CheckBoxPreference mTogglePowerButtonEndsCallPreference;
- private CheckBoxPreference mToggleLockScreenRotationPreference;
- private CheckBoxPreference mToggleSpeakPasswordPreference;
- private ListPreference mSelectLongPressTimeoutPreference;
- private Preference mNoServicesMessagePreference;
- private PreferenceScreen mDisplayMagnificationPreferenceScreen;
- private PreferenceScreen mGlobalGesturePreferenceScreen;
-
- private int mLongPressTimeoutDefault;
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- addPreferencesFromResource(R.xml.accessibility_settings);
- initializeAllPreferences();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- loadInstalledServices();
- updateAllPreferences();
-
- offerInstallAccessibilitySerivceOnce();
-
- mSettingsPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false);
- mSettingsContentObserver.register(getContentResolver());
- if (RotationPolicy.isRotationSupported(getActivity())) {
- RotationPolicy.registerRotationPolicyListener(getActivity(),
- mRotationPolicyListener);
- }
- }
-
- @Override
- public void onPause() {
- mSettingsPackageMonitor.unregister();
- mSettingsContentObserver.unregister(getContentResolver());
- if (RotationPolicy.isRotationSupported(getActivity())) {
- RotationPolicy.unregisterRotationPolicyListener(getActivity(),
- mRotationPolicyListener);
- }
- super.onPause();
- }
-
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (preference == mSelectLongPressTimeoutPreference) {
- String stringValue = (String) newValue;
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.LONG_PRESS_TIMEOUT, Integer.parseInt(stringValue));
- mSelectLongPressTimeoutPreference.setSummary(
- mLongPressTimeoutValuetoTitleMap.get(stringValue));
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- if (mToggleLargeTextPreference == preference) {
- handleToggleLargeTextPreferenceClick();
- return true;
- } else if (mTogglePowerButtonEndsCallPreference == preference) {
- handleTogglePowerButtonEndsCallPreferenceClick();
- return true;
- } else if (mToggleLockScreenRotationPreference == preference) {
- handleLockScreenRotationPreferenceClick();
- return true;
- } else if (mToggleSpeakPasswordPreference == preference) {
- handleToggleSpeakPasswordPreferenceClick();
- return true;
- } else if (mGlobalGesturePreferenceScreen == preference) {
- handleTogglEnableAccessibilityGesturePreferenceClick();
- return true;
- } else if (mDisplayMagnificationPreferenceScreen == preference) {
- handleDisplayMagnificationPreferenceScreenClick();
- return true;
- }
- return super.onPreferenceTreeClick(preferenceScreen, preference);
- }
-
- private void handleToggleLargeTextPreferenceClick() {
- try {
- mCurConfig.fontScale = mToggleLargeTextPreference.isChecked() ? LARGE_FONT_SCALE : 1;
- ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig);
- } catch (RemoteException re) {
- /* ignore */
- }
- }
-
- 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 handleLockScreenRotationPreferenceClick() {
- RotationPolicy.setRotationLockForAccessibility(getActivity(),
- !mToggleLockScreenRotationPreference.isChecked());
- }
-
- private void handleToggleSpeakPasswordPreferenceClick() {
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD,
- mToggleSpeakPasswordPreference.isChecked() ? 1 : 0);
- }
-
- private void handleTogglEnableAccessibilityGesturePreferenceClick() {
- Bundle extras = mGlobalGesturePreferenceScreen.getExtras();
- extras.putString(EXTRA_TITLE, getString(
- R.string.accessibility_global_gesture_preference_title));
- extras.putString(EXTRA_SUMMARY, getString(
- R.string.accessibility_global_gesture_preference_description));
- extras.putBoolean(EXTRA_CHECKED, Settings.Global.getInt(getContentResolver(),
- Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1);
- super.onPreferenceTreeClick(mGlobalGesturePreferenceScreen,
- mGlobalGesturePreferenceScreen);
- }
-
- private void handleDisplayMagnificationPreferenceScreenClick() {
- Bundle extras = mDisplayMagnificationPreferenceScreen.getExtras();
- extras.putString(EXTRA_TITLE, getString(
- R.string.accessibility_screen_magnification_title));
- extras.putCharSequence(EXTRA_SUMMARY, getActivity().getResources().getText(
- R.string.accessibility_screen_magnification_summary));
- extras.putBoolean(EXTRA_CHECKED, Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0) == 1);
- super.onPreferenceTreeClick(mDisplayMagnificationPreferenceScreen,
- mDisplayMagnificationPreferenceScreen);
- }
-
- private void initializeAllPreferences() {
- mServicesCategory = (PreferenceCategory) findPreference(SERVICES_CATEGORY);
- mSystemsCategory = (PreferenceCategory) findPreference(SYSTEM_CATEGORY);
-
- // Large text.
- mToggleLargeTextPreference =
- (CheckBoxPreference) findPreference(TOGGLE_LARGE_TEXT_PREFERENCE);
-
- // Power button ends calls.
- mTogglePowerButtonEndsCallPreference =
- (CheckBoxPreference) findPreference(TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE);
- if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
- || !Utils.isVoiceCapable(getActivity())) {
- mSystemsCategory.removePreference(mTogglePowerButtonEndsCallPreference);
- }
-
- // Lock screen rotation.
- mToggleLockScreenRotationPreference =
- (CheckBoxPreference) findPreference(TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE);
- if (!RotationPolicy.isRotationSupported(getActivity())) {
- mSystemsCategory.removePreference(mToggleLockScreenRotationPreference);
- }
-
- // Speak passwords.
- mToggleSpeakPasswordPreference =
- (CheckBoxPreference) findPreference(TOGGLE_SPEAK_PASSWORD_PREFERENCE);
-
- // 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]);
- }
- }
-
- // Display magnification.
- mDisplayMagnificationPreferenceScreen = (PreferenceScreen) findPreference(
- DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN);
-
- // Global gesture.
- mGlobalGesturePreferenceScreen =
- (PreferenceScreen) findPreference(ENABLE_ACCESSIBILITY_GESTURE_PREFERENCE_SCREEN);
- final int longPressOnPowerBehavior = getActivity().getResources().getInteger(
- com.android.internal.R.integer.config_longPressOnPowerBehavior);
- final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
- if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
- || longPressOnPowerBehavior != LONG_PRESS_POWER_GLOBAL_ACTIONS) {
- // Remove accessibility shortcut if power key is not present
- // nor long press power does not show global actions menu.
- mSystemsCategory.removePreference(mGlobalGesturePreferenceScreen);
- }
- }
-
- private void updateAllPreferences() {
- updateServicesPreferences();
- updateSystemPreferences();
- }
-
- private void updateServicesPreferences() {
- // 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());
-
- List<AccessibilityServiceInfo> installedServices =
- accessibilityManager.getInstalledAccessibilityServiceList();
- Set<ComponentName> enabledServices = getEnabledServicesFromSettings(getActivity());
-
- final boolean accessibilityEnabled = Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
-
- for (int i = 0, count = installedServices.size(); i < count; ++i) {
- AccessibilityServiceInfo info = installedServices.get(i);
-
- PreferenceScreen preference = getPreferenceManager().createPreferenceScreen(
- getActivity());
- String title = info.getResolveInfo().loadLabel(getPackageManager()).toString();
-
- ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
- ComponentName componentName = new ComponentName(serviceInfo.packageName,
- serviceInfo.name);
-
- preference.setKey(componentName.flattenToString());
-
- preference.setTitle(title);
- final boolean serviceEnabled = accessibilityEnabled
- && enabledServices.contains(componentName);
- if (serviceEnabled) {
- preference.setSummary(getString(R.string.accessibility_feature_state_on));
- } else {
- preference.setSummary(getString(R.string.accessibility_feature_state_off));
- }
-
- preference.setOrder(i);
- preference.setFragment(ToggleAccessibilityServicePreferenceFragment.class.getName());
- preference.setPersistent(true);
-
- Bundle extras = preference.getExtras();
- extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey());
- extras.putBoolean(EXTRA_CHECKED, serviceEnabled);
- extras.putString(EXTRA_TITLE, title);
-
- String description = info.loadDescription(getPackageManager());
- if (TextUtils.isEmpty(description)) {
- description = getString(R.string.accessibility_service_default_description);
- }
- extras.putString(EXTRA_SUMMARY, description);
-
- String settingsClassName = info.getSettingsActivityName();
- if (!TextUtils.isEmpty(settingsClassName)) {
- extras.putString(EXTRA_SETTINGS_TITLE,
- getString(R.string.accessibility_menu_item_settings));
- extras.putString(EXTRA_SETTINGS_COMPONENT_NAME,
- new ComponentName(info.getResolveInfo().serviceInfo.packageName,
- settingsClassName).flattenToString());
- }
-
- extras.putParcelable(EXTRA_COMPONENT_NAME, componentName);
-
- mServicesCategory.addPreference(preference);
- }
-
- if (mServicesCategory.getPreferenceCount() == 0) {
- if (mNoServicesMessagePreference == null) {
- mNoServicesMessagePreference = new Preference(getActivity()) {
- @Override
- protected void onBindView(View view) {
- super.onBindView(view);
- TextView summaryView = (TextView) view.findViewById(R.id.summary);
- String title = getString(R.string.accessibility_no_services_installed);
- summaryView.setText(title);
- }
- };
- mNoServicesMessagePreference.setPersistent(false);
- mNoServicesMessagePreference.setLayoutResource(
- R.layout.text_description_preference);
- mNoServicesMessagePreference.setSelectable(false);
- }
- mServicesCategory.addPreference(mNoServicesMessagePreference);
- }
- }
-
- private void updateSystemPreferences() {
- // Large text.
- try {
- mCurConfig.updateFrom(ActivityManagerNative.getDefault().getConfiguration());
- } catch (RemoteException re) {
- /* ignore */
- }
- mToggleLargeTextPreference.setChecked(mCurConfig.fontScale == LARGE_FONT_SCALE);
-
- // Power button ends calls.
- 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);
- }
-
- // Auto-rotate screen
- updateLockScreenRotationCheckbox();
-
- // Speak passwords.
- final boolean speakPasswordEnabled = Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0;
- mToggleSpeakPasswordPreference.setChecked(speakPasswordEnabled);
-
- // Long press timeout.
- 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));
-
- // Screen magnification.
- final boolean magnificationEnabled = Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0) == 1;
- if (magnificationEnabled) {
- mDisplayMagnificationPreferenceScreen.setSummary(
- R.string.accessibility_feature_state_on);
- } else {
- mDisplayMagnificationPreferenceScreen.setSummary(
- R.string.accessibility_feature_state_off);
- }
-
- // Global gesture
- final boolean globalGestureEnabled = Settings.Global.getInt(getContentResolver(),
- Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1;
- if (globalGestureEnabled) {
- mGlobalGesturePreferenceScreen.setSummary(
- R.string.accessibility_global_gesture_preference_summary_on);
- } else {
- mGlobalGesturePreferenceScreen.setSummary(
- R.string.accessibility_global_gesture_preference_summary_off);
- }
- }
-
- private void updateLockScreenRotationCheckbox() {
- Context context = getActivity();
- if (context != null) {
- mToggleLockScreenRotationPreference.setChecked(
- !RotationPolicy.isRotationLocked(context));
- }
- }
-
- private void offerInstallAccessibilitySerivceOnce() {
- // There is always one preference - if no services it is just a message.
- if (mServicesCategory.getPreference(0) != mNoServicesMessagePreference) {
- return;
- }
- SharedPreferences preferences = getActivity().getPreferences(Context.MODE_PRIVATE);
- final boolean offerInstallService = !preferences.getBoolean(
- KEY_INSTALL_ACCESSIBILITY_SERVICE_OFFERED_ONCE, false);
- if (offerInstallService) {
- String screenreaderMarketLink = SystemProperties.get(
- SYSTEM_PROPERTY_MARKET_URL,
- DEFAULT_SCREENREADER_MARKET_LINK);
- Uri marketUri = Uri.parse(screenreaderMarketLink);
- Intent marketIntent = new Intent(Intent.ACTION_VIEW, marketUri);
-
- if (getPackageManager().resolveActivity(marketIntent, 0) == null) {
- // Don't show the dialog if no market app is found/installed.
- return;
- }
-
- 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);
- }
- }
-
- @Override
- public Dialog onCreateDialog(int dialogId) {
- switch (dialogId) {
- case DIALOG_ID_NO_ACCESSIBILITY_SERVICES:
- return new AlertDialog.Builder(getActivity())
- .setTitle(R.string.accessibility_service_no_apps_title)
- .setMessage(R.string.accessibility_service_no_apps_message)
- .setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // dismiss the dialog before launching
- // the activity otherwise
- // the dialog removal occurs after
- // onSaveInstanceState which
- // triggers an exception
- removeDialog(DIALOG_ID_NO_ACCESSIBILITY_SERVICES);
- String screenreaderMarketLink = SystemProperties.get(
- SYSTEM_PROPERTY_MARKET_URL,
- DEFAULT_SCREENREADER_MARKET_LINK);
- Uri marketUri = Uri.parse(screenreaderMarketLink);
- Intent marketIntent = new Intent(Intent.ACTION_VIEW,
- marketUri);
- startActivity(marketIntent);
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .create();
- default:
- return null;
- }
- }
-
- private void loadInstalledServices() {
- Set<ComponentName> installedServices = sInstalledServices;
- installedServices.clear();
-
- List<AccessibilityServiceInfo> installedServiceInfos =
- AccessibilityManager.getInstance(getActivity())
- .getInstalledAccessibilityServiceList();
- if (installedServiceInfos == null) {
- return;
- }
-
- final int installedServiceInfoCount = installedServiceInfos.size();
- for (int i = 0; i < installedServiceInfoCount; i++) {
- ResolveInfo resolveInfo = installedServiceInfos.get(i).getResolveInfo();
- ComponentName installedService = new ComponentName(
- resolveInfo.serviceInfo.packageName,
- resolveInfo.serviceInfo.name);
- installedServices.add(installedService);
- }
- }
-
- private static Set<ComponentName> getEnabledServicesFromSettings(Context context) {
- String enabledServicesSetting = Settings.Secure.getString(context.getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
- if (enabledServicesSetting == null) {
- enabledServicesSetting = "";
- }
- Set<ComponentName> enabledServices = new HashSet<ComponentName>();
- SimpleStringSplitter colonSplitter = sStringColonSplitter;
- colonSplitter.setString(enabledServicesSetting);
- while (colonSplitter.hasNext()) {
- String componentNameString = colonSplitter.next();
- ComponentName enabledService = ComponentName.unflattenFromString(
- componentNameString);
- if (enabledService != null) {
- enabledServices.add(enabledService);
- }
- }
- return enabledServices;
- }
-
- private class SettingsPackageMonitor extends PackageMonitor {
-
- @Override
- public void onPackageAdded(String packageName, int uid) {
- Message message = mHandler.obtainMessage();
- mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_MILLIS);
- }
-
- @Override
- public void onPackageAppeared(String packageName, int reason) {
- Message message = mHandler.obtainMessage();
- mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_MILLIS);
- }
-
- @Override
- public void onPackageDisappeared(String packageName, int reason) {
- Message message = mHandler.obtainMessage();
- mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_MILLIS);
- }
-
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- Message message = mHandler.obtainMessage();
- mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_MILLIS);
- }
- }
-
- public static class ToggleSwitch extends Switch {
-
- private OnBeforeCheckedChangeListener mOnBeforeListener;
-
- public static interface OnBeforeCheckedChangeListener {
- public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked);
- }
-
- public ToggleSwitch(Context context) {
- super(context);
- }
-
- public void setOnBeforeCheckedChangeListener(OnBeforeCheckedChangeListener listener) {
- mOnBeforeListener = listener;
- }
-
- @Override
- public void setChecked(boolean checked) {
- if (mOnBeforeListener != null
- && mOnBeforeListener.onBeforeCheckedChanged(this, checked)) {
- return;
- }
- super.setChecked(checked);
- }
-
- public void setCheckedInternal(boolean checked) {
- super.setChecked(checked);
- }
- }
-
- public static class ToggleAccessibilityServicePreferenceFragment
- extends ToggleFeaturePreferenceFragment implements DialogInterface.OnClickListener {
-
- private static final int DIALOG_ID_ENABLE_WARNING = 1;
- private static final int DIALOG_ID_DISABLE_WARNING = 2;
-
- private final SettingsContentObserver mSettingsContentObserver =
- new SettingsContentObserver(new Handler()) {
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- String settingValue = Settings.Secure.getString(getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
- final boolean enabled = settingValue.contains(mComponentName.flattenToString());
- mToggleSwitch.setCheckedInternal(enabled);
- }
- };
-
- private ComponentName mComponentName;
-
- private int mShownDialogId;
-
- @Override
- public void onResume() {
- mSettingsContentObserver.register(getContentResolver());
- super.onResume();
- }
-
- @Override
- public void onPause() {
- mSettingsContentObserver.unregister(getContentResolver());
- super.onPause();
- }
-
- @Override
- public void onPreferenceToggled(String preferenceKey, boolean enabled) {
- // Parse the enabled services.
- Set<ComponentName> enabledServices = getEnabledServicesFromSettings(getActivity());
-
- // Determine enabled services and accessibility state.
- ComponentName toggledService = ComponentName.unflattenFromString(preferenceKey);
- boolean accessibilityEnabled = false;
- if (enabled) {
- enabledServices.add(toggledService);
- // Enabling at least one service enables accessibility.
- accessibilityEnabled = true;
- } else {
- enabledServices.remove(toggledService);
- // Check how many enabled and installed services are present.
- Set<ComponentName> installedServices = sInstalledServices;
- for (ComponentName enabledService : enabledServices) {
- if (installedServices.contains(enabledService)) {
- // Disabling the last service disables accessibility.
- accessibilityEnabled = true;
- break;
- }
- }
- }
-
- // Update the enabled services setting.
- StringBuilder enabledServicesBuilder = new StringBuilder();
- // Keep the enabled services even if they are not installed since we
- // have no way to know whether the application restore process has
- // completed. In general the system should be responsible for the
- // clean up not settings.
- for (ComponentName enabledService : enabledServices) {
- enabledServicesBuilder.append(enabledService.flattenToString());
- enabledServicesBuilder.append(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
- }
- final int enabledServicesBuilderLength = enabledServicesBuilder.length();
- if (enabledServicesBuilderLength > 0) {
- enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1);
- }
- Settings.Secure.putString(getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- enabledServicesBuilder.toString());
-
- // Update accessibility enabled.
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_ENABLED, accessibilityEnabled ? 1 : 0);
- }
-
- // IMPORTANT: Refresh the info since there are dynamically changing capabilities. For
- // example, before JellyBean MR2 the user was granting the explore by touch one.
- private AccessibilityServiceInfo getAccessibilityServiceInfo() {
- List<AccessibilityServiceInfo> serviceInfos = AccessibilityManager.getInstance(
- getActivity()).getInstalledAccessibilityServiceList();
- final int serviceInfoCount = serviceInfos.size();
- for (int i = 0; i < serviceInfoCount; i++) {
- AccessibilityServiceInfo serviceInfo = serviceInfos.get(i);
- ResolveInfo resolveInfo = serviceInfo.getResolveInfo();
- if (mComponentName.getPackageName().equals(resolveInfo.serviceInfo.packageName)
- && mComponentName.getClassName().equals(resolveInfo.serviceInfo.name)) {
- return serviceInfo;
- }
- }
- return null;
- }
-
- @Override
- public Dialog onCreateDialog(int dialogId) {
- switch (dialogId) {
- case DIALOG_ID_ENABLE_WARNING: {
- mShownDialogId = DIALOG_ID_ENABLE_WARNING;
- AccessibilityServiceInfo info = getAccessibilityServiceInfo();
- if (info == null) {
- return null;
- }
- return new AlertDialog.Builder(getActivity())
- .setTitle(getString(R.string.enable_service_title,
- info.getResolveInfo().loadLabel(getPackageManager())))
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .setView(createEnableDialogContentView(info))
- .setCancelable(true)
- .setPositiveButton(android.R.string.ok, this)
- .setNegativeButton(android.R.string.cancel, this)
- .create();
- }
- case DIALOG_ID_DISABLE_WARNING: {
- mShownDialogId = DIALOG_ID_DISABLE_WARNING;
- AccessibilityServiceInfo info = getAccessibilityServiceInfo();
- if (info == null) {
- return null;
- }
- return new AlertDialog.Builder(getActivity())
- .setTitle(getString(R.string.disable_service_title,
- info.getResolveInfo().loadLabel(getPackageManager())))
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .setMessage(getString(R.string.disable_service_message,
- info.getResolveInfo().loadLabel(getPackageManager())))
- .setCancelable(true)
- .setPositiveButton(android.R.string.ok, this)
- .setNegativeButton(android.R.string.cancel, this)
- .create();
- }
- default: {
- throw new IllegalArgumentException();
- }
- }
- }
-
- private View createEnableDialogContentView(AccessibilityServiceInfo info) {
- LayoutInflater inflater = (LayoutInflater) getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
-
- View content = inflater.inflate(R.layout.enable_accessibility_service_dialog_content,
- null);
-
- TextView capabilitiesHeaderView = (TextView) content.findViewById(
- R.id.capabilities_header);
- capabilitiesHeaderView.setText(getString(R.string.capabilities_list_title,
- info.getResolveInfo().loadLabel(getPackageManager())));
-
- LinearLayout capabilitiesView = (LinearLayout) content.findViewById(R.id.capabilities);
-
- // This capability is implicit for all services.
- View capabilityView = inflater.inflate(
- com.android.internal.R.layout.app_permission_item_old, null);
-
- ImageView imageView = (ImageView) capabilityView.findViewById(
- com.android.internal.R.id.perm_icon);
- imageView.setImageDrawable(getResources().getDrawable(
- com.android.internal.R.drawable.ic_text_dot));
-
- TextView labelView = (TextView) capabilityView.findViewById(
- com.android.internal.R.id.permission_group);
- labelView.setText(getString(R.string.capability_title_receiveAccessibilityEvents));
-
- TextView descriptionView = (TextView) capabilityView.findViewById(
- com.android.internal.R.id.permission_list);
- descriptionView.setText(getString(R.string.capability_desc_receiveAccessibilityEvents));
-
- List<AccessibilityServiceInfo.CapabilityInfo> capabilities =
- info.getCapabilityInfos();
-
- capabilitiesView.addView(capabilityView);
-
- // Service specific capabilities.
- final int capabilityCount = capabilities.size();
- for (int i = 0; i < capabilityCount; i++) {
- AccessibilityServiceInfo.CapabilityInfo capability = capabilities.get(i);
-
- capabilityView = inflater.inflate(
- com.android.internal.R.layout.app_permission_item_old, null);
-
- imageView = (ImageView) capabilityView.findViewById(
- com.android.internal.R.id.perm_icon);
- imageView.setImageDrawable(getResources().getDrawable(
- com.android.internal.R.drawable.ic_text_dot));
-
- labelView = (TextView) capabilityView.findViewById(
- com.android.internal.R.id.permission_group);
- labelView.setText(getString(capability.titleResId));
-
- descriptionView = (TextView) capabilityView.findViewById(
- com.android.internal.R.id.permission_list);
- descriptionView.setText(getString(capability.descResId));
-
- capabilitiesView.addView(capabilityView);
- }
-
- return content;
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- final boolean checked;
- switch (which) {
- case DialogInterface.BUTTON_POSITIVE:
- checked = (mShownDialogId == DIALOG_ID_ENABLE_WARNING);
- mToggleSwitch.setCheckedInternal(checked);
- getArguments().putBoolean(EXTRA_CHECKED, checked);
- onPreferenceToggled(mPreferenceKey, checked);
- break;
- case DialogInterface.BUTTON_NEGATIVE:
- checked = (mShownDialogId == DIALOG_ID_DISABLE_WARNING);
- mToggleSwitch.setCheckedInternal(checked);
- getArguments().putBoolean(EXTRA_CHECKED, checked);
- onPreferenceToggled(mPreferenceKey, checked);
- break;
- default:
- throw new IllegalArgumentException();
- }
- }
-
- @Override
- protected void onInstallActionBarToggleSwitch() {
- super.onInstallActionBarToggleSwitch();
- mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
- @Override
- public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
- if (checked) {
- toggleSwitch.setCheckedInternal(false);
- getArguments().putBoolean(EXTRA_CHECKED, false);
- showDialog(DIALOG_ID_ENABLE_WARNING);
- } else {
- toggleSwitch.setCheckedInternal(true);
- getArguments().putBoolean(EXTRA_CHECKED, true);
- showDialog(DIALOG_ID_DISABLE_WARNING);
- }
- return true;
- }
- });
- }
-
- @Override
- protected void onProcessArguments(Bundle arguments) {
- super.onProcessArguments(arguments);
- // Settings title and intent.
- String settingsTitle = arguments.getString(EXTRA_SETTINGS_TITLE);
- String settingsComponentName = arguments.getString(EXTRA_SETTINGS_COMPONENT_NAME);
- if (!TextUtils.isEmpty(settingsTitle) && !TextUtils.isEmpty(settingsComponentName)) {
- Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent(
- ComponentName.unflattenFromString(settingsComponentName.toString()));
- if (!getPackageManager().queryIntentActivities(settingsIntent, 0).isEmpty()) {
- mSettingsTitle = settingsTitle;
- mSettingsIntent = settingsIntent;
- setHasOptionsMenu(true);
- }
- }
-
- mComponentName = arguments.getParcelable(EXTRA_COMPONENT_NAME);
- }
- }
-
- public static class ToggleScreenMagnificationPreferenceFragment
- extends ToggleFeaturePreferenceFragment {
- @Override
- protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, enabled? 1 : 0);
- }
-
- @Override
- protected void onInstallActionBarToggleSwitch() {
- super.onInstallActionBarToggleSwitch();
- mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
- @Override
- public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
- toggleSwitch.setCheckedInternal(checked);
- getArguments().putBoolean(EXTRA_CHECKED, checked);
- onPreferenceToggled(mPreferenceKey, checked);
- return false;
- }
- });
- }
- }
-
- public static class ToggleGlobalGesturePreferenceFragment
- extends ToggleFeaturePreferenceFragment {
- @Override
- protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
- Settings.Global.putInt(getContentResolver(),
- Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, enabled ? 1 : 0);
- }
-
- @Override
- protected void onInstallActionBarToggleSwitch() {
- super.onInstallActionBarToggleSwitch();
- mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
- @Override
- public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
- toggleSwitch.setCheckedInternal(checked);
- getArguments().putBoolean(EXTRA_CHECKED, checked);
- onPreferenceToggled(mPreferenceKey, checked);
- return false;
- }
- });
- }
- }
-
- public static abstract class ToggleFeaturePreferenceFragment
- extends SettingsPreferenceFragment {
-
- protected ToggleSwitch mToggleSwitch;
-
- protected String mPreferenceKey;
- protected Preference mSummaryPreference;
-
- protected CharSequence mSettingsTitle;
- protected Intent mSettingsIntent;
-
- // 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) {
- super.onCreate(savedInstanceState);
- PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(
- getActivity());
- setPreferenceScreen(preferenceScreen);
- mSummaryPreference = new Preference(getActivity()) {
- @Override
- protected void onBindView(View view) {
- 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);
- mSummaryPreference.setLayoutResource(R.layout.text_description_preference);
- preferenceScreen.addPreference(mSummaryPreference);
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- onInstallActionBarToggleSwitch();
- onProcessArguments(getArguments());
- // Set a transparent drawable to prevent use of the default one.
- getListView().setSelector(new ColorDrawable(Color.TRANSPARENT));
- getListView().setDivider(null);
- }
-
- @Override
- public void onDestroyView() {
- getActivity().getActionBar().setCustomView(null);
- if (mOldActivityTitle != null) {
- getActivity().getActionBar().setTitle(mOldActivityTitle);
- }
- mToggleSwitch.setOnBeforeCheckedChangeListener(null);
- super.onDestroyView();
- }
-
- protected abstract void onPreferenceToggled(String preferenceKey, boolean enabled);
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- super.onCreateOptionsMenu(menu, inflater);
- MenuItem menuItem = menu.add(mSettingsTitle);
- menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- menuItem.setIntent(mSettingsIntent);
- }
-
- protected void onInstallActionBarToggleSwitch() {
- mToggleSwitch = createAndAddActionBarToggleSwitch(getActivity());
- }
-
- private ToggleSwitch createAndAddActionBarToggleSwitch(Activity activity) {
- ToggleSwitch toggleSwitch = new ToggleSwitch(activity);
- final int padding = activity.getResources().getDimensionPixelSize(
- R.dimen.action_bar_switch_padding);
- toggleSwitch.setPaddingRelative(0, 0, padding, 0);
- activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
- ActionBar.DISPLAY_SHOW_CUSTOM);
- activity.getActionBar().setCustomView(toggleSwitch,
- new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT,
- ActionBar.LayoutParams.WRAP_CONTENT,
- Gravity.CENTER_VERTICAL | Gravity.END));
- return toggleSwitch;
- }
-
- protected void onProcessArguments(Bundle arguments) {
- // Key.
- mPreferenceKey = arguments.getString(EXTRA_PREFERENCE_KEY);
- // Enabled.
- final boolean enabled = arguments.getBoolean(EXTRA_CHECKED);
- mToggleSwitch.setCheckedInternal(enabled);
- // Title.
- PreferenceActivity activity = (PreferenceActivity) getActivity();
- if (!activity.onIsMultiPane() || activity.onIsHidingHeaders()) {
- mOldActivityTitle = getActivity().getTitle();
- String title = arguments.getString(EXTRA_TITLE);
- getActivity().getActionBar().setTitle(title);
- }
- // Summary.
- CharSequence summary = arguments.getCharSequence(EXTRA_SUMMARY);
- mSummaryPreference.setSummary(summary);
- }
- }
-
- private static abstract class SettingsContentObserver extends ContentObserver {
-
- public SettingsContentObserver(Handler handler) {
- super(handler);
- }
-
- public void register(ContentResolver contentResolver) {
- contentResolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_ENABLED), false, this);
- contentResolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES), false, this);
- }
-
- public void unregister(ContentResolver contentResolver) {
- contentResolver.unregisterContentObserver(this);
- }
-
- @Override
- public abstract void onChange(boolean selfChange, Uri uri);
- }
-}
diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java
index a7ad1f7..8ed9a7e 100644
--- a/src/com/android/settings/DevelopmentSettings.java
+++ b/src/com/android/settings/DevelopmentSettings.java
@@ -27,6 +27,7 @@
import android.app.DialogFragment;
import android.app.admin.DevicePolicyManager;
import android.app.backup.IBackupManager;
+import android.bluetooth.BluetoothAdapter;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
@@ -97,6 +98,7 @@
private static final String CLEAR_ADB_KEYS = "clear_adb_keys";
private static final String ENABLE_TERMINAL = "enable_terminal";
private static final String KEEP_SCREEN_ON = "keep_screen_on";
+ private static final String BT_HCI_SNOOP_LOG = "bt_hci_snoop_log";
private static final String SELECT_RUNTIME_KEY = "select_runtime";
private static final String SELECT_RUNTIME_PROPERTY = "persist.sys.dalvik.vm.lib";
private static final String ALLOW_MOCK_LOCATION = "allow_mock_location";
@@ -167,6 +169,7 @@
private Preference mBugreport;
private CheckBoxPreference mBugreportInPower;
private CheckBoxPreference mKeepScreenOn;
+ private CheckBoxPreference mBtHciSnoopLog;
private CheckBoxPreference mEnforceReadExternal;
private CheckBoxPreference mAllowMockLocation;
private PreferenceScreen mPassword;
@@ -252,6 +255,7 @@
mBugreport = findPreference(BUGREPORT);
mBugreportInPower = findAndInitCheckboxPref(BUGREPORT_IN_POWER_KEY);
mKeepScreenOn = findAndInitCheckboxPref(KEEP_SCREEN_ON);
+ mBtHciSnoopLog = findAndInitCheckboxPref(BT_HCI_SNOOP_LOG);
mEnforceReadExternal = findAndInitCheckboxPref(ENFORCE_READ_EXTERNAL);
mAllowMockLocation = findAndInitCheckboxPref(ALLOW_MOCK_LOCATION);
mPassword = (PreferenceScreen) findPreference(LOCAL_BACKUP_PASSWORD);
@@ -477,6 +481,8 @@
Settings.Secure.BUGREPORT_IN_POWER_MENU, 0) != 0);
updateCheckBox(mKeepScreenOn, Settings.Global.getInt(cr,
Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0) != 0);
+ updateCheckBox(mBtHciSnoopLog, Settings.Secure.getInt(cr,
+ Settings.Secure.BLUETOOTH_HCI_LOG, 0) != 0);
updateCheckBox(mEnforceReadExternal, isPermissionEnforced(READ_EXTERNAL_STORAGE));
updateCheckBox(mAllowMockLocation, Settings.Secure.getInt(cr,
Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0);
@@ -607,6 +613,14 @@
}
}
+ private void writeBtHciSnoopLogOptions() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ adapter.configHciSnoopLog(mBtHciSnoopLog.isChecked());
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.BLUETOOTH_HCI_LOG,
+ mBtHciSnoopLog.isChecked() ? 1 : 0);
+ }
+
private void writeDebuggerOptions() {
try {
ActivityManagerNative.getDefault().setDebugApp(
@@ -1191,6 +1205,8 @@
Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
mKeepScreenOn.isChecked() ?
(BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB) : 0);
+ } else if (preference == mBtHciSnoopLog) {
+ writeBtHciSnoopLogOptions();
} else if (preference == mEnforceReadExternal) {
if (mEnforceReadExternal.isChecked()) {
ConfirmEnforceFragment.show(this);
diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java
index 495f3fd..3777a8e 100644
--- a/src/com/android/settings/MasterClear.java
+++ b/src/com/android/settings/MasterClear.java
@@ -29,6 +29,7 @@
import android.os.Bundle;
import android.os.Environment;
import android.os.SystemProperties;
+import android.os.UserManager;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.util.Log;
@@ -54,6 +55,7 @@
private static final String TAG = "MasterClear";
private static final int KEYGUARD_REQUEST = 55;
+ private static final int PIN_REQUEST = 56;
static final String ERASE_EXTERNAL_EXTRA = "erase_sd";
@@ -61,6 +63,7 @@
private Button mInitiateButton;
private View mExternalStorageContainer;
private CheckBox mExternalStorage;
+ private boolean mPinConfirmed;
/**
* Keyguard validation is run using the standard {@link ConfirmLockPattern}
@@ -76,11 +79,25 @@
res.getText(R.string.master_clear_gesture_explanation));
}
+ private boolean runRestrictionsChallenge() {
+ if (UserManager.get(getActivity()).hasRestrictionsPin()) {
+ startActivityForResult(
+ new Intent(Intent.ACTION_RESTRICTIONS_PIN_CHALLENGE), PIN_REQUEST);
+ return true;
+ }
+ return false;
+ }
+
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
- if (requestCode != KEYGUARD_REQUEST) {
+ if (requestCode == PIN_REQUEST) {
+ if (resultCode == Activity.RESULT_OK) {
+ mPinConfirmed = true;
+ }
+ return;
+ } else if (requestCode != KEYGUARD_REQUEST) {
return;
}
@@ -109,6 +126,10 @@
private final Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
public void onClick(View v) {
+ mPinConfirmed = false;
+ if (runRestrictionsChallenge()) {
+ return;
+ }
if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
showFinalConfirmation();
}
@@ -239,4 +260,17 @@
establishInitialState();
return mContentView;
}
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ // If this is the second step after restrictions pin challenge
+ if (mPinConfirmed) {
+ mPinConfirmed = false;
+ if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
+ showFinalConfirmation();
+ }
+ }
+ }
}
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 24ffc50..e90b1cd 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -53,7 +53,7 @@
import android.widget.TextView;
import com.android.internal.util.ArrayUtils;
-import com.android.settings.AccessibilitySettings.ToggleAccessibilityServicePreferenceFragment;
+import com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment;
import com.android.settings.accounts.AccountSyncSettings;
import com.android.settings.accounts.AuthenticatorHelper;
import com.android.settings.accounts.ManageAccountsSettings;
@@ -488,7 +488,8 @@
target.remove(i);
}
} else if (id == R.id.restriction_settings) {
- if (um.isLinkedUser()) {
+ if (um.isLinkedUser()
+ || um.hasUserRestriction(UserManager.DISALLOW_APP_RESTRICTIONS)) {
target.remove(i);
}
}
diff --git a/src/com/android/settings/UserDictionarySettings.java b/src/com/android/settings/UserDictionarySettings.java
index b156105..9f6df50 100644
--- a/src/com/android/settings/UserDictionarySettings.java
+++ b/src/com/android/settings/UserDictionarySettings.java
@@ -38,6 +38,7 @@
import android.widget.TextView;
import com.android.settings.inputmethod.UserDictionaryAddWordContents;
+import com.android.settings.inputmethod.UserDictionarySettingsUtils;
import java.util.Locale;
@@ -115,7 +116,9 @@
listView.setEmptyView(emptyView);
setHasOptionsMenu(true);
-
+ // Show the language as a subtitle of the action bar
+ getActivity().getActionBar().setSubtitle(
+ UserDictionarySettingsUtils.getLocaleDisplayName(getActivity(), mLocale));
}
private Cursor createCursor(final String locale) {
diff --git a/src/com/android/settings/WirelessSettings.java b/src/com/android/settings/WirelessSettings.java
index a3684be..1f29927 100644
--- a/src/com/android/settings/WirelessSettings.java
+++ b/src/com/android/settings/WirelessSettings.java
@@ -45,7 +45,7 @@
import com.android.settings.NsdEnabler;
public class WirelessSettings extends SettingsPreferenceFragment {
- private static final String TAG = "WirelessSettiings";
+ private static final String TAG = "WirelessSettings";
private static final String KEY_TOGGLE_AIRPLANE = "toggle_airplane";
private static final String KEY_TOGGLE_NFC = "toggle_nfc";
@@ -106,7 +106,7 @@
NetworkInfo ni = mCm.getActiveNetworkInfo();
if (mTm.hasIccCard() && (ni != null)) {
// Get provisioning URL
- String url = getProvisioningUrl();
+ String url = mCm.getMobileProvisioningUrl();
if (!TextUtils.isEmpty(url)) {
// Send user to provisioning webpage
Intent intent = new Intent(Intent.ACTION_VIEW);
@@ -145,26 +145,6 @@
}
}
- private String getProvisioningUrl() {
- String url = getActivity().getResources()
- .getString(com.android.internal.R.string.mobile_provisioning_url);
- log("getProvisioningUrl: mobile_provisioning_url=" + url);
-
- // populate the iccid, imei and phone number in the provisioning url.
- if (!TextUtils.isEmpty(url)) {
- String phoneNumber = mTm.getLine1Number();
- if (TextUtils.isEmpty(phoneNumber)) {
- phoneNumber = "0000000000";
- }
- url = String.format(url,
- mTm.getSimSerialNumber() /* ICCID */,
- mTm.getDeviceId() /* IMEI */,
- phoneNumber /* Phone number */);
- }
-
- return url;
- }
-
@Override
public Dialog onCreateDialog(int dialogId) {
log("onCreateDialog: dialogId=" + dialogId);
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
new file mode 100644
index 0000000..d2198a7
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2009 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.accessibility;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.ActivityManagerNative;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.Configuration;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceScreen;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.TextView;
+
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.view.RotationPolicy;
+import com.android.internal.view.RotationPolicy.RotationPolicyListener;
+import com.android.settings.DialogCreatable;
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Activity with the accessibility settings.
+ */
+public class AccessibilitySettings extends SettingsPreferenceFragment implements DialogCreatable,
+ Preference.OnPreferenceChangeListener {
+ private static final String DEFAULT_SCREENREADER_MARKET_LINK =
+ "market://search?q=pname:com.google.android.marvin.talkback";
+
+ private static final float LARGE_FONT_SCALE = 1.3f;
+
+ private static final String SYSTEM_PROPERTY_MARKET_URL = "ro.screenreader.market";
+
+ static final char ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':';
+
+ 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";
+ private static final String TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE =
+ "toggle_power_button_ends_call_preference";
+ private static final String TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE =
+ "toggle_lock_screen_rotation_preference";
+ private static final String TOGGLE_SPEAK_PASSWORD_PREFERENCE =
+ "toggle_speak_password_preference";
+ private static final String SELECT_LONG_PRESS_TIMEOUT_PREFERENCE =
+ "select_long_press_timeout_preference";
+ private static final String ENABLE_ACCESSIBILITY_GESTURE_PREFERENCE_SCREEN =
+ "enable_global_gesture_preference_screen";
+ private static final String DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN =
+ "screen_magnification_preference_screen";
+
+ // 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_SETTINGS_TITLE = "settings_title";
+ static final String EXTRA_COMPONENT_NAME = "component_name";
+ static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
+
+ // 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.
+ private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000;
+
+ // Dialog IDs.
+ private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 1;
+
+ // Auxiliary members.
+ final static SimpleStringSplitter sStringColonSplitter =
+ new SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
+
+ static final Set<ComponentName> sInstalledServices = new HashSet<ComponentName>();
+
+ private final Map<String, String> mLongPressTimeoutValuetoTitleMap =
+ new HashMap<String, String>();
+
+ private final Configuration mCurConfig = new Configuration();
+
+ private final Handler mHandler = new Handler();
+
+ private final Runnable mUpdateRunnable = new Runnable() {
+ @Override
+ public void run() {
+ loadInstalledServices();
+ updateServicesPreferences();
+ }
+ };
+
+ private final PackageMonitor mSettingsPackageMonitor = new PackageMonitor() {
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ sendUpdate();
+ }
+
+ @Override
+ public void onPackageAppeared(String packageName, int reason) {
+ sendUpdate();
+ }
+
+ @Override
+ public void onPackageDisappeared(String packageName, int reason) {
+ sendUpdate();
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ sendUpdate();
+ }
+
+ private void sendUpdate() {
+ mHandler.postDelayed(mUpdateRunnable, DELAY_UPDATE_SERVICES_MILLIS);
+ }
+ };
+
+ private final SettingsContentObserver mSettingsContentObserver =
+ new SettingsContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ loadInstalledServices();
+ updateServicesPreferences();
+ }
+ };
+
+ private final RotationPolicyListener mRotationPolicyListener = new RotationPolicyListener() {
+ @Override
+ public void onChange() {
+ updateLockScreenRotationCheckbox();
+ }
+ };
+
+ // Preference controls.
+ private PreferenceCategory mServicesCategory;
+ private PreferenceCategory mSystemsCategory;
+
+ private CheckBoxPreference mToggleLargeTextPreference;
+ private CheckBoxPreference mTogglePowerButtonEndsCallPreference;
+ private CheckBoxPreference mToggleLockScreenRotationPreference;
+ private CheckBoxPreference mToggleSpeakPasswordPreference;
+ private ListPreference mSelectLongPressTimeoutPreference;
+ private Preference mNoServicesMessagePreference;
+ private PreferenceScreen mDisplayMagnificationPreferenceScreen;
+ private PreferenceScreen mGlobalGesturePreferenceScreen;
+
+ private int mLongPressTimeoutDefault;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ addPreferencesFromResource(R.xml.accessibility_settings);
+ initializeAllPreferences();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ loadInstalledServices();
+ updateAllPreferences();
+
+ offerInstallAccessibilitySerivceOnce();
+
+ mSettingsPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false);
+ mSettingsContentObserver.register(getContentResolver());
+ if (RotationPolicy.isRotationSupported(getActivity())) {
+ RotationPolicy.registerRotationPolicyListener(getActivity(),
+ mRotationPolicyListener);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ mSettingsPackageMonitor.unregister();
+ mSettingsContentObserver.unregister(getContentResolver());
+ if (RotationPolicy.isRotationSupported(getActivity())) {
+ RotationPolicy.unregisterRotationPolicyListener(getActivity(),
+ mRotationPolicyListener);
+ }
+ super.onPause();
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference == mSelectLongPressTimeoutPreference) {
+ String stringValue = (String) newValue;
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.LONG_PRESS_TIMEOUT, Integer.parseInt(stringValue));
+ mSelectLongPressTimeoutPreference.setSummary(
+ mLongPressTimeoutValuetoTitleMap.get(stringValue));
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (mToggleLargeTextPreference == preference) {
+ handleToggleLargeTextPreferenceClick();
+ return true;
+ } else if (mTogglePowerButtonEndsCallPreference == preference) {
+ handleTogglePowerButtonEndsCallPreferenceClick();
+ return true;
+ } else if (mToggleLockScreenRotationPreference == preference) {
+ handleLockScreenRotationPreferenceClick();
+ return true;
+ } else if (mToggleSpeakPasswordPreference == preference) {
+ handleToggleSpeakPasswordPreferenceClick();
+ return true;
+ } else if (mGlobalGesturePreferenceScreen == preference) {
+ handleTogglEnableAccessibilityGesturePreferenceClick();
+ return true;
+ } else if (mDisplayMagnificationPreferenceScreen == preference) {
+ handleDisplayMagnificationPreferenceScreenClick();
+ return true;
+ }
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
+ }
+
+ private void handleToggleLargeTextPreferenceClick() {
+ try {
+ mCurConfig.fontScale = mToggleLargeTextPreference.isChecked() ? LARGE_FONT_SCALE : 1;
+ ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ }
+
+ 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 handleLockScreenRotationPreferenceClick() {
+ RotationPolicy.setRotationLockForAccessibility(getActivity(),
+ !mToggleLockScreenRotationPreference.isChecked());
+ }
+
+ private void handleToggleSpeakPasswordPreferenceClick() {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD,
+ mToggleSpeakPasswordPreference.isChecked() ? 1 : 0);
+ }
+
+ private void handleTogglEnableAccessibilityGesturePreferenceClick() {
+ Bundle extras = mGlobalGesturePreferenceScreen.getExtras();
+ extras.putString(EXTRA_TITLE, getString(
+ R.string.accessibility_global_gesture_preference_title));
+ extras.putString(EXTRA_SUMMARY, getString(
+ R.string.accessibility_global_gesture_preference_description));
+ extras.putBoolean(EXTRA_CHECKED, Settings.Global.getInt(getContentResolver(),
+ Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1);
+ super.onPreferenceTreeClick(mGlobalGesturePreferenceScreen,
+ mGlobalGesturePreferenceScreen);
+ }
+
+ private void handleDisplayMagnificationPreferenceScreenClick() {
+ Bundle extras = mDisplayMagnificationPreferenceScreen.getExtras();
+ extras.putString(EXTRA_TITLE, getString(
+ R.string.accessibility_screen_magnification_title));
+ extras.putCharSequence(EXTRA_SUMMARY, getActivity().getResources().getText(
+ R.string.accessibility_screen_magnification_summary));
+ extras.putBoolean(EXTRA_CHECKED, Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0) == 1);
+ super.onPreferenceTreeClick(mDisplayMagnificationPreferenceScreen,
+ mDisplayMagnificationPreferenceScreen);
+ }
+
+ private void initializeAllPreferences() {
+ mServicesCategory = (PreferenceCategory) findPreference(SERVICES_CATEGORY);
+ mSystemsCategory = (PreferenceCategory) findPreference(SYSTEM_CATEGORY);
+
+ // Large text.
+ mToggleLargeTextPreference =
+ (CheckBoxPreference) findPreference(TOGGLE_LARGE_TEXT_PREFERENCE);
+
+ // Power button ends calls.
+ mTogglePowerButtonEndsCallPreference =
+ (CheckBoxPreference) findPreference(TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE);
+ if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
+ || !Utils.isVoiceCapable(getActivity())) {
+ mSystemsCategory.removePreference(mTogglePowerButtonEndsCallPreference);
+ }
+
+ // Lock screen rotation.
+ mToggleLockScreenRotationPreference =
+ (CheckBoxPreference) findPreference(TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE);
+ if (!RotationPolicy.isRotationSupported(getActivity())) {
+ mSystemsCategory.removePreference(mToggleLockScreenRotationPreference);
+ }
+
+ // Speak passwords.
+ mToggleSpeakPasswordPreference =
+ (CheckBoxPreference) findPreference(TOGGLE_SPEAK_PASSWORD_PREFERENCE);
+
+ // 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]);
+ }
+ }
+
+ // Display magnification.
+ mDisplayMagnificationPreferenceScreen = (PreferenceScreen) findPreference(
+ DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN);
+
+ // Global gesture.
+ mGlobalGesturePreferenceScreen =
+ (PreferenceScreen) findPreference(ENABLE_ACCESSIBILITY_GESTURE_PREFERENCE_SCREEN);
+ final int longPressOnPowerBehavior = getActivity().getResources().getInteger(
+ com.android.internal.R.integer.config_longPressOnPowerBehavior);
+ final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
+ if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
+ || longPressOnPowerBehavior != LONG_PRESS_POWER_GLOBAL_ACTIONS) {
+ // Remove accessibility shortcut if power key is not present
+ // nor long press power does not show global actions menu.
+ mSystemsCategory.removePreference(mGlobalGesturePreferenceScreen);
+ }
+ }
+
+ private void updateAllPreferences() {
+ updateServicesPreferences();
+ updateSystemPreferences();
+ }
+
+ private void updateServicesPreferences() {
+ // 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());
+
+ List<AccessibilityServiceInfo> installedServices =
+ accessibilityManager.getInstalledAccessibilityServiceList();
+ Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(
+ getActivity());
+
+ final boolean accessibilityEnabled = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
+
+ for (int i = 0, count = installedServices.size(); i < count; ++i) {
+ AccessibilityServiceInfo info = installedServices.get(i);
+
+ PreferenceScreen preference = getPreferenceManager().createPreferenceScreen(
+ getActivity());
+ String title = info.getResolveInfo().loadLabel(getPackageManager()).toString();
+
+ ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
+ ComponentName componentName = new ComponentName(serviceInfo.packageName,
+ serviceInfo.name);
+
+ preference.setKey(componentName.flattenToString());
+
+ preference.setTitle(title);
+ final boolean serviceEnabled = accessibilityEnabled
+ && enabledServices.contains(componentName);
+ if (serviceEnabled) {
+ preference.setSummary(getString(R.string.accessibility_feature_state_on));
+ } else {
+ preference.setSummary(getString(R.string.accessibility_feature_state_off));
+ }
+
+ preference.setOrder(i);
+ preference.setFragment(ToggleAccessibilityServicePreferenceFragment.class.getName());
+ preference.setPersistent(true);
+
+ Bundle extras = preference.getExtras();
+ extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey());
+ extras.putBoolean(EXTRA_CHECKED, serviceEnabled);
+ extras.putString(EXTRA_TITLE, title);
+
+ String description = info.loadDescription(getPackageManager());
+ if (TextUtils.isEmpty(description)) {
+ description = getString(R.string.accessibility_service_default_description);
+ }
+ extras.putString(EXTRA_SUMMARY, description);
+
+ String settingsClassName = info.getSettingsActivityName();
+ if (!TextUtils.isEmpty(settingsClassName)) {
+ extras.putString(EXTRA_SETTINGS_TITLE,
+ getString(R.string.accessibility_menu_item_settings));
+ extras.putString(EXTRA_SETTINGS_COMPONENT_NAME,
+ new ComponentName(info.getResolveInfo().serviceInfo.packageName,
+ settingsClassName).flattenToString());
+ }
+
+ extras.putParcelable(EXTRA_COMPONENT_NAME, componentName);
+
+ mServicesCategory.addPreference(preference);
+ }
+
+ if (mServicesCategory.getPreferenceCount() == 0) {
+ if (mNoServicesMessagePreference == null) {
+ mNoServicesMessagePreference = new Preference(getActivity()) {
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+ TextView summaryView = (TextView) view.findViewById(R.id.summary);
+ String title = getString(R.string.accessibility_no_services_installed);
+ summaryView.setText(title);
+ }
+ };
+ mNoServicesMessagePreference.setPersistent(false);
+ mNoServicesMessagePreference.setLayoutResource(
+ R.layout.text_description_preference);
+ mNoServicesMessagePreference.setSelectable(false);
+ }
+ mServicesCategory.addPreference(mNoServicesMessagePreference);
+ }
+ }
+
+ private void updateSystemPreferences() {
+ // Large text.
+ try {
+ mCurConfig.updateFrom(ActivityManagerNative.getDefault().getConfiguration());
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ mToggleLargeTextPreference.setChecked(mCurConfig.fontScale == LARGE_FONT_SCALE);
+
+ // Power button ends calls.
+ 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);
+ }
+
+ // Auto-rotate screen
+ updateLockScreenRotationCheckbox();
+
+ // Speak passwords.
+ final boolean speakPasswordEnabled = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0;
+ mToggleSpeakPasswordPreference.setChecked(speakPasswordEnabled);
+
+ // Long press timeout.
+ 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));
+
+ // Screen magnification.
+ final boolean magnificationEnabled = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0) == 1;
+ if (magnificationEnabled) {
+ mDisplayMagnificationPreferenceScreen.setSummary(
+ R.string.accessibility_feature_state_on);
+ } else {
+ mDisplayMagnificationPreferenceScreen.setSummary(
+ R.string.accessibility_feature_state_off);
+ }
+
+ // Global gesture
+ final boolean globalGestureEnabled = Settings.Global.getInt(getContentResolver(),
+ Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1;
+ if (globalGestureEnabled) {
+ mGlobalGesturePreferenceScreen.setSummary(
+ R.string.accessibility_global_gesture_preference_summary_on);
+ } else {
+ mGlobalGesturePreferenceScreen.setSummary(
+ R.string.accessibility_global_gesture_preference_summary_off);
+ }
+ }
+
+ private void updateLockScreenRotationCheckbox() {
+ Context context = getActivity();
+ if (context != null) {
+ mToggleLockScreenRotationPreference.setChecked(
+ !RotationPolicy.isRotationLocked(context));
+ }
+ }
+
+ private void offerInstallAccessibilitySerivceOnce() {
+ // There is always one preference - if no services it is just a message.
+ if (mServicesCategory.getPreference(0) != mNoServicesMessagePreference) {
+ return;
+ }
+ SharedPreferences preferences = getActivity().getPreferences(Context.MODE_PRIVATE);
+ final boolean offerInstallService = !preferences.getBoolean(
+ KEY_INSTALL_ACCESSIBILITY_SERVICE_OFFERED_ONCE, false);
+ if (offerInstallService) {
+ String screenreaderMarketLink = SystemProperties.get(
+ SYSTEM_PROPERTY_MARKET_URL,
+ DEFAULT_SCREENREADER_MARKET_LINK);
+ Uri marketUri = Uri.parse(screenreaderMarketLink);
+ Intent marketIntent = new Intent(Intent.ACTION_VIEW, marketUri);
+
+ if (getPackageManager().resolveActivity(marketIntent, 0) == null) {
+ // Don't show the dialog if no market app is found/installed.
+ return;
+ }
+
+ 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);
+ }
+ }
+
+ @Override
+ public Dialog onCreateDialog(int dialogId) {
+ switch (dialogId) {
+ case DIALOG_ID_NO_ACCESSIBILITY_SERVICES:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.accessibility_service_no_apps_title)
+ .setMessage(R.string.accessibility_service_no_apps_message)
+ .setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // dismiss the dialog before launching
+ // the activity otherwise the dialog
+ // removal occurs after
+ // onSaveInstanceState which triggers an
+ // exception
+ removeDialog(DIALOG_ID_NO_ACCESSIBILITY_SERVICES);
+ String screenreaderMarketLink = SystemProperties.get(
+ SYSTEM_PROPERTY_MARKET_URL,
+ DEFAULT_SCREENREADER_MARKET_LINK);
+ Uri marketUri = Uri.parse(screenreaderMarketLink);
+ Intent marketIntent = new Intent(Intent.ACTION_VIEW,
+ marketUri);
+ startActivity(marketIntent);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ default:
+ return null;
+ }
+ }
+
+ private void loadInstalledServices() {
+ Set<ComponentName> installedServices = sInstalledServices;
+ installedServices.clear();
+
+ List<AccessibilityServiceInfo> installedServiceInfos =
+ AccessibilityManager.getInstance(getActivity())
+ .getInstalledAccessibilityServiceList();
+ if (installedServiceInfos == null) {
+ return;
+ }
+
+ final int installedServiceInfoCount = installedServiceInfos.size();
+ for (int i = 0; i < installedServiceInfoCount; i++) {
+ ResolveInfo resolveInfo = installedServiceInfos.get(i).getResolveInfo();
+ ComponentName installedService = new ComponentName(
+ resolveInfo.serviceInfo.packageName,
+ resolveInfo.serviceInfo.name);
+ installedServices.add(installedService);
+ }
+ }
+}
diff --git a/src/com/android/settings/accessibility/AccessibilityUtils.java b/src/com/android/settings/accessibility/AccessibilityUtils.java
new file mode 100644
index 0000000..fd4a34f
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilityUtils.java
@@ -0,0 +1,37 @@
+package com.android.settings.accessibility;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.text.TextUtils.SimpleStringSplitter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * TODO: Insert description here. (generated by alanv)
+ */
+public class AccessibilityUtils {
+
+ static Set<ComponentName> getEnabledServicesFromSettings(Context context) {
+ String enabledServicesSetting = Settings.Secure.getString(context.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ if (enabledServicesSetting == null) {
+ enabledServicesSetting = "";
+ }
+ Set<ComponentName> enabledServices = new HashSet<ComponentName>();
+ SimpleStringSplitter colonSplitter = AccessibilitySettings.sStringColonSplitter;
+ colonSplitter.setString(enabledServicesSetting);
+ while (colonSplitter.hasNext()) {
+ String componentNameString = colonSplitter.next();
+ ComponentName enabledService = ComponentName.unflattenFromString(
+ componentNameString);
+ if (enabledService != null) {
+ enabledServices.add(enabledService);
+ }
+ }
+ return enabledServices;
+ }
+
+}
diff --git a/src/com/android/settings/accessibility/SettingsContentObserver.java b/src/com/android/settings/accessibility/SettingsContentObserver.java
new file mode 100644
index 0000000..c3baec5
--- /dev/null
+++ b/src/com/android/settings/accessibility/SettingsContentObserver.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 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.accessibility;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+
+abstract class SettingsContentObserver extends ContentObserver {
+ public SettingsContentObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void register(ContentResolver contentResolver) {
+ contentResolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_ENABLED), false, this);
+ contentResolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES), false, this);
+ }
+
+ public void unregister(ContentResolver contentResolver) {
+ contentResolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public abstract void onChange(boolean selfChange, Uri uri);
+}
diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
new file mode 100644
index 0000000..3059dcc
--- /dev/null
+++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2013 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.accessibility;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener;
+
+import java.util.List;
+import java.util.Set;
+
+public class ToggleAccessibilityServicePreferenceFragment
+ extends ToggleFeaturePreferenceFragment implements DialogInterface.OnClickListener {
+
+ private static final int DIALOG_ID_ENABLE_WARNING = 1;
+ private static final int DIALOG_ID_DISABLE_WARNING = 2;
+
+ private final SettingsContentObserver mSettingsContentObserver =
+ new SettingsContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ String settingValue = Settings.Secure.getString(getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ final boolean enabled = settingValue.contains(mComponentName.flattenToString());
+ mToggleSwitch.setCheckedInternal(enabled);
+ }
+ };
+
+ private ComponentName mComponentName;
+
+ private int mShownDialogId;
+
+ @Override
+ public void onResume() {
+ mSettingsContentObserver.register(getContentResolver());
+ super.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ mSettingsContentObserver.unregister(getContentResolver());
+ super.onPause();
+ }
+
+ @Override
+ public void onPreferenceToggled(String preferenceKey, boolean enabled) {
+ // Parse the enabled services.
+ Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(
+ getActivity());
+
+ // Determine enabled services and accessibility state.
+ ComponentName toggledService = ComponentName.unflattenFromString(preferenceKey);
+ boolean accessibilityEnabled = false;
+ if (enabled) {
+ enabledServices.add(toggledService);
+ // Enabling at least one service enables accessibility.
+ accessibilityEnabled = true;
+ } else {
+ enabledServices.remove(toggledService);
+ // Check how many enabled and installed services are present.
+ Set<ComponentName> installedServices = AccessibilitySettings.sInstalledServices;
+ for (ComponentName enabledService : enabledServices) {
+ if (installedServices.contains(enabledService)) {
+ // Disabling the last service disables accessibility.
+ accessibilityEnabled = true;
+ break;
+ }
+ }
+ }
+
+ // Update the enabled services setting.
+ StringBuilder enabledServicesBuilder = new StringBuilder();
+ // Keep the enabled services even if they are not installed since we
+ // have no way to know whether the application restore process has
+ // completed. In general the system should be responsible for the
+ // clean up not settings.
+ for (ComponentName enabledService : enabledServices) {
+ enabledServicesBuilder.append(enabledService.flattenToString());
+ enabledServicesBuilder.append(
+ AccessibilitySettings.ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
+ }
+ final int enabledServicesBuilderLength = enabledServicesBuilder.length();
+ if (enabledServicesBuilderLength > 0) {
+ enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1);
+ }
+ Settings.Secure.putString(getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ enabledServicesBuilder.toString());
+
+ // Update accessibility enabled.
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, accessibilityEnabled ? 1 : 0);
+ }
+
+ // IMPORTANT: Refresh the info since there are dynamically changing
+ // capabilities. For
+ // example, before JellyBean MR2 the user was granting the explore by touch
+ // one.
+ private AccessibilityServiceInfo getAccessibilityServiceInfo() {
+ List<AccessibilityServiceInfo> serviceInfos = AccessibilityManager.getInstance(
+ getActivity()).getInstalledAccessibilityServiceList();
+ final int serviceInfoCount = serviceInfos.size();
+ for (int i = 0; i < serviceInfoCount; i++) {
+ AccessibilityServiceInfo serviceInfo = serviceInfos.get(i);
+ ResolveInfo resolveInfo = serviceInfo.getResolveInfo();
+ if (mComponentName.getPackageName().equals(resolveInfo.serviceInfo.packageName)
+ && mComponentName.getClassName().equals(resolveInfo.serviceInfo.name)) {
+ return serviceInfo;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Dialog onCreateDialog(int dialogId) {
+ switch (dialogId) {
+ case DIALOG_ID_ENABLE_WARNING: {
+ mShownDialogId = DIALOG_ID_ENABLE_WARNING;
+ AccessibilityServiceInfo info = getAccessibilityServiceInfo();
+ if (info == null) {
+ return null;
+ }
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getString(R.string.enable_service_title,
+ info.getResolveInfo().loadLabel(getPackageManager())))
+ .setIconAttribute(android.R.attr.alertDialogIcon)
+ .setView(createEnableDialogContentView(info))
+ .setCancelable(true)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .create();
+ }
+ case DIALOG_ID_DISABLE_WARNING: {
+ mShownDialogId = DIALOG_ID_DISABLE_WARNING;
+ AccessibilityServiceInfo info = getAccessibilityServiceInfo();
+ if (info == null) {
+ return null;
+ }
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getString(R.string.disable_service_title,
+ info.getResolveInfo().loadLabel(getPackageManager())))
+ .setIconAttribute(android.R.attr.alertDialogIcon)
+ .setMessage(getString(R.string.disable_service_message,
+ info.getResolveInfo().loadLabel(getPackageManager())))
+ .setCancelable(true)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .create();
+ }
+ default: {
+ throw new IllegalArgumentException();
+ }
+ }
+ }
+
+ private View createEnableDialogContentView(AccessibilityServiceInfo info) {
+ LayoutInflater inflater = (LayoutInflater) getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+
+ View content = inflater.inflate(R.layout.enable_accessibility_service_dialog_content,
+ null);
+
+ TextView capabilitiesHeaderView = (TextView) content.findViewById(
+ R.id.capabilities_header);
+ capabilitiesHeaderView.setText(getString(R.string.capabilities_list_title,
+ info.getResolveInfo().loadLabel(getPackageManager())));
+
+ LinearLayout capabilitiesView = (LinearLayout) content.findViewById(R.id.capabilities);
+
+ // This capability is implicit for all services.
+ View capabilityView = inflater.inflate(
+ com.android.internal.R.layout.app_permission_item_old, null);
+
+ ImageView imageView = (ImageView) capabilityView.findViewById(
+ com.android.internal.R.id.perm_icon);
+ imageView.setImageDrawable(getResources().getDrawable(
+ com.android.internal.R.drawable.ic_text_dot));
+
+ TextView labelView = (TextView) capabilityView.findViewById(
+ com.android.internal.R.id.permission_group);
+ labelView.setText(getString(R.string.capability_title_receiveAccessibilityEvents));
+
+ TextView descriptionView = (TextView) capabilityView.findViewById(
+ com.android.internal.R.id.permission_list);
+ descriptionView.setText(getString(R.string.capability_desc_receiveAccessibilityEvents));
+
+ List<AccessibilityServiceInfo.CapabilityInfo> capabilities =
+ info.getCapabilityInfos();
+
+ capabilitiesView.addView(capabilityView);
+
+ // Service specific capabilities.
+ final int capabilityCount = capabilities.size();
+ for (int i = 0; i < capabilityCount; i++) {
+ AccessibilityServiceInfo.CapabilityInfo capability = capabilities.get(i);
+
+ capabilityView = inflater.inflate(
+ com.android.internal.R.layout.app_permission_item_old, null);
+
+ imageView = (ImageView) capabilityView.findViewById(
+ com.android.internal.R.id.perm_icon);
+ imageView.setImageDrawable(getResources().getDrawable(
+ com.android.internal.R.drawable.ic_text_dot));
+
+ labelView = (TextView) capabilityView.findViewById(
+ com.android.internal.R.id.permission_group);
+ labelView.setText(getString(capability.titleResId));
+
+ descriptionView = (TextView) capabilityView.findViewById(
+ com.android.internal.R.id.permission_list);
+ descriptionView.setText(getString(capability.descResId));
+
+ capabilitiesView.addView(capabilityView);
+ }
+
+ return content;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final boolean checked;
+ switch (which) {
+ case DialogInterface.BUTTON_POSITIVE:
+ checked = (mShownDialogId == DIALOG_ID_ENABLE_WARNING);
+ mToggleSwitch.setCheckedInternal(checked);
+ getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, checked);
+ onPreferenceToggled(mPreferenceKey, checked);
+ break;
+ case DialogInterface.BUTTON_NEGATIVE:
+ checked = (mShownDialogId == DIALOG_ID_DISABLE_WARNING);
+ mToggleSwitch.setCheckedInternal(checked);
+ getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, checked);
+ onPreferenceToggled(mPreferenceKey, checked);
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ @Override
+ protected void onInstallActionBarToggleSwitch() {
+ super.onInstallActionBarToggleSwitch();
+ mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
+ @Override
+ public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
+ if (checked) {
+ toggleSwitch.setCheckedInternal(false);
+ getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, false);
+ showDialog(DIALOG_ID_ENABLE_WARNING);
+ } else {
+ toggleSwitch.setCheckedInternal(true);
+ getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, true);
+ showDialog(DIALOG_ID_DISABLE_WARNING);
+ }
+ return true;
+ }
+ });
+ }
+
+ @Override
+ protected void onProcessArguments(Bundle arguments) {
+ super.onProcessArguments(arguments);
+ // Settings title and intent.
+ String settingsTitle = arguments.getString(AccessibilitySettings.EXTRA_SETTINGS_TITLE);
+ String settingsComponentName = arguments.getString(
+ AccessibilitySettings.EXTRA_SETTINGS_COMPONENT_NAME);
+ if (!TextUtils.isEmpty(settingsTitle) && !TextUtils.isEmpty(settingsComponentName)) {
+ Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent(
+ ComponentName.unflattenFromString(settingsComponentName.toString()));
+ if (!getPackageManager().queryIntentActivities(settingsIntent, 0).isEmpty()) {
+ mSettingsTitle = settingsTitle;
+ mSettingsIntent = settingsIntent;
+ setHasOptionsMenu(true);
+ }
+ }
+
+ mComponentName = arguments.getParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME);
+ }
+}
diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
new file mode 100644
index 0000000..171b1ac
--- /dev/null
+++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2013 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.accessibility;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.view.Gravity;
+import android.view.Menu;
+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.TextView;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+public abstract class ToggleFeaturePreferenceFragment
+ extends SettingsPreferenceFragment {
+
+ protected ToggleSwitch mToggleSwitch;
+
+ protected String mPreferenceKey;
+ protected Preference mSummaryPreference;
+
+ protected CharSequence mSettingsTitle;
+ protected Intent mSettingsIntent;
+
+ // 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) {
+ super.onCreate(savedInstanceState);
+ PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(
+ getActivity());
+ setPreferenceScreen(preferenceScreen);
+ mSummaryPreference = new Preference(getActivity()) {
+ @Override
+ protected void onBindView(View view) {
+ 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);
+ mSummaryPreference.setLayoutResource(R.layout.text_description_preference);
+ preferenceScreen.addPreference(mSummaryPreference);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ onInstallActionBarToggleSwitch();
+ onProcessArguments(getArguments());
+ // Set a transparent drawable to prevent use of the default one.
+ getListView().setSelector(new ColorDrawable(Color.TRANSPARENT));
+ getListView().setDivider(null);
+ }
+
+ @Override
+ public void onDestroyView() {
+ getActivity().getActionBar().setCustomView(null);
+ if (mOldActivityTitle != null) {
+ getActivity().getActionBar().setTitle(mOldActivityTitle);
+ }
+ mToggleSwitch.setOnBeforeCheckedChangeListener(null);
+ super.onDestroyView();
+ }
+
+ protected abstract void onPreferenceToggled(String preferenceKey, boolean enabled);
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ MenuItem menuItem = menu.add(mSettingsTitle);
+ menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ menuItem.setIntent(mSettingsIntent);
+ }
+
+ protected void onInstallActionBarToggleSwitch() {
+ mToggleSwitch = createAndAddActionBarToggleSwitch(getActivity());
+ }
+
+ private ToggleSwitch createAndAddActionBarToggleSwitch(Activity activity) {
+ ToggleSwitch toggleSwitch = new ToggleSwitch(activity);
+ final int padding = activity.getResources().getDimensionPixelSize(
+ R.dimen.action_bar_switch_padding);
+ toggleSwitch.setPaddingRelative(0, 0, padding, 0);
+ activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
+ ActionBar.DISPLAY_SHOW_CUSTOM);
+ activity.getActionBar().setCustomView(toggleSwitch,
+ new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT,
+ ActionBar.LayoutParams.WRAP_CONTENT,
+ Gravity.CENTER_VERTICAL | Gravity.END));
+ return toggleSwitch;
+ }
+
+ protected void onProcessArguments(Bundle arguments) {
+ // Key.
+ mPreferenceKey = arguments.getString(AccessibilitySettings.EXTRA_PREFERENCE_KEY);
+ // Enabled.
+ final boolean enabled = arguments.getBoolean(AccessibilitySettings.EXTRA_CHECKED);
+ mToggleSwitch.setCheckedInternal(enabled);
+ // Title.
+ PreferenceActivity activity = (PreferenceActivity) getActivity();
+ if (!activity.onIsMultiPane() || activity.onIsHidingHeaders()) {
+ mOldActivityTitle = getActivity().getTitle();
+ String title = arguments.getString(AccessibilitySettings.EXTRA_TITLE);
+ getActivity().getActionBar().setTitle(title);
+ }
+ // Summary.
+ CharSequence summary = arguments.getCharSequence(AccessibilitySettings.EXTRA_SUMMARY);
+ mSummaryPreference.setSummary(summary);
+ }
+}
diff --git a/src/com/android/settings/accessibility/ToggleGlobalGesturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleGlobalGesturePreferenceFragment.java
new file mode 100644
index 0000000..f4ac2cc
--- /dev/null
+++ b/src/com/android/settings/accessibility/ToggleGlobalGesturePreferenceFragment.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 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.accessibility;
+
+import android.provider.Settings;
+
+import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener;
+
+public class ToggleGlobalGesturePreferenceFragment
+ extends ToggleFeaturePreferenceFragment {
+ @Override
+ protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
+ Settings.Global.putInt(getContentResolver(),
+ Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, enabled ? 1 : 0);
+ }
+
+ @Override
+ protected void onInstallActionBarToggleSwitch() {
+ super.onInstallActionBarToggleSwitch();
+ mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
+ @Override
+ public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
+ toggleSwitch.setCheckedInternal(checked);
+ getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, checked);
+ onPreferenceToggled(mPreferenceKey, checked);
+ return false;
+ }
+ });
+ }
+}
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
new file mode 100644
index 0000000..27d07d2
--- /dev/null
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 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.accessibility;
+
+import android.provider.Settings;
+
+import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener;
+
+public class ToggleScreenMagnificationPreferenceFragment
+ extends ToggleFeaturePreferenceFragment {
+ @Override
+ protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, enabled ? 1 : 0);
+ }
+
+ @Override
+ protected void onInstallActionBarToggleSwitch() {
+ super.onInstallActionBarToggleSwitch();
+ mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
+ @Override
+ public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
+ toggleSwitch.setCheckedInternal(checked);
+ getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, checked);
+ onPreferenceToggled(mPreferenceKey, checked);
+ return false;
+ }
+ });
+ }
+}
diff --git a/src/com/android/settings/accessibility/ToggleSwitch.java b/src/com/android/settings/accessibility/ToggleSwitch.java
new file mode 100644
index 0000000..e7c39e4
--- /dev/null
+++ b/src/com/android/settings/accessibility/ToggleSwitch.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 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.accessibility;
+
+import android.content.Context;
+import android.widget.Switch;
+
+public class ToggleSwitch extends Switch {
+ private ToggleSwitch.OnBeforeCheckedChangeListener mOnBeforeListener;
+
+ public static interface OnBeforeCheckedChangeListener {
+ public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked);
+ }
+
+ public ToggleSwitch(Context context) {
+ super(context);
+ }
+
+ public void setOnBeforeCheckedChangeListener(OnBeforeCheckedChangeListener listener) {
+ mOnBeforeListener = listener;
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ if (mOnBeforeListener != null
+ && mOnBeforeListener.onBeforeCheckedChanged(this, checked)) {
+ return;
+ }
+ super.setChecked(checked);
+ }
+
+ public void setCheckedInternal(boolean checked) {
+ super.setChecked(checked);
+ }
+}
diff --git a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
index 4658955..45b1182 100644
--- a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
+++ b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
@@ -20,10 +20,12 @@
import com.android.settings.Settings.KeyboardLayoutPickerActivity;
import com.android.settings.Settings.SpellCheckersSettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.UserDictionarySettings;
import com.android.settings.Utils;
import com.android.settings.VoiceInputOutputSettings;
import android.app.Activity;
+import android.app.Fragment;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -38,6 +40,7 @@
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.provider.Settings;
@@ -200,7 +203,35 @@
// not present or disabled. In this case we need to remove the preference.
getPreferenceScreen().removePreference(userDictionaryPreference);
} else {
- userDictionaryPreference.setFragment(UserDictionaryList.class.getName());
+ userDictionaryPreference.setOnPreferenceClickListener(
+ new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference arg0) {
+ // Redirect to UserDictionarySettings if the user needs only one
+ // language.
+ final Bundle extras = new Bundle();
+ final Class<? extends Fragment> targetFragment;
+ if (localeSet.size() <= 1) {
+ if (!localeSet.isEmpty()) {
+ // If the size of localeList is 0, we don't set the locale
+ // parameter in the extras. This will be interpreted by the
+ // UserDictionarySettings class as meaning
+ // "the current locale". Note that with the current code for
+ // UserDictionaryList#getUserDictionaryLocalesSet()
+ // the locale list always has at least one element, since it
+ // always includes the current locale explicitly.
+ // @see UserDictionaryList.getUserDictionaryLocalesSet().
+ extras.putString("locale", localeSet.first());
+ }
+ targetFragment = UserDictionarySettings.class;
+ } else {
+ targetFragment = UserDictionaryList.class;
+ }
+ startFragment(InputMethodAndLanguageSettings.this,
+ targetFragment.getCanonicalName(), -1, extras);
+ return true;
+ }
+ });
}
}
diff --git a/src/com/android/settings/inputmethod/UserDictionaryAddWordContents.java b/src/com/android/settings/inputmethod/UserDictionaryAddWordContents.java
index 5efe117..d81703e 100644
--- a/src/com/android/settings/inputmethod/UserDictionaryAddWordContents.java
+++ b/src/com/android/settings/inputmethod/UserDictionaryAddWordContents.java
@@ -57,6 +57,8 @@
private String mLocale;
private final String mOldWord;
private final String mOldShortcut;
+ private String mSavedWord;
+ private String mSavedShortcut;
/* package */ UserDictionaryAddWordContents(final View view, final Bundle args) {
mWordEditText = (EditText)view.findViewById(R.id.user_dictionary_add_word_text);
@@ -78,6 +80,16 @@
updateLocale(args.getString(EXTRA_LOCALE));
}
+ /* package */ UserDictionaryAddWordContents(final View view,
+ final UserDictionaryAddWordContents oldInstanceToBeEdited) {
+ mWordEditText = (EditText)view.findViewById(R.id.user_dictionary_add_word_text);
+ mShortcutEditText = (EditText)view.findViewById(R.id.user_dictionary_add_shortcut);
+ mMode = MODE_EDIT;
+ mOldWord = oldInstanceToBeEdited.mSavedWord;
+ mOldShortcut = oldInstanceToBeEdited.mSavedShortcut;
+ updateLocale(mLocale);
+ }
+
// locale may be null, this means default locale
// It may also be the empty string, which means "all locales"
/* package */ void updateLocale(final String locale) {
@@ -128,6 +140,8 @@
// If the word is somehow empty, don't insert it.
return UserDictionaryAddWordActivity.CODE_CANCEL;
}
+ mSavedWord = newWord;
+ mSavedShortcut = newShortcut;
// If there is no shortcut, and the word already exists in the database, then we
// should not insert, because either A. the word exists with no shortcut, in which
// case the exact same thing we want to insert is already there, or B. the word
@@ -239,4 +253,8 @@
localesList.add(new LocaleRenderer(activity, null)); // meaning: select another locale
return localesList;
}
+
+ public String getCurrentUserDictionaryLocale() {
+ return mLocale;
+ }
}
diff --git a/src/com/android/settings/inputmethod/UserDictionaryAddWordFragment.java b/src/com/android/settings/inputmethod/UserDictionaryAddWordFragment.java
index e33333b..8f7029a 100644
--- a/src/com/android/settings/inputmethod/UserDictionaryAddWordFragment.java
+++ b/src/com/android/settings/inputmethod/UserDictionaryAddWordFragment.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.settings.inputmethod;
import android.app.Fragment;
@@ -51,23 +52,39 @@
private boolean mIsDeleting = false;
@Override
- public void onActivityCreated(Bundle savedInstanceState) {
+ public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
+ getActivity().getActionBar().setTitle(R.string.user_dict_settings_title);
+ // Keep the instance so that we remember mContents when configuration changes (eg rotation)
+ setRetainInstance(true);
}
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
+ final Bundle savedState) {
mRootView = inflater.inflate(R.layout.user_dictionary_add_word_fullscreen, null);
mIsDeleting = false;
+ // If we have a non-null mContents object, it's the old value before a configuration
+ // change (eg rotation) so we need to use its values. Otherwise, read from the arguments.
if (null == mContents) {
mContents = new UserDictionaryAddWordContents(mRootView, getArguments());
+ } else {
+ // We create a new mContents object to account for the new situation : a word has
+ // been added to the user dictionary when we started rotating, and we are now editing
+ // it. That means in particular if the word undergoes any change, the old version should
+ // be updated, so the mContents object needs to switch to EDIT mode if it was in
+ // INSERT mode.
+ mContents = new UserDictionaryAddWordContents(mRootView,
+ mContents /* oldInstanceToBeEdited */);
}
+ getActivity().getActionBar().setSubtitle(UserDictionarySettingsUtils.getLocaleDisplayName(
+ getActivity(), mContents.getCurrentUserDictionaryLocale()));
return mRootView;
}
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
MenuItem actionItem = menu.add(0, OPTIONS_MENU_DELETE, 0, R.string.delete)
.setIcon(android.R.drawable.ic_menu_delete);
actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
@@ -102,13 +119,9 @@
private void updateSpinner() {
final ArrayList<LocaleRenderer> localesList = mContents.getLocalesList(getActivity());
- final Spinner localeSpinner =
- (Spinner)mRootView.findViewById(R.id.user_dictionary_add_locale);
final ArrayAdapter<LocaleRenderer> adapter = new ArrayAdapter<LocaleRenderer>(getActivity(),
android.R.layout.simple_spinner_item, localesList);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- localeSpinner.setAdapter(adapter);
- localeSpinner.setOnItemSelectedListener(this);
}
@Override
diff --git a/src/com/android/settings/inputmethod/UserDictionaryList.java b/src/com/android/settings/inputmethod/UserDictionaryList.java
index f9e4379..24acb4a 100644
--- a/src/com/android/settings/inputmethod/UserDictionaryList.java
+++ b/src/com/android/settings/inputmethod/UserDictionaryList.java
@@ -26,18 +26,13 @@
import android.database.Cursor;
import android.os.Bundle;
import android.preference.Preference;
-import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
import android.provider.UserDictionary;
import android.text.TextUtils;
-import android.util.Log;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.TreeSet;
@@ -129,9 +124,8 @@
/**
* Creates the entries that allow the user to go into the user dictionary for each locale.
* @param userDictGroup The group to put the settings in.
- * @return the shown language set
*/
- protected TreeSet<String> createUserDictSettingsAndReturnSet(PreferenceGroup userDictGroup) {
+ protected void createUserDictSettings(PreferenceGroup userDictGroup) {
final Activity activity = getActivity();
userDictGroup.removeAll();
final TreeSet<String> localeSet =
@@ -141,6 +135,11 @@
// in the list.
localeSet.add(mLocale);
}
+ if (localeSet.size() > 1) {
+ // Have an "All languages" entry in the languages list if there are two or more active
+ // languages
+ localeSet.add("");
+ }
if (localeSet.isEmpty()) {
userDictGroup.addPreference(createUserDictionaryPreference(null, activity));
@@ -149,7 +148,6 @@
userDictGroup.addPreference(createUserDictionaryPreference(locale, activity));
}
}
- return localeSet;
}
/**
@@ -178,25 +176,6 @@
@Override
public void onResume() {
super.onResume();
- final TreeSet<String> localeSet = createUserDictSettingsAndReturnSet(getPreferenceScreen());
- if (localeSet.size() <= 1) {
- // Redirect to UserDictionarySettings if the user needs only one language.
- final Bundle extras = new Bundle();
- if (!localeSet.isEmpty()) {
- // If the size of localeList is 0, we don't set the locale parameter in the
- // extras. This will be interpreted by the UserDictionarySettings class as
- // meaning "the current locale".
- // Note that with the current code for
- // UserDictionaryList#getUserDictionaryLocalesSet()
- // the locale list always has at least one element, since it always includes
- // the current locale explicitly.
- // @see UserDictionaryList.getUserDictionaryLocalesSet().
- extras.putString("locale", localeSet.first());
- }
- startFragment(this,
- com.android.settings.UserDictionarySettings.class.getCanonicalName(), -1,
- extras);
- finish();
- }
+ createUserDictSettings(getPreferenceScreen());
}
}
diff --git a/src/com/android/settings/inputmethod/UserDictionarySettingsUtils.java b/src/com/android/settings/inputmethod/UserDictionarySettingsUtils.java
new file mode 100644
index 0000000..2238b4b
--- /dev/null
+++ b/src/com/android/settings/inputmethod/UserDictionarySettingsUtils.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 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.Utils;
+
+import android.content.Context;
+
+import java.util.Locale;
+
+/**
+ * Utilities of the user dictionary settings
+ */
+public class UserDictionarySettingsUtils {
+ public static String getLocaleDisplayName(Context context, String localeStr) {
+ final Locale locale = Utils.createLocaleFromString(localeStr);
+ final Locale systemLocale = context.getResources().getConfiguration().locale;
+ return locale.getDisplayName(systemLocale);
+ }
+}
diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java
index 2f99d11..0e15cec 100644
--- a/src/com/android/settings/users/AppRestrictionsFragment.java
+++ b/src/com/android/settings/users/AppRestrictionsFragment.java
@@ -57,6 +57,7 @@
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.ViewGroup;
+import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Switch;
@@ -85,7 +86,9 @@
protected PackageManager mPackageManager;
protected UserManager mUserManager;
+ protected IPackageManager mIPm;
protected UserHandle mUser;
+ private PackageInfo mSysPackageInfo;
private PreferenceGroup mAppList;
@@ -129,6 +132,13 @@
}
};
+ private BroadcastReceiver mPackageObserver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ onPackageChanged(intent);
+ }
+ };
+
static class SelectableAppInfo {
String packageName;
CharSequence appName;
@@ -147,9 +157,9 @@
private boolean hasSettings;
private OnClickListener listener;
private ArrayList<RestrictionEntry> restrictions;
- boolean panelOpen;
+ private boolean mPanelOpen;
private boolean immutable;
- List<Preference> childPreferences = new ArrayList<Preference>();
+ private List<Preference> mChildren = new ArrayList<Preference>();
private final ColorFilter grayscaleFilter;
AppRestrictionsPreference(Context context, OnClickListener listener) {
@@ -204,6 +214,14 @@
return restrictions;
}
+ boolean isPanelOpen() {
+ return mPanelOpen;
+ }
+
+ List<Preference> getChildren() {
+ return mChildren;
+ }
+
@Override
protected void onBindView(View view) {
super.onBindView(view);
@@ -222,13 +240,13 @@
ViewGroup widget = (ViewGroup) view.findViewById(android.R.id.widget_frame);
widget.setEnabled(!isImmutable());
if (widget.getChildCount() > 0) {
- final Switch switchView = (Switch) widget.getChildAt(0);
- switchView.setEnabled(!isImmutable());
- switchView.setTag(this);
- switchView.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+ final Switch toggle = (Switch) widget.getChildAt(0);
+ toggle.setEnabled(!isImmutable());
+ toggle.setTag(this);
+ toggle.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- listener.onClick(switchView);
+ listener.onClick(toggle);
}
});
}
@@ -253,9 +271,15 @@
}
mPackageManager = getActivity().getPackageManager();
+ mIPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
mRestrictedProfile = mUserManager.getUserInfo(mUser.getIdentifier()).isRestricted();
-
+ try {
+ mSysPackageInfo = mPackageManager.getPackageInfo("android",
+ PackageManager.GET_SIGNATURES);
+ } catch (NameNotFoundException nnfe) {
+ // ?
+ }
addPreferencesFromResource(R.xml.app_restrictions);
mAppList = getAppPreferenceGroup();
}
@@ -266,21 +290,30 @@
outState.putInt(EXTRA_USER_ID, mUser.getIdentifier());
}
+ @Override
public void onResume() {
super.onResume();
getActivity().registerReceiver(mUserBackgrounding,
new IntentFilter(Intent.ACTION_USER_BACKGROUND));
+ IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageFilter.addDataScheme("package");
+ getActivity().registerReceiver(mPackageObserver, packageFilter);
+
mAppListChanged = false;
if (mAppLoadingTask == null || mAppLoadingTask.getStatus() == AsyncTask.Status.FINISHED) {
mAppLoadingTask = new AppLoadingTask().execute((Void[]) null);
}
}
+ @Override
public void onPause() {
super.onPause();
mNewUser = false;
getActivity().unregisterReceiver(mUserBackgrounding);
+ getActivity().unregisterReceiver(mPackageObserver);
if (mAppListChanged) {
new Thread() {
public void run() {
@@ -290,6 +323,20 @@
}
}
+ private void onPackageChanged(Intent intent) {
+ String action = intent.getAction();
+ String packageName = intent.getData().getSchemeSpecificPart();
+ // Package added, check if the preference needs to be enabled
+ AppRestrictionsPreference pref = (AppRestrictionsPreference)
+ findPreference(getKeyForPackage(packageName));
+ if (pref == null) return;
+
+ if ((Intent.ACTION_PACKAGE_ADDED.equals(action) && pref.isChecked())
+ || (Intent.ACTION_PACKAGE_REMOVED.equals(action) && !pref.isChecked())) {
+ pref.setEnabled(true);
+ }
+ }
+
protected PreferenceGroup getAppPreferenceGroup() {
return getPreferenceScreen();
}
@@ -306,8 +353,6 @@
}
private void applyUserAppsStates() {
- IPackageManager ipm = IPackageManager.Stub.asInterface(
- ServiceManager.getService("package"));
final int userId = mUser.getIdentifier();
if (!mUserManager.getUserInfo(userId).isRestricted() && userId != UserHandle.myUserId()) {
Log.e(TAG, "Cannot apply application restrictions on another user!");
@@ -315,47 +360,64 @@
}
for (Map.Entry<String,Boolean> entry : mSelectedPackages.entrySet()) {
String packageName = entry.getKey();
- if (entry.getValue()) {
- // Enable selected apps
- try {
- ApplicationInfo info = ipm.getApplicationInfo(packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES, userId);
- if (info == null || info.enabled == false) {
- ipm.installExistingPackageAsUser(packageName, mUser.getIdentifier());
- if (DEBUG) {
- Log.d(TAG, "Installing " + packageName);
- }
+ boolean enabled = entry.getValue();
+ applyUserAppState(packageName, enabled);
+ }
+ }
+
+ private void applyUserAppState(String packageName, boolean enabled) {
+ final int userId = mUser.getIdentifier();
+ if (enabled) {
+ // Enable selected apps
+ try {
+ ApplicationInfo info = mIPm.getApplicationInfo(packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES, userId);
+ if (info == null || info.enabled == false
+ || (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
+ mIPm.installExistingPackageAsUser(packageName, mUser.getIdentifier());
+ if (DEBUG) {
+ Log.d(TAG, "Installing " + packageName);
}
- if (info != null && (info.flags&ApplicationInfo.FLAG_BLOCKED) != 0
- && (info.flags&ApplicationInfo.FLAG_INSTALLED) != 0) {
- ipm.setApplicationBlockedSettingAsUser(packageName, false, userId);
- if (DEBUG) {
- Log.d(TAG, "Unblocking " + packageName);
- }
- }
- } catch (RemoteException re) {
}
- } else {
- // Blacklist all other apps, system or downloaded
- try {
- ApplicationInfo info = ipm.getApplicationInfo(packageName, 0, userId);
- if (info != null) {
- if (mRestrictedProfile) {
- ipm.deletePackageAsUser(entry.getKey(), null, mUser.getIdentifier(),
- PackageManager.DELETE_SYSTEM_APP);
- if (DEBUG) {
- Log.d(TAG, "Uninstalling " + packageName);
- }
- } else {
- ipm.setApplicationBlockedSettingAsUser(packageName, true, userId);
- if (DEBUG) {
- Log.d(TAG, "Blocking " + packageName);
- }
- }
+ if (info != null && (info.flags&ApplicationInfo.FLAG_BLOCKED) != 0
+ && (info.flags&ApplicationInfo.FLAG_INSTALLED) != 0) {
+ disableUiForPackage(packageName);
+ mIPm.setApplicationBlockedSettingAsUser(packageName, false, userId);
+ if (DEBUG) {
+ Log.d(TAG, "Unblocking " + packageName);
}
- } catch (RemoteException re) {
}
+ } catch (RemoteException re) {
}
+ } else {
+ // Blacklist all other apps, system or downloaded
+ try {
+ ApplicationInfo info = mIPm.getApplicationInfo(packageName, 0, userId);
+ if (info != null) {
+ if (mRestrictedProfile) {
+ mIPm.deletePackageAsUser(packageName, null, mUser.getIdentifier(),
+ PackageManager.DELETE_SYSTEM_APP);
+ if (DEBUG) {
+ Log.d(TAG, "Uninstalling " + packageName);
+ }
+ } else {
+ disableUiForPackage(packageName);
+ mIPm.setApplicationBlockedSettingAsUser(packageName, true, userId);
+ if (DEBUG) {
+ Log.d(TAG, "Blocking " + packageName);
+ }
+ }
+ }
+ } catch (RemoteException re) {
+ }
+ }
+ }
+
+ private void disableUiForPackage(String packageName) {
+ AppRestrictionsPreference pref = (AppRestrictionsPreference) findPreference(
+ getKeyForPackage(packageName));
+ if (pref != null) {
+ pref.setEnabled(false);
}
}
@@ -457,7 +519,7 @@
final Context context = getActivity();
if (context == null) return;
final PackageManager pm = mPackageManager;
- IPackageManager ipm = AppGlobals.getPackageManager();
+ final IPackageManager ipm = mIPm;
final HashSet<String> excludePackages = new HashSet<String>();
addSystemImes(excludePackages);
@@ -552,6 +614,11 @@
}
}
+ private boolean isPlatformSigned(PackageInfo pi) {
+ return (pi != null && pi.signatures != null &&
+ mSysPackageInfo.signatures[0].equals(pi.signatures[0]));
+ }
+
private boolean isAppEnabledForUser(PackageInfo pi) {
if (pi == null) return false;
final int flags = pi.applicationInfo.flags;
@@ -564,7 +631,8 @@
final Context context = getActivity();
if (context == null) return;
final PackageManager pm = mPackageManager;
- IPackageManager ipm = AppGlobals.getPackageManager();
+ final IPackageManager ipm = mIPm;
+
mAppList.removeAll();
Intent restrictionsIntent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES);
final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(restrictionsIntent, 0);
@@ -583,7 +651,7 @@
p.setSummary(context.getString(R.string.user_restrictions_controlled_by,
app.masterEntry.activityName));
}
- p.setKey(PKG_PREFIX + packageName);
+ p.setKey(getKeyForPackage(packageName));
p.setSettingsEnabled(hasSettings || isSettingsApp);
p.setPersistent(false);
p.setOnPreferenceChangeListener(this);
@@ -591,10 +659,11 @@
PackageInfo pi = null;
try {
pi = ipm.getPackageInfo(packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES, mUser.getIdentifier());
+ PackageManager.GET_UNINSTALLED_PACKAGES
+ | PackageManager.GET_SIGNATURES, mUser.getIdentifier());
} catch (RemoteException e) {
}
- if (pi != null && pi.requiredForAllUsers) {
+ if (pi != null && (pi.requiredForAllUsers || isPlatformSigned(pi))) {
p.setChecked(true);
p.setImmutable(true);
// If the app is required and has no restrictions, skip showing it
@@ -602,10 +671,10 @@
// Get and populate the defaults, since the user is not going to be
// able to toggle this app ON (it's ON by default and immutable).
// Only do this for restricted profiles, not single-user restrictions
- if (hasSettings && mRestrictedProfile) {
+ if (hasSettings) {
requestRestrictionsForApp(packageName, p);
}
- } else if (!mNewUser && isAppEnabledForUser(pi)) { /*appInfoListHasPackage(mUserApps, packageName)*/
+ } else if (!mNewUser && isAppEnabledForUser(pi)) {
p.setChecked(true);
}
if (mRestrictedProfile
@@ -640,6 +709,10 @@
}
}
+ private String getKeyForPackage(String packageName) {
+ return PKG_PREFIX + packageName;
+ }
+
private class AppLabelComparator implements Comparator<SelectableAppInfo> {
@Override
@@ -686,6 +759,10 @@
requestRestrictionsForApp(packageName, pref);
}
mAppListChanged = true;
+ // If it's not a restricted profile, apply the changes immediately
+ if (!mRestrictedProfile) {
+ applyUserAppState(packageName, pref.isChecked());
+ }
updateAllEntries(pref.getKey(), pref.isChecked());
}
}
@@ -742,11 +819,11 @@
private void toggleAppPanel(AppRestrictionsPreference preference) {
if (preference.getKey().startsWith(PKG_PREFIX)) {
- if (preference.panelOpen) {
- for (Preference p : preference.childPreferences) {
+ if (preference.mPanelOpen) {
+ for (Preference p : preference.mChildren) {
mAppList.removePreference(p);
}
- preference.childPreferences.clear();
+ preference.mChildren.clear();
} else {
String packageName = preference.getKey().substring(PKG_PREFIX.length());
if (packageName.equals(getActivity().getPackageName())) {
@@ -758,7 +835,7 @@
requestRestrictionsForApp(packageName, preference);
}
}
- preference.panelOpen = !preference.panelOpen;
+ preference.mPanelOpen = !preference.mPanelOpen;
}
}
@@ -795,8 +872,10 @@
Intent restrictionsIntent = (Intent) results.getParcelable(CUSTOM_RESTRICTIONS_INTENT);
if (restrictions != null && restrictionsIntent == null) {
onRestrictionsReceived(preference, packageName, restrictions);
- mUserManager.setApplicationRestrictions(packageName,
- RestrictionUtils.restrictionsToBundle(restrictions), mUser);
+ if (mRestrictedProfile) {
+ mUserManager.setApplicationRestrictions(packageName,
+ RestrictionUtils.restrictionsToBundle(restrictions), mUser);
+ }
} else if (restrictionsIntent != null) {
final Intent customIntent = restrictionsIntent;
if (restrictions != null) {
@@ -817,7 +896,7 @@
});
p.setPersistent(false);
p.setOrder(preference.getOrder() + 1);
- preference.childPreferences.add(p);
+ preference.mChildren.add(p);
mAppList.addPreference(p);
preference.setRestrictions(restrictions);
}
@@ -876,7 +955,7 @@
+ entry.getKey());
mAppList.addPreference(p);
p.setOnPreferenceChangeListener(AppRestrictionsFragment.this);
- preference.childPreferences.add(p);
+ preference.mChildren.add(p);
count++;
}
}
@@ -946,10 +1025,13 @@
if (preference.getKey().startsWith(PKG_PREFIX)) {
AppRestrictionsPreference arp = (AppRestrictionsPreference) preference;
if (!arp.isImmutable()) {
- arp.setChecked(!arp.isChecked());
- mSelectedPackages.put(arp.getKey().substring(PKG_PREFIX.length()), arp.isChecked());
- updateAllEntries(arp.getKey(), arp.isChecked());
+ final String packageName = arp.getKey().substring(PKG_PREFIX.length());
+ final boolean newEnabledState = !arp.isChecked();
+ arp.setChecked(newEnabledState);
+ mSelectedPackages.put(packageName, newEnabledState);
+ updateAllEntries(arp.getKey(), newEnabledState);
mAppListChanged = true;
+ applyUserAppState(packageName, newEnabledState);
}
return true;
}
diff --git a/src/com/android/settings/users/RestrictionSettings.java b/src/com/android/settings/users/RestrictionSettings.java
index 789cee4..91b8bd3 100644
--- a/src/com/android/settings/users/RestrictionSettings.java
+++ b/src/com/android/settings/users/RestrictionSettings.java
@@ -41,25 +41,36 @@
private static final int MENU_RESET = Menu.FIRST + 1;
private static final int MENU_CHANGE_PIN = Menu.FIRST + 2;
+ private static final String KEY_CHALLENGE_SUCCEEDED = "chsc";
private static final String KEY_CHALLENGE_REQUESTED = "chrq";
private boolean mChallengeSucceeded;
private boolean mChallengeRequested;
+ private boolean mDisableSelf;
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
-
+ if (UserManager.get(getActivity()).hasUserRestriction(
+ UserManager.DISALLOW_APP_RESTRICTIONS)) {
+ mDisableSelf = true;
+ return;
+ }
init(icicle);
- mChallengeSucceeded = false;
- mChallengeRequested = icicle != null
- ? icicle.getBoolean(KEY_CHALLENGE_REQUESTED, false)
- : false;
+ if (icicle != null) {
+ mChallengeSucceeded = icicle.getBoolean(KEY_CHALLENGE_SUCCEEDED, false);
+ mChallengeRequested = icicle.getBoolean(KEY_CHALLENGE_REQUESTED, false);
+ }
setHasOptionsMenu(true);
}
public void onResume() {
super.onResume();
+ if (!mDisableSelf) {
+ ensurePin();
+ }
+ }
+ private void ensurePin() {
if (!mChallengeSucceeded) {
getListView().setEnabled(false);
final UserManager um = UserManager.get(getActivity());
@@ -81,24 +92,13 @@
private void resetAndRemovePin() {
final UserManager um = UserManager.get(getActivity());
- final PackageManager pm = getActivity().getPackageManager();
- List<ApplicationInfo> installedApps = pm.getInstalledApplications(
- PackageManager.GET_UNINSTALLED_PACKAGES);
- UserHandle user = android.os.Process.myUserHandle();
- for (ApplicationInfo info: installedApps) {
- if ((info.flags & ApplicationInfo.FLAG_BLOCKED) != 0
- && (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
- pm.setApplicationBlockedSettingAsUser(info.packageName, false, user);
- }
- }
- um.changeRestrictionsPin(null);
+ um.removeRestrictions();
clearSelectedApps();
finishFragment();
}
private void changePin() {
final UserManager um = UserManager.get(getActivity());
- um.changeRestrictionsPin(null);
Intent requestPin = new Intent("android.intent.action.RESTRICTIONS_PIN_CREATE");
startActivityForResult(requestPin, REQUEST_PIN_CHALLENGE);
}
@@ -120,14 +120,19 @@
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
+
outState.putBoolean(KEY_CHALLENGE_REQUESTED, mChallengeRequested);
+ if (getActivity().isChangingConfigurations()) {
+ outState.putBoolean(KEY_CHALLENGE_SUCCEEDED, mChallengeSucceeded);
+ }
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- menu.add(0, MENU_RESET, 0, R.string.restriction_menu_reset);
- menu.add(0, MENU_CHANGE_PIN, 0, R.string.restriction_menu_change_pin);
-
+ if (!mDisableSelf) {
+ menu.add(0, MENU_RESET, 0, R.string.restriction_menu_reset);
+ menu.add(0, MENU_CHANGE_PIN, 0, R.string.restriction_menu_change_pin);
+ }
super.onCreateOptionsMenu(menu, inflater);
}