1 /*
2  * Copyright (C) 2020 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 android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
20 
21 import static com.android.systemui.accessibility.MagnificationModeSwitch.ClickListener;
22 
23 import android.annotation.MainThread;
24 import android.content.Context;
25 import android.hardware.display.DisplayManager;
26 import android.view.Display;
27 
28 import com.android.internal.annotations.VisibleForTesting;
29 import com.android.systemui.dagger.SysUISingleton;
30 
31 import javax.inject.Inject;
32 
33 /**
34  * A class to control {@link MagnificationModeSwitch}. It shows the button UI with following
35  * conditions:
36  * <ol>
37  *   <li> Both full-screen and window magnification mode are capable.</li>
38  *   <li> The magnification scale is changed by a user.</li>
39  * <ol>
40  * The click action will be handled by {@link #mClickListenerDelegate} which opens the
41  * {@link WindowMagnificationSettings} panel.
42  */
43 @SysUISingleton
44 public class ModeSwitchesController implements ClickListener {
45 
46     private final DisplayIdIndexSupplier<MagnificationModeSwitch> mSwitchSupplier;
47     private ClickListener mClickListenerDelegate;
48 
49     @Inject
ModeSwitchesController(Context context, DisplayManager displayManager)50     public ModeSwitchesController(Context context, DisplayManager displayManager) {
51         mSwitchSupplier = new SwitchSupplier(context, displayManager, this::onClick);
52     }
53 
54     @VisibleForTesting
ModeSwitchesController(DisplayIdIndexSupplier<MagnificationModeSwitch> switchSupplier)55     ModeSwitchesController(DisplayIdIndexSupplier<MagnificationModeSwitch> switchSupplier) {
56         mSwitchSupplier = switchSupplier;
57     }
58 
59     /**
60      * Shows a button that a user can click to switch magnification mode. And the button
61      * would be dismissed automatically after the button is displayed for a period of time.
62      *
63      * @param displayId The logical display id
64      * @param mode      The magnification mode
65      * @see android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
66      * @see android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
67      */
68     @MainThread
showButton(int displayId, int mode)69     void showButton(int displayId, int mode) {
70         final MagnificationModeSwitch magnificationModeSwitch =
71                 mSwitchSupplier.get(displayId);
72         if (magnificationModeSwitch == null) {
73             return;
74         }
75         magnificationModeSwitch.showButton(mode);
76     }
77 
78     /**
79      * Removes magnification mode switch button immediately.
80      *
81      * @param displayId The logical display id
82      */
removeButton(int displayId)83     void removeButton(int displayId) {
84         final MagnificationModeSwitch magnificationModeSwitch =
85                 mSwitchSupplier.get(displayId);
86         if (magnificationModeSwitch == null) {
87             return;
88         }
89         magnificationModeSwitch.removeButton();
90     }
91 
92     /**
93      * Called when the configuration has changed, and it updates magnification button UI.
94      *
95      * @param configDiff a bit mask of the differences between the configurations
96      */
97     @MainThread
onConfigurationChanged(int configDiff)98     void onConfigurationChanged(int configDiff) {
99         mSwitchSupplier.forEach(
100                 switchController -> switchController.onConfigurationChanged(configDiff));
101     }
102 
103     @Override
onClick(int displayId)104     public void onClick(int displayId) {
105         if (mClickListenerDelegate != null) {
106             mClickListenerDelegate.onClick(displayId);
107         }
108     }
109 
setClickListenerDelegate(ClickListener clickListenerDelegate)110     public void setClickListenerDelegate(ClickListener clickListenerDelegate) {
111         mClickListenerDelegate = clickListenerDelegate;
112     }
113 
114     private static class SwitchSupplier extends DisplayIdIndexSupplier<MagnificationModeSwitch> {
115 
116         private final Context mContext;
117         private final ClickListener mClickListener;
118 
119         /**
120          * Supplies the switch for the given display.
121          *
122          * @param context        Context
123          * @param displayManager DisplayManager
124          * @param clickListener The callback that will run when the switch is clicked
125          */
SwitchSupplier(Context context, DisplayManager displayManager, ClickListener clickListener)126         SwitchSupplier(Context context, DisplayManager displayManager,
127                 ClickListener clickListener) {
128             super(displayManager);
129             mContext = context;
130             mClickListener = clickListener;
131         }
132 
133         @Override
createInstance(Display display)134         protected MagnificationModeSwitch createInstance(Display display) {
135             final Context uiContext = mContext.createWindowContext(display,
136                     TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, /* options */ null);
137             return new MagnificationModeSwitch(uiContext, mClickListener);
138         }
139     }
140 }
141