• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.gestures;
18 
19 import static android.os.UserHandle.USER_CURRENT;
20 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
21 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
22 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
23 
24 import android.app.settings.SettingsEnums;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.SharedPreferences;
28 import android.content.om.IOverlayManager;
29 import android.content.om.OverlayInfo;
30 import android.os.RemoteException;
31 import android.os.ServiceManager;
32 import android.provider.Settings;
33 
34 import androidx.annotation.VisibleForTesting;
35 import androidx.preference.PreferenceScreen;
36 
37 import com.android.settings.R;
38 import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
39 import com.android.settings.overlay.FeatureFactory;
40 import com.android.settings.search.BaseSearchIndexProvider;
41 import com.android.settings.support.actionbar.HelpResourceProvider;
42 import com.android.settings.utils.CandidateInfoExtra;
43 import com.android.settings.widget.RadioButtonPickerFragment;
44 import com.android.settingslib.search.SearchIndexable;
45 import com.android.settingslib.widget.CandidateInfo;
46 import com.android.settingslib.widget.IllustrationPreference;
47 import com.android.settingslib.widget.RadioButtonPreference;
48 
49 import java.util.ArrayList;
50 import java.util.List;
51 
52 @SearchIndexable
53 public class SystemNavigationGestureSettings extends RadioButtonPickerFragment implements
54         HelpResourceProvider {
55 
56     private static final String TAG = "SystemNavigationGesture";
57 
58     @VisibleForTesting
59     static final String KEY_SYSTEM_NAV_3BUTTONS = "system_nav_3buttons";
60     @VisibleForTesting
61     static final String KEY_SYSTEM_NAV_2BUTTONS = "system_nav_2buttons";
62     @VisibleForTesting
63     static final String KEY_SYSTEM_NAV_GESTURAL = "system_nav_gestural";
64 
65     public static final String PREF_KEY_SUGGESTION_COMPLETE =
66             "pref_system_navigation_suggestion_complete";
67 
68     private IOverlayManager mOverlayManager;
69 
70     private IllustrationPreference mVideoPreference;
71 
72     @Override
onAttach(Context context)73     public void onAttach(Context context) {
74         super.onAttach(context);
75 
76         SuggestionFeatureProvider suggestionFeatureProvider = FeatureFactory.getFactory(context)
77                 .getSuggestionFeatureProvider(context);
78         SharedPreferences prefs = suggestionFeatureProvider.getSharedPrefs(context);
79         prefs.edit().putBoolean(PREF_KEY_SUGGESTION_COMPLETE, true).apply();
80 
81         mOverlayManager = IOverlayManager.Stub.asInterface(
82                 ServiceManager.getService(Context.OVERLAY_SERVICE));
83 
84         mVideoPreference = new IllustrationPreference(context);
85         setIllustrationVideo(mVideoPreference, getDefaultKey());
86 
87         migrateOverlaySensitivityToSettings(context, mOverlayManager);
88     }
89 
90     @Override
getMetricsCategory()91     public int getMetricsCategory() {
92         return SettingsEnums.SETTINGS_GESTURE_SWIPE_UP;
93     }
94 
95     @Override
updateCandidates()96     public void updateCandidates() {
97         final String defaultKey = getDefaultKey();
98         final String systemDefaultKey = getSystemDefaultKey();
99         final PreferenceScreen screen = getPreferenceScreen();
100         screen.removeAll();
101         screen.addPreference(mVideoPreference);
102 
103         final List<? extends CandidateInfo> candidateList = getCandidates();
104         if (candidateList == null) {
105             return;
106         }
107         for (CandidateInfo info : candidateList) {
108             RadioButtonPreference pref =
109                     new RadioButtonPreference(getPrefContext());
110             bindPreference(pref, info.getKey(), info, defaultKey);
111             bindPreferenceExtra(pref, info.getKey(), info, defaultKey, systemDefaultKey);
112             screen.addPreference(pref);
113         }
114         mayCheckOnlyRadioButton();
115     }
116 
117     @Override
bindPreferenceExtra(RadioButtonPreference pref, String key, CandidateInfo info, String defaultKey, String systemDefaultKey)118     public void bindPreferenceExtra(RadioButtonPreference pref,
119             String key, CandidateInfo info, String defaultKey, String systemDefaultKey) {
120         if (!(info instanceof CandidateInfoExtra)) {
121             return;
122         }
123 
124         pref.setSummary(((CandidateInfoExtra) info).loadSummary());
125 
126         if (info.getKey() == KEY_SYSTEM_NAV_GESTURAL) {
127             pref.setExtraWidgetOnClickListener((v) -> startActivity(new Intent(
128                     GestureNavigationSettingsFragment.GESTURE_NAVIGATION_SETTINGS)));
129         }
130     }
131 
132     @Override
getPreferenceScreenResId()133     protected int getPreferenceScreenResId() {
134         return R.xml.system_navigation_gesture_settings;
135     }
136 
137     @Override
getCandidates()138     protected List<? extends CandidateInfo> getCandidates() {
139         final Context c = getContext();
140         List<CandidateInfoExtra> candidates = new ArrayList<>();
141 
142         if (SystemNavigationPreferenceController.isOverlayPackageAvailable(c,
143                 NAV_BAR_MODE_GESTURAL_OVERLAY)) {
144             candidates.add(new CandidateInfoExtra(
145                     c.getText(R.string.edge_to_edge_navigation_title),
146                     c.getText(R.string.edge_to_edge_navigation_summary),
147                     KEY_SYSTEM_NAV_GESTURAL, true /* enabled */));
148         }
149         if (SystemNavigationPreferenceController.isOverlayPackageAvailable(c,
150                 NAV_BAR_MODE_2BUTTON_OVERLAY)) {
151             candidates.add(new CandidateInfoExtra(
152                     c.getText(R.string.swipe_up_to_switch_apps_title),
153                     c.getText(R.string.swipe_up_to_switch_apps_summary),
154                     KEY_SYSTEM_NAV_2BUTTONS, true /* enabled */));
155         }
156         if (SystemNavigationPreferenceController.isOverlayPackageAvailable(c,
157                 NAV_BAR_MODE_3BUTTON_OVERLAY)) {
158             candidates.add(new CandidateInfoExtra(
159                     c.getText(R.string.legacy_navigation_title),
160                     c.getText(R.string.legacy_navigation_summary),
161                     KEY_SYSTEM_NAV_3BUTTONS, true /* enabled */));
162         }
163 
164         return candidates;
165     }
166 
167     @Override
getDefaultKey()168     protected String getDefaultKey() {
169         return getCurrentSystemNavigationMode(getContext());
170     }
171 
172     @Override
setDefaultKey(String key)173     protected boolean setDefaultKey(String key) {
174         setCurrentSystemNavigationMode(mOverlayManager, key);
175         setIllustrationVideo(mVideoPreference, key);
176 
177         return true;
178     }
179 
migrateOverlaySensitivityToSettings(Context context, IOverlayManager overlayManager)180     static void migrateOverlaySensitivityToSettings(Context context,
181             IOverlayManager overlayManager) {
182         if (!SystemNavigationPreferenceController.isGestureNavigationEnabled(context)) {
183             return;
184         }
185 
186         OverlayInfo info = null;
187         try {
188             info = overlayManager.getOverlayInfo(NAV_BAR_MODE_GESTURAL_OVERLAY, USER_CURRENT);
189         } catch (RemoteException e) { /* Do nothing */ }
190         if (info != null && !info.isEnabled()) {
191             // Enable the default gesture nav overlay. Back sensitivity for left and right are
192             // stored as separate settings values, and other gesture nav overlays are deprecated.
193             setCurrentSystemNavigationMode(overlayManager, KEY_SYSTEM_NAV_GESTURAL);
194             Settings.Secure.putFloat(context.getContentResolver(),
195                     Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT, 1.0f);
196             Settings.Secure.putFloat(context.getContentResolver(),
197                     Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT, 1.0f);
198         }
199     }
200 
201     @VisibleForTesting
getCurrentSystemNavigationMode(Context context)202     static String getCurrentSystemNavigationMode(Context context) {
203         if (SystemNavigationPreferenceController.isGestureNavigationEnabled(context)) {
204             return KEY_SYSTEM_NAV_GESTURAL;
205         } else if (SystemNavigationPreferenceController.is2ButtonNavigationEnabled(context)) {
206             return KEY_SYSTEM_NAV_2BUTTONS;
207         } else {
208             return KEY_SYSTEM_NAV_3BUTTONS;
209         }
210     }
211 
212     @VisibleForTesting
setCurrentSystemNavigationMode(IOverlayManager overlayManager, String key)213     static void setCurrentSystemNavigationMode(IOverlayManager overlayManager, String key) {
214         String overlayPackage = NAV_BAR_MODE_GESTURAL_OVERLAY;
215         switch (key) {
216             case KEY_SYSTEM_NAV_GESTURAL:
217                 overlayPackage = NAV_BAR_MODE_GESTURAL_OVERLAY;
218                 break;
219             case KEY_SYSTEM_NAV_2BUTTONS:
220                 overlayPackage = NAV_BAR_MODE_2BUTTON_OVERLAY;
221                 break;
222             case KEY_SYSTEM_NAV_3BUTTONS:
223                 overlayPackage = NAV_BAR_MODE_3BUTTON_OVERLAY;
224                 break;
225         }
226 
227         try {
228             overlayManager.setEnabledExclusiveInCategory(overlayPackage, USER_CURRENT);
229         } catch (RemoteException e) {
230             throw e.rethrowFromSystemServer();
231         }
232     }
233 
setIllustrationVideo(IllustrationPreference videoPref, String systemNavKey)234     private static void setIllustrationVideo(IllustrationPreference videoPref,
235             String systemNavKey) {
236         switch (systemNavKey) {
237             case KEY_SYSTEM_NAV_GESTURAL:
238                 videoPref.setLottieAnimationResId(R.raw.lottie_system_nav_fully_gestural);
239                 break;
240             case KEY_SYSTEM_NAV_2BUTTONS:
241                 videoPref.setLottieAnimationResId(R.raw.lottie_system_nav_2_button);
242                 break;
243             case KEY_SYSTEM_NAV_3BUTTONS:
244                 videoPref.setLottieAnimationResId(R.raw.lottie_system_nav_3_button);
245                 break;
246         }
247     }
248 
249     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
250             new BaseSearchIndexProvider(R.xml.system_navigation_gesture_settings) {
251 
252                 @Override
253                 protected boolean isPageSearchEnabled(Context context) {
254                     return SystemNavigationPreferenceController.isGestureAvailable(context);
255                 }
256             };
257 
258     // From HelpResourceProvider
259     @Override
getHelpResource()260     public int getHelpResource() {
261         // TODO(b/146001201): Replace with system navigation help page when ready.
262         return R.string.help_uri_default;
263     }
264 }
265