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