1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.accessibility; 18 19 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; 20 21 import android.accessibilityservice.AccessibilityServiceInfo; 22 import android.app.settings.SettingsEnums; 23 import android.content.ComponentName; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.content.res.Resources; 27 import android.os.Bundle; 28 import android.provider.SearchIndexableResource; 29 import android.provider.Settings; 30 import android.text.TextUtils; 31 import android.view.accessibility.AccessibilityManager; 32 33 import androidx.annotation.VisibleForTesting; 34 import androidx.preference.Preference; 35 36 import com.android.settings.R; 37 import com.android.settings.dashboard.DashboardFragment; 38 import com.android.settings.search.BaseSearchIndexProvider; 39 import com.android.settings.search.Indexable; 40 import com.android.settings.search.actionbar.SearchMenuController; 41 import com.android.settings.support.actionbar.HelpResourceProvider; 42 import com.android.settingslib.search.SearchIndexable; 43 44 import java.util.Arrays; 45 import java.util.List; 46 47 @SearchIndexable 48 public final class MagnificationPreferenceFragment extends DashboardFragment { 49 @VisibleForTesting 50 static final int ON = 1; 51 @VisibleForTesting 52 static final int OFF = 0; 53 54 private static final String TAG = "MagnificationPreferenceFragment"; 55 56 // Settings App preference keys 57 private static final String PREFERENCE_TITLE_KEY = "magnification_preference_screen_title"; 58 59 // Pseudo ComponentName used to represent navbar magnification in Settings.Secure. 60 private static final String MAGNIFICATION_COMPONENT_ID = 61 "com.android.server.accessibility.MagnificationController"; 62 63 private boolean mLaunchedFromSuw = false; 64 65 @Override getMetricsCategory()66 public int getMetricsCategory() { 67 return SettingsEnums.ACCESSIBILITY_SCREEN_MAGNIFICATION_SETTINGS; 68 } 69 70 @Override getLogTag()71 protected String getLogTag() { 72 return TAG; 73 } 74 75 @Override getHelpResource()76 public int getHelpResource() { 77 return R.string.help_url_magnification; 78 } 79 80 @Override getPreferenceScreenResId()81 protected int getPreferenceScreenResId() { 82 return R.xml.accessibility_magnification_settings; 83 } 84 85 @Override onAttach(Context context)86 public void onAttach(Context context) { 87 super.onAttach(context); 88 final Bundle args = getArguments(); 89 if ((args != null) && args.containsKey(AccessibilitySettings.EXTRA_LAUNCHED_FROM_SUW)) { 90 mLaunchedFromSuw = args.getBoolean(AccessibilitySettings.EXTRA_LAUNCHED_FROM_SUW); 91 } 92 use(MagnificationGesturesPreferenceController.class) 93 .setIsFromSUW(mLaunchedFromSuw); 94 use(MagnificationNavbarPreferenceController.class) 95 .setIsFromSUW(mLaunchedFromSuw); 96 } 97 98 @Override onPreferenceTreeClick(Preference preference)99 public boolean onPreferenceTreeClick(Preference preference) { 100 if (mLaunchedFromSuw) { 101 // If invoked from SUW, redirect to fragment instrumented for Vision Settings metrics 102 preference.setFragment( 103 ToggleScreenMagnificationPreferenceFragmentForSetupWizard.class.getName()); 104 Bundle args = preference.getExtras(); 105 // Copy from AccessibilitySettingsForSetupWizardActivity, hide search and help menu 106 args.putInt(HelpResourceProvider.HELP_URI_RESOURCE_KEY, 0); 107 args.putBoolean(SearchMenuController.NEED_SEARCH_ICON_IN_ACTION_BAR, false); 108 } 109 return super.onPreferenceTreeClick(preference); 110 } 111 getConfigurationWarningStringForSecureSettingsKey(String key, Context context)112 static CharSequence getConfigurationWarningStringForSecureSettingsKey(String key, 113 Context context) { 114 if (!Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED.equals(key)) { 115 return null; 116 } 117 if (Settings.Secure.getInt(context.getContentResolver(), 118 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, 0) == 0) { 119 return null; 120 } 121 final AccessibilityManager am = (AccessibilityManager) context.getSystemService( 122 Context.ACCESSIBILITY_SERVICE); 123 final String assignedId = Settings.Secure.getString(context.getContentResolver(), 124 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT); 125 if (!TextUtils.isEmpty(assignedId) && !MAGNIFICATION_COMPONENT_ID.equals(assignedId)) { 126 final ComponentName assignedComponentName = ComponentName.unflattenFromString( 127 assignedId); 128 final List<AccessibilityServiceInfo> activeServices = 129 am.getEnabledAccessibilityServiceList( 130 AccessibilityServiceInfo.FEEDBACK_ALL_MASK); 131 final int serviceCount = activeServices.size(); 132 for (int i = 0; i < serviceCount; i++) { 133 final AccessibilityServiceInfo info = activeServices.get(i); 134 if (info.getComponentName().equals(assignedComponentName)) { 135 final CharSequence assignedServiceName = info.getResolveInfo().loadLabel( 136 context.getPackageManager()); 137 final int messageId = isGestureNavigateEnabled(context) 138 ? R.string.accessibility_screen_magnification_gesture_navigation_warning 139 : R.string.accessibility_screen_magnification_navbar_configuration_warning; 140 return context.getString(messageId, assignedServiceName); 141 } 142 } 143 } 144 return null; 145 } 146 isChecked(ContentResolver contentResolver, String settingsKey)147 static boolean isChecked(ContentResolver contentResolver, String settingsKey) { 148 return Settings.Secure.getInt(contentResolver, settingsKey, OFF) == ON; 149 } 150 setChecked(ContentResolver contentResolver, String settingsKey, boolean isChecked)151 static boolean setChecked(ContentResolver contentResolver, String settingsKey, 152 boolean isChecked) { 153 return Settings.Secure.putInt(contentResolver, settingsKey, isChecked ? ON : OFF); 154 } 155 156 /** 157 * @return {@code true} if this fragment should be shown, {@code false} otherwise. This 158 * fragment is shown in the case that more than one magnification mode is available. 159 */ isApplicable(Resources res)160 static boolean isApplicable(Resources res) { 161 return res.getBoolean(com.android.internal.R.bool.config_showNavigationBar); 162 } 163 isGestureNavigateEnabled(Context context)164 private static boolean isGestureNavigateEnabled(Context context) { 165 return context.getResources().getInteger( 166 com.android.internal.R.integer.config_navBarInteractionMode) 167 == NAV_BAR_MODE_GESTURAL; 168 } 169 170 public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 171 new BaseSearchIndexProvider() { 172 @Override 173 public List<SearchIndexableResource> getXmlResourcesToIndex(Context context, 174 boolean enabled) { 175 final SearchIndexableResource sir = new SearchIndexableResource(context); 176 sir.xmlResId = R.xml.accessibility_magnification_settings; 177 return Arrays.asList(sir); 178 } 179 180 @Override 181 protected boolean isPageSearchEnabled(Context context) { 182 return isApplicable(context.getResources()); 183 } 184 }; 185 }