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