1 /* 2 * Copyright (C) 2021 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.statusbar.policy; 18 19 import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED; 20 import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED; 21 22 import android.annotation.Nullable; 23 import android.hardware.devicestate.DeviceStateManager; 24 import android.os.Trace; 25 import android.util.IndentingPrintWriter; 26 27 import androidx.annotation.NonNull; 28 29 import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; 30 import com.android.systemui.Dumpable; 31 import com.android.systemui.dagger.SysUISingleton; 32 import com.android.systemui.dagger.qualifiers.Main; 33 import com.android.systemui.dump.DumpManager; 34 import com.android.systemui.util.wrapper.RotationPolicyWrapper; 35 36 import java.io.PrintWriter; 37 import java.util.concurrent.Executor; 38 39 import javax.inject.Inject; 40 41 /** 42 * Handles reading and writing of rotation lock settings per device state, as well as setting the 43 * rotation lock when device state changes. 44 */ 45 @SysUISingleton 46 public final class DeviceStateRotationLockSettingController 47 implements Listenable, RotationLockController.RotationLockControllerCallback, Dumpable { 48 49 private final RotationPolicyWrapper mRotationPolicyWrapper; 50 private final DeviceStateManager mDeviceStateManager; 51 private final Executor mMainExecutor; 52 private final DeviceStateRotationLockSettingsManager mDeviceStateRotationLockSettingsManager; 53 private final DeviceStateRotationLockSettingControllerLogger mLogger; 54 55 // On registration for DeviceStateCallback, we will receive a callback with the current state 56 // and this will be initialized. 57 private int mDeviceState = -1; 58 @Nullable 59 private DeviceStateManager.DeviceStateCallback mDeviceStateCallback; 60 private DeviceStateRotationLockSettingsManager.DeviceStateRotationLockSettingsListener 61 mDeviceStateRotationLockSettingsListener; 62 63 @Inject DeviceStateRotationLockSettingController( RotationPolicyWrapper rotationPolicyWrapper, DeviceStateManager deviceStateManager, @Main Executor executor, DeviceStateRotationLockSettingsManager deviceStateRotationLockSettingsManager, DeviceStateRotationLockSettingControllerLogger logger, DumpManager dumpManager)64 public DeviceStateRotationLockSettingController( 65 RotationPolicyWrapper rotationPolicyWrapper, 66 DeviceStateManager deviceStateManager, 67 @Main Executor executor, 68 DeviceStateRotationLockSettingsManager deviceStateRotationLockSettingsManager, 69 DeviceStateRotationLockSettingControllerLogger logger, 70 DumpManager dumpManager) { 71 mRotationPolicyWrapper = rotationPolicyWrapper; 72 mDeviceStateManager = deviceStateManager; 73 mMainExecutor = executor; 74 mDeviceStateRotationLockSettingsManager = deviceStateRotationLockSettingsManager; 75 mLogger = logger; 76 dumpManager.registerDumpable(this); 77 } 78 79 @Override setListening(boolean listening)80 public void setListening(boolean listening) { 81 mLogger.logListeningChange(listening); 82 if (listening) { 83 // Note that this is called once with the initial state of the device, even if there 84 // is no user action. 85 mDeviceStateCallback = this::updateDeviceState; 86 mDeviceStateManager.registerCallback(mMainExecutor, mDeviceStateCallback); 87 mDeviceStateRotationLockSettingsListener = () -> 88 readPersistedSetting("deviceStateRotationLockChange", mDeviceState); 89 mDeviceStateRotationLockSettingsManager.registerListener( 90 mDeviceStateRotationLockSettingsListener); 91 } else { 92 if (mDeviceStateCallback != null) { 93 mDeviceStateManager.unregisterCallback(mDeviceStateCallback); 94 } 95 if (mDeviceStateRotationLockSettingsListener != null) { 96 mDeviceStateRotationLockSettingsManager.unregisterListener( 97 mDeviceStateRotationLockSettingsListener); 98 } 99 } 100 } 101 102 @Override onRotationLockStateChanged(boolean newRotationLocked, boolean affordanceVisible)103 public void onRotationLockStateChanged(boolean newRotationLocked, boolean affordanceVisible) { 104 int deviceState = mDeviceState; 105 boolean currentRotationLocked = mDeviceStateRotationLockSettingsManager 106 .isRotationLocked(deviceState); 107 mLogger.logRotationLockStateChanged(deviceState, newRotationLocked, currentRotationLocked); 108 if (deviceState == -1) { 109 return; 110 } 111 if (newRotationLocked == currentRotationLocked) { 112 return; 113 } 114 saveNewRotationLockSetting(newRotationLocked); 115 } 116 saveNewRotationLockSetting(boolean isRotationLocked)117 private void saveNewRotationLockSetting(boolean isRotationLocked) { 118 int deviceState = mDeviceState; 119 mLogger.logSaveNewRotationLockSetting(isRotationLocked, deviceState); 120 mDeviceStateRotationLockSettingsManager.updateSetting(deviceState, isRotationLocked); 121 } 122 updateDeviceState(int state)123 private void updateDeviceState(int state) { 124 mLogger.logUpdateDeviceState(mDeviceState, state); 125 if (Trace.isEnabled()) { 126 Trace.traceBegin( 127 Trace.TRACE_TAG_APP, "updateDeviceState [state=" + state + "]"); 128 } 129 try { 130 if (mDeviceState == state) { 131 return; 132 } 133 134 readPersistedSetting("updateDeviceState", state); 135 } finally { 136 Trace.endSection(); 137 } 138 } 139 readPersistedSetting(String caller, int state)140 private void readPersistedSetting(String caller, int state) { 141 int rotationLockSetting = 142 mDeviceStateRotationLockSettingsManager.getRotationLockSetting(state); 143 boolean shouldBeLocked = rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_LOCKED; 144 boolean isLocked = mRotationPolicyWrapper.isRotationLocked(); 145 146 mLogger.readPersistedSetting(caller, state, rotationLockSetting, shouldBeLocked, isLocked); 147 148 if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) { 149 // This should not happen. Device states that have an ignored setting, should also 150 // specify a fallback device state which is not ignored. 151 // We won't handle this device state. The same rotation lock setting as before should 152 // apply and any changes to the rotation lock setting will be written for the previous 153 // valid device state. 154 return; 155 } 156 157 // Accept the new state 158 mDeviceState = state; 159 160 // Update the rotation policy, if needed, for this new device state 161 if (shouldBeLocked != isLocked) { 162 mRotationPolicyWrapper.setRotationLock(shouldBeLocked); 163 } 164 } 165 166 @Override dump(@onNull PrintWriter printWriter, @NonNull String[] args)167 public void dump(@NonNull PrintWriter printWriter, @NonNull String[] args) { 168 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter); 169 mDeviceStateRotationLockSettingsManager.dump(pw); 170 pw.println("DeviceStateRotationLockSettingController"); 171 pw.increaseIndent(); 172 pw.println("mDeviceState: " + mDeviceState); 173 pw.decreaseIndent(); 174 } 175 } 176