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 android.accessibilityservice.AccessibilityServiceInfo;
20 import android.app.settings.SettingsEnums;
21 import android.content.ComponentName;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.res.Resources;
25 import android.os.Bundle;
26 import android.provider.Settings;
27 import android.text.TextUtils;
28 import android.view.Menu;
29 import android.view.MenuInflater;
30 import android.view.accessibility.AccessibilityManager;
31 
32 import androidx.annotation.VisibleForTesting;
33 import androidx.preference.Preference;
34 
35 import com.android.settings.R;
36 import com.android.settings.dashboard.DashboardFragment;
37 import com.android.settings.search.BaseSearchIndexProvider;
38 import com.android.settingslib.search.SearchIndexable;
39 
40 import java.util.List;
41 
42 /** Settings fragment containing magnification preference. */
43 @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
44 public final class MagnificationPreferenceFragment extends DashboardFragment {
45     @VisibleForTesting static final int ON = 1;
46     @VisibleForTesting static final int OFF = 0;
47 
48     private static final String TAG = "MagnificationPreferenceFragment";
49 
50     // Settings App preference keys
51     private static final String PREFERENCE_TITLE_KEY = "magnification_preference_screen_title";
52 
53     // Pseudo ComponentName used to represent navbar magnification in Settings.Secure.
54     private static final String MAGNIFICATION_COMPONENT_ID =
55             "com.android.server.accessibility.MagnificationController";
56 
57     private boolean mLaunchedFromSuw = false;
58 
59     @Override
getMetricsCategory()60     public int getMetricsCategory() {
61         return SettingsEnums.ACCESSIBILITY_SCREEN_MAGNIFICATION_SETTINGS;
62     }
63 
64     @Override
getLogTag()65     protected String getLogTag() {
66         return TAG;
67     }
68 
69     @Override
getHelpResource()70     public int getHelpResource() {
71         return R.string.help_url_magnification;
72     }
73 
74     @Override
getPreferenceScreenResId()75     protected int getPreferenceScreenResId() {
76         return R.xml.accessibility_magnification_settings;
77     }
78 
79     @Override
onAttach(Context context)80     public void onAttach(Context context) {
81         super.onAttach(context);
82         final Bundle args = getArguments();
83         if ((args != null) && args.containsKey(AccessibilitySettings.EXTRA_LAUNCHED_FROM_SUW)) {
84             mLaunchedFromSuw = args.getBoolean(AccessibilitySettings.EXTRA_LAUNCHED_FROM_SUW);
85         }
86         use(MagnificationGesturesPreferenceController.class)
87                 .setIsFromSUW(mLaunchedFromSuw);
88         use(MagnificationNavbarPreferenceController.class)
89                 .setIsFromSUW(mLaunchedFromSuw);
90     }
91 
92     @Override
onPreferenceTreeClick(Preference preference)93     public boolean onPreferenceTreeClick(Preference preference) {
94         if (mLaunchedFromSuw) {
95             // If invoked from SUW, redirect to fragment instrumented for Vision Settings metrics
96             preference.setFragment(
97                     ToggleScreenMagnificationPreferenceFragmentForSetupWizard.class.getName());
98         }
99         return super.onPreferenceTreeClick(preference);
100     }
101 
102     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)103     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
104         if (mLaunchedFromSuw) {
105             // Do not call super. We don't want to see the "Help & feedback" on OOBE page.
106         } else {
107             super.onCreateOptionsMenu(menu, inflater);
108         }
109     }
110 
getConfigurationWarningStringForSecureSettingsKey(String key, Context context)111     static CharSequence getConfigurationWarningStringForSecureSettingsKey(String key,
112             Context context) {
113         if (!Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED.equals(key)) {
114             return null;
115         }
116         if (Settings.Secure.getInt(context.getContentResolver(),
117                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, 0) == 0) {
118             return null;
119         }
120         final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
121                 Context.ACCESSIBILITY_SERVICE);
122         final String assignedId = Settings.Secure.getString(context.getContentResolver(),
123                 Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
124         if (!TextUtils.isEmpty(assignedId) && !MAGNIFICATION_COMPONENT_ID.equals(assignedId)) {
125             final ComponentName assignedComponentName = ComponentName.unflattenFromString(
126                     assignedId);
127             final List<AccessibilityServiceInfo> activeServices =
128                     am.getEnabledAccessibilityServiceList(
129                             AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
130             final int serviceCount = activeServices.size();
131             for (int i = 0; i < serviceCount; i++) {
132                 final AccessibilityServiceInfo info = activeServices.get(i);
133                 if (info.getComponentName().equals(assignedComponentName)) {
134                     final CharSequence assignedServiceName = info.getResolveInfo().loadLabel(
135                             context.getPackageManager());
136                     final int messageId = AccessibilityUtil.isGestureNavigateEnabled(context)
137                             ? R.string.accessibility_screen_magnification_gesture_navigation_warning
138                             : R.string.accessibility_screen_magnification_navbar_configuration_warning;
139                     return context.getString(messageId, assignedServiceName);
140                 }
141             }
142         }
143         return null;
144     }
145 
isChecked(ContentResolver contentResolver, String settingsKey)146     static boolean isChecked(ContentResolver contentResolver, String settingsKey) {
147         return Settings.Secure.getInt(contentResolver, settingsKey, OFF) == ON;
148     }
149 
setChecked(ContentResolver contentResolver, String settingsKey, boolean isChecked)150     static boolean setChecked(ContentResolver contentResolver, String settingsKey,
151             boolean isChecked) {
152         return Settings.Secure.putInt(contentResolver, settingsKey, isChecked ? ON : OFF);
153     }
154 
155     /**
156      * @return {@code true} if this fragment should be shown, {@code false} otherwise. This
157      * fragment is shown in the case that more than one magnification mode is available.
158      */
isApplicable(Resources res)159     static boolean isApplicable(Resources res) {
160         return res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);
161     }
162 
163     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
164             new BaseSearchIndexProvider(R.xml.accessibility_magnification_settings) {
165 
166                 @Override
167                 protected boolean isPageSearchEnabled(Context context) {
168                     return isApplicable(context.getResources());
169                 }
170             };
171 }
172