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.internal.policy;
18 
19 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BACK_GESTURE_EDGE_WIDTH;
20 
21 import android.content.ContentResolver;
22 import android.content.Context;
23 import android.content.res.Resources;
24 import android.database.ContentObserver;
25 import android.os.Handler;
26 import android.os.UserHandle;
27 import android.provider.DeviceConfig;
28 import android.provider.Settings;
29 import android.util.DisplayMetrics;
30 import android.util.TypedValue;
31 
32 /**
33  * @hide
34  */
35 public class GestureNavigationSettingsObserver extends ContentObserver {
36     private Context mContext;
37     private Runnable mOnChangeRunnable;
38     private Handler mMainHandler;
39 
GestureNavigationSettingsObserver(Handler handler, Context context, Runnable onChangeRunnable)40     public GestureNavigationSettingsObserver(Handler handler, Context context,
41             Runnable onChangeRunnable) {
42         super(handler);
43         mMainHandler = handler;
44         mContext = context;
45         mOnChangeRunnable = onChangeRunnable;
46     }
47 
48     private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
49             new DeviceConfig.OnPropertiesChangedListener() {
50         @Override
51         public void onPropertiesChanged(DeviceConfig.Properties properties) {
52             if (DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())
53                             && mOnChangeRunnable != null) {
54                 mOnChangeRunnable.run();
55             }
56         }
57     };
58 
59     /**
60      * Registers the observer for all users.
61      */
register()62     public void register() {
63         ContentResolver r = mContext.getContentResolver();
64         r.registerContentObserver(
65                 Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT),
66                 false, this, UserHandle.USER_ALL);
67         r.registerContentObserver(
68                 Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT),
69                 false, this, UserHandle.USER_ALL);
70         r.registerContentObserver(
71                 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE),
72                 false, this, UserHandle.USER_ALL);
73         DeviceConfig.addOnPropertiesChangedListener(
74                 DeviceConfig.NAMESPACE_SYSTEMUI,
75                 runnable -> mMainHandler.post(runnable),
76                 mOnPropertiesChangedListener);
77     }
78 
79     /**
80      * Registers the observer for the calling user.
81      */
registerForCallingUser()82     public void registerForCallingUser() {
83         ContentResolver r = mContext.getContentResolver();
84         r.registerContentObserver(
85                 Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT),
86                 false, this);
87         r.registerContentObserver(
88                 Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT),
89                 false, this);
90         r.registerContentObserver(
91                 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE),
92                 false, this);
93         DeviceConfig.addOnPropertiesChangedListener(
94                 DeviceConfig.NAMESPACE_SYSTEMUI,
95                 runnable -> mMainHandler.post(runnable),
96                 mOnPropertiesChangedListener);
97     }
98 
unregister()99     public void unregister() {
100         mContext.getContentResolver().unregisterContentObserver(this);
101         DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
102     }
103 
104     @Override
onChange(boolean selfChange)105     public void onChange(boolean selfChange) {
106         super.onChange(selfChange);
107         if (mOnChangeRunnable != null) {
108             mOnChangeRunnable.run();
109         }
110     }
111 
112     /**
113      * Returns the left sensitivity for the current user.  To be used in code that runs primarily
114      * in one user's process.
115      */
getLeftSensitivity(Resources userRes)116     public int getLeftSensitivity(Resources userRes) {
117         final float scale = Settings.Secure.getFloatForUser(mContext.getContentResolver(),
118                 Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT, 1.0f, UserHandle.USER_CURRENT);
119         return (int) (getUnscaledInset(userRes) * scale);
120     }
121 
122     /**
123      * Returns the left sensitivity for the calling user.  To be used in code that runs in a
124      * per-user process.
125      */
126     @SuppressWarnings("NonUserGetterCalled")
getLeftSensitivityForCallingUser(Resources userRes)127     public int getLeftSensitivityForCallingUser(Resources userRes) {
128         final float scale = Settings.Secure.getFloat(mContext.getContentResolver(),
129                 Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT, 1.0f);
130         return (int) (getUnscaledInset(userRes) * scale);
131     }
132 
133     /**
134      * Returns the right sensitivity for the current user.  To be used in code that runs primarily
135      * in one user's process.
136      */
getRightSensitivity(Resources userRes)137     public int getRightSensitivity(Resources userRes) {
138         final float scale = Settings.Secure.getFloatForUser(mContext.getContentResolver(),
139                 Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT, 1.0f, UserHandle.USER_CURRENT);
140         return (int) (getUnscaledInset(userRes) * scale);
141     }
142 
143     /**
144      * Returns the right sensitivity for the calling user.  To be used in code that runs in a
145      * per-user process.
146      */
147     @SuppressWarnings("NonUserGetterCalled")
getRightSensitivityForCallingUser(Resources userRes)148     public int getRightSensitivityForCallingUser(Resources userRes) {
149         final float scale = Settings.Secure.getFloat(mContext.getContentResolver(),
150                 Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT, 1.0f);
151         return (int) (getUnscaledInset(userRes) * scale);
152     }
153 
areNavigationButtonForcedVisible()154     public boolean areNavigationButtonForcedVisible() {
155         return Settings.Secure.getIntForUser(mContext.getContentResolver(),
156                 Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) == 0;
157     }
158 
getUnscaledInset(Resources userRes)159     private float getUnscaledInset(Resources userRes) {
160         final DisplayMetrics dm = userRes.getDisplayMetrics();
161         final float defaultInset = userRes.getDimension(
162                 com.android.internal.R.dimen.config_backGestureInset) / dm.density;
163         // Only apply the back gesture config if there is an existing inset
164         final float backGestureInset = defaultInset > 0
165                 ? DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI,
166                         BACK_GESTURE_EDGE_WIDTH, defaultInset)
167                 : defaultInset;
168         final float inset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, backGestureInset,
169                 dm);
170         return inset;
171     }
172 }
173