1 /*
2  * Copyright (C) 2023 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.systemui.accessibility;
18 
19 import static com.android.systemui.accessibility.WindowMagnificationSettings.MagnificationSize;
20 
21 import android.annotation.NonNull;
22 import android.annotation.UiContext;
23 import android.content.ComponentCallbacks;
24 import android.content.Context;
25 import android.content.res.Configuration;
26 import android.util.Range;
27 import android.view.WindowManager;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
31 import com.android.systemui.util.settings.SecureSettings;
32 
33 /**
34  * A class to control {@link WindowMagnificationSettings} and receive settings panel callbacks by
35  * {@link WindowMagnificationSettingsCallback}.
36  * The settings panel callbacks will be delegated through
37  * {@link MagnificationSettingsController.Callback} to {@link Magnification}.
38  */
39 
40 public class MagnificationSettingsController implements ComponentCallbacks {
41 
42     // It should be consistent with the value defined in WindowMagnificationGestureHandler.
43     private static final Range<Float> A11Y_ACTION_SCALE_RANGE = new Range<>(1.0f, 8.0f);
44 
45     private final Context mContext;
46 
47     private final int mDisplayId;
48 
49     @NonNull
50     private final Callback mSettingsControllerCallback;
51 
52     // Window Magnification Setting view
53     private WindowMagnificationSettings mWindowMagnificationSettings;
54 
55     private final Configuration mConfiguration;
56 
MagnificationSettingsController( @iContext Context context, SfVsyncFrameCallbackProvider sfVsyncFrameProvider, @NonNull Callback settingsControllerCallback, SecureSettings secureSettings)57     MagnificationSettingsController(
58             @UiContext Context context,
59             SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
60             @NonNull Callback settingsControllerCallback,
61             SecureSettings secureSettings) {
62         this(context, sfVsyncFrameProvider, settingsControllerCallback,  secureSettings, null);
63     }
64 
65     @VisibleForTesting
MagnificationSettingsController( @iContext Context context, SfVsyncFrameCallbackProvider sfVsyncFrameProvider, @NonNull Callback settingsControllerCallback, SecureSettings secureSettings, WindowMagnificationSettings windowMagnificationSettings)66     MagnificationSettingsController(
67             @UiContext Context context,
68             SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
69             @NonNull Callback settingsControllerCallback,
70             SecureSettings secureSettings,
71             WindowMagnificationSettings windowMagnificationSettings) {
72         mContext = context.createWindowContext(
73                 context.getDisplay(),
74                 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
75                 null);
76         mContext.setTheme(com.android.systemui.res.R.style.Theme_SystemUI);
77         mDisplayId = mContext.getDisplayId();
78         mConfiguration = new Configuration(mContext.getResources().getConfiguration());
79         mSettingsControllerCallback = settingsControllerCallback;
80         if (windowMagnificationSettings != null) {
81             mWindowMagnificationSettings = windowMagnificationSettings;
82         } else {
83             mWindowMagnificationSettings = new WindowMagnificationSettings(mContext,
84                     mWindowMagnificationSettingsCallback,
85                     sfVsyncFrameProvider, secureSettings);
86         }
87     }
88 
89     /**
90      * Toggles the visibility of magnification settings panel {@link WindowMagnificationSettings}.
91      * We show the panel if it is not visible. Otherwise, hide the panel.
92      */
toggleSettingsPanelVisibility()93     void toggleSettingsPanelVisibility() {
94         if (!mWindowMagnificationSettings.isSettingPanelShowing()) {
95             onConfigurationChanged(mContext.getResources().getConfiguration());
96             mContext.registerComponentCallbacks(this);
97         }
98         mWindowMagnificationSettings.toggleSettingsPanelVisibility();
99     }
100 
closeMagnificationSettings()101     void closeMagnificationSettings() {
102         mContext.unregisterComponentCallbacks(this);
103         mWindowMagnificationSettings.hideSettingPanel();
104     }
105 
isMagnificationSettingsShowing()106     boolean isMagnificationSettingsShowing() {
107         return mWindowMagnificationSettings.isSettingPanelShowing();
108     }
109 
setMagnificationScale(float scale)110     void setMagnificationScale(float scale) {
111         mWindowMagnificationSettings.setMagnificationScale(scale);
112     }
113 
114     @Override
onConfigurationChanged(@onNull Configuration newConfig)115     public void onConfigurationChanged(@NonNull Configuration newConfig) {
116         final int configDiff = newConfig.diff(mConfiguration);
117         mConfiguration.setTo(newConfig);
118         onConfigurationChanged(configDiff);
119     }
120 
121     @VisibleForTesting
onConfigurationChanged(int configDiff)122     void onConfigurationChanged(int configDiff) {
123         mWindowMagnificationSettings.onConfigurationChanged(configDiff);
124     }
125 
126     @Override
onLowMemory()127     public void onLowMemory() {
128 
129     }
130 
131     interface Callback {
132 
133         /**
134          * Called when change magnification size.
135          *
136          * @param displayId The logical display id.
137          * @param index Magnification size index.
138          *     0 : MagnificationSize.NONE,
139          *     1 : MagnificationSize.SMALL,
140          *     2 : MagnificationSize.MEDIUM,
141          *     3 : MagnificationSize.LARGE,
142          *     4 : MagnificationSize.FULLSCREEN
143          */
onSetMagnifierSize(int displayId, @MagnificationSize int index)144         void onSetMagnifierSize(int displayId, @MagnificationSize int index);
145 
146         /**
147          * Called when set allow diagonal scrolling.
148          *
149          * @param displayId The logical display id.
150          * @param enable Allow diagonal scrolling enable value.
151          */
onSetDiagonalScrolling(int displayId, boolean enable)152         void onSetDiagonalScrolling(int displayId, boolean enable);
153 
154         /**
155          * Called when change magnification size on free mode.
156          *
157          * @param displayId The logical display id.
158          * @param enable Free mode enable value.
159          */
onEditMagnifierSizeMode(int displayId, boolean enable)160         void onEditMagnifierSizeMode(int displayId, boolean enable);
161 
162         /**
163          * Called when set magnification scale.
164          *
165          * @param displayId The logical display id.
166          * @param scale Magnification scale value.
167          * @param updatePersistence whether the new scale should be persisted.
168          */
onMagnifierScale(int displayId, float scale, boolean updatePersistence)169         void onMagnifierScale(int displayId, float scale, boolean updatePersistence);
170 
171         /**
172          * Called when magnification mode changed.
173          *
174          * @param displayId The logical display id.
175          * @param newMode Magnification mode
176          *      1 : ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN,
177          *      2 : ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
178          */
onModeSwitch(int displayId, int newMode)179         void onModeSwitch(int displayId, int newMode);
180 
181         /**
182          * Called when the visibility of the magnification settings panel changed.
183          *
184          * @param displayId The logical display id.
185          * @param shown The visibility of the magnification settings panel.
186          */
onSettingsPanelVisibilityChanged(int displayId, boolean shown)187         void onSettingsPanelVisibilityChanged(int displayId, boolean shown);
188     }
189 
190     @VisibleForTesting
191     final WindowMagnificationSettingsCallback mWindowMagnificationSettingsCallback =
192             new WindowMagnificationSettingsCallback() {
193                 @Override
194         public void onSetDiagonalScrolling(boolean enable) {
195             mSettingsControllerCallback.onSetDiagonalScrolling(mDisplayId, enable);
196         }
197 
198         @Override
199         public void onModeSwitch(int newMode) {
200             mSettingsControllerCallback.onModeSwitch(mDisplayId, newMode);
201         }
202 
203         @Override
204         public void onSettingsPanelVisibilityChanged(boolean shown) {
205             mSettingsControllerCallback.onSettingsPanelVisibilityChanged(mDisplayId, shown);
206         }
207 
208         @Override
209         public void onSetMagnifierSize(@MagnificationSize int index) {
210             mSettingsControllerCallback.onSetMagnifierSize(mDisplayId, index);
211         }
212 
213         @Override
214         public void onEditMagnifierSizeMode(boolean enable) {
215             mSettingsControllerCallback.onEditMagnifierSizeMode(mDisplayId, enable);
216         }
217 
218         @Override
219         public void onMagnifierScale(float scale, boolean updatePersistence) {
220             mSettingsControllerCallback.onMagnifierScale(mDisplayId,
221                     A11Y_ACTION_SCALE_RANGE.clamp(scale), updatePersistence);
222         }
223     };
224 }
225