/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.statusbar.policy; import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED; import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED; import android.annotation.Nullable; import android.hardware.devicestate.DeviceStateManager; import android.os.Trace; import android.util.IndentingPrintWriter; import androidx.annotation.NonNull; import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.util.wrapper.RotationPolicyWrapper; import java.io.PrintWriter; import java.util.concurrent.Executor; import javax.inject.Inject; /** * Handles reading and writing of rotation lock settings per device state, as well as setting the * rotation lock when device state changes. */ @SysUISingleton public final class DeviceStateRotationLockSettingController implements Listenable, RotationLockController.RotationLockControllerCallback, Dumpable { private final RotationPolicyWrapper mRotationPolicyWrapper; private final DeviceStateManager mDeviceStateManager; private final Executor mMainExecutor; private final DeviceStateRotationLockSettingsManager mDeviceStateRotationLockSettingsManager; private final DeviceStateRotationLockSettingControllerLogger mLogger; // On registration for DeviceStateCallback, we will receive a callback with the current state // and this will be initialized. private int mDeviceState = -1; @Nullable private DeviceStateManager.DeviceStateCallback mDeviceStateCallback; private DeviceStateRotationLockSettingsManager.DeviceStateRotationLockSettingsListener mDeviceStateRotationLockSettingsListener; @Inject public DeviceStateRotationLockSettingController( RotationPolicyWrapper rotationPolicyWrapper, DeviceStateManager deviceStateManager, @Main Executor executor, DeviceStateRotationLockSettingsManager deviceStateRotationLockSettingsManager, DeviceStateRotationLockSettingControllerLogger logger, DumpManager dumpManager) { mRotationPolicyWrapper = rotationPolicyWrapper; mDeviceStateManager = deviceStateManager; mMainExecutor = executor; mDeviceStateRotationLockSettingsManager = deviceStateRotationLockSettingsManager; mLogger = logger; dumpManager.registerDumpable(this); } @Override public void setListening(boolean listening) { mLogger.logListeningChange(listening); if (listening) { // Note that this is called once with the initial state of the device, even if there // is no user action. mDeviceStateCallback = this::updateDeviceState; mDeviceStateManager.registerCallback(mMainExecutor, mDeviceStateCallback); mDeviceStateRotationLockSettingsListener = () -> readPersistedSetting("deviceStateRotationLockChange", mDeviceState); mDeviceStateRotationLockSettingsManager.registerListener( mDeviceStateRotationLockSettingsListener); } else { if (mDeviceStateCallback != null) { mDeviceStateManager.unregisterCallback(mDeviceStateCallback); } if (mDeviceStateRotationLockSettingsListener != null) { mDeviceStateRotationLockSettingsManager.unregisterListener( mDeviceStateRotationLockSettingsListener); } } } @Override public void onRotationLockStateChanged(boolean newRotationLocked, boolean affordanceVisible) { int deviceState = mDeviceState; boolean currentRotationLocked = mDeviceStateRotationLockSettingsManager .isRotationLocked(deviceState); mLogger.logRotationLockStateChanged(deviceState, newRotationLocked, currentRotationLocked); if (deviceState == -1) { return; } if (newRotationLocked == currentRotationLocked) { return; } saveNewRotationLockSetting(newRotationLocked); } private void saveNewRotationLockSetting(boolean isRotationLocked) { int deviceState = mDeviceState; mLogger.logSaveNewRotationLockSetting(isRotationLocked, deviceState); mDeviceStateRotationLockSettingsManager.updateSetting(deviceState, isRotationLocked); } private void updateDeviceState(int state) { mLogger.logUpdateDeviceState(mDeviceState, state); if (Trace.isEnabled()) { Trace.traceBegin( Trace.TRACE_TAG_APP, "updateDeviceState [state=" + state + "]"); } try { if (mDeviceState == state) { return; } readPersistedSetting("updateDeviceState", state); } finally { Trace.endSection(); } } private void readPersistedSetting(String caller, int state) { int rotationLockSetting = mDeviceStateRotationLockSettingsManager.getRotationLockSetting(state); boolean shouldBeLocked = rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_LOCKED; boolean isLocked = mRotationPolicyWrapper.isRotationLocked(); mLogger.readPersistedSetting(caller, state, rotationLockSetting, shouldBeLocked, isLocked); if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) { // This should not happen. Device states that have an ignored setting, should also // specify a fallback device state which is not ignored. // We won't handle this device state. The same rotation lock setting as before should // apply and any changes to the rotation lock setting will be written for the previous // valid device state. return; } // Accept the new state mDeviceState = state; // Update the rotation policy, if needed, for this new device state if (shouldBeLocked != isLocked) { mRotationPolicyWrapper.setRotationLock(shouldBeLocked); } } @Override public void dump(@NonNull PrintWriter printWriter, @NonNull String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter); mDeviceStateRotationLockSettingsManager.dump(pw); pw.println("DeviceStateRotationLockSettingController"); pw.increaseIndent(); pw.println("mDeviceState: " + mDeviceState); pw.decreaseIndent(); } }