Merge "Extract device state rotation lock settings management to a separate class. This will be followed-up by a CL moving it to SettingsLib so it can be shared with Settings"

This commit is contained in:
Alex Florescu 2022-01-17 09:53:17 +00:00 committed by Android (Google) Code Review
commit 491bd1a6fb
7 changed files with 406 additions and 217 deletions

View File

@ -10525,7 +10525,7 @@ public final class Settings {
DEVICE_STATE_ROTATION_LOCK_UNLOCKED,
})
@Retention(RetentionPolicy.SOURCE)
@interface DeviceStateRotationLockSetting {
public @interface DeviceStateRotationLockSetting {
}
/**

View File

@ -16,110 +16,53 @@
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 static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED;
import static com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule.DEVICE_STATE_ROTATION_LOCK_DEFAULTS;
import android.annotation.Nullable;
import android.hardware.devicestate.DeviceStateManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseIntArray;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;
import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
/**
* Handles reading and writing of rotation lock settings per device state, as well as setting
* the rotation lock when device state changes.
**/
* 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 {
public final class DeviceStateRotationLockSettingController
implements Listenable, RotationLockController.RotationLockControllerCallback {
private static final String TAG = "DSRotateLockSettingCon";
private static final String SEPARATOR_REGEX = ":";
private final SecureSettings mSecureSettings;
private final RotationPolicyWrapper mRotationPolicyWrapper;
private final DeviceStateManager mDeviceStateManager;
private final Executor mMainExecutor;
private final String[] mDeviceStateRotationLockDefaults;
private final DeviceStateRotationLockSettingsManager mDeviceStateRotationLockSettingsManager;
private SparseIntArray mDeviceStateRotationLockSettings;
// TODO(b/183001527): Add API to query current device state and initialize this.
// 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;
@Nullable private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
private DeviceStateRotationLockSettingsManager.DeviceStateRotationLockSettingsListener
mDeviceStateRotationLockSettingsListener;
@Inject
public DeviceStateRotationLockSettingController(
SecureSettings secureSettings,
RotationPolicyWrapper rotationPolicyWrapper,
DeviceStateManager deviceStateManager,
@Main Executor executor,
@Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS) String[] deviceStateRotationLockDefaults
) {
mSecureSettings = secureSettings;
DeviceStateRotationLockSettingsManager deviceStateRotationLockSettingsManager) {
mRotationPolicyWrapper = rotationPolicyWrapper;
mDeviceStateManager = deviceStateManager;
mMainExecutor = executor;
mDeviceStateRotationLockDefaults = deviceStateRotationLockDefaults;
}
/**
* Loads the settings from storage.
*/
public void initialize() {
String serializedSetting =
mSecureSettings.getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
UserHandle.USER_CURRENT);
if (TextUtils.isEmpty(serializedSetting)) {
// No settings saved, we should load the defaults and persist them.
fallbackOnDefaults();
return;
}
String[] values = serializedSetting.split(SEPARATOR_REGEX);
if (values.length % 2 != 0) {
// Each entry should be a key/value pair, so this is corrupt.
Log.wtf(TAG, "Can't deserialize saved settings, falling back on defaults");
fallbackOnDefaults();
return;
}
mDeviceStateRotationLockSettings = new SparseIntArray(values.length / 2);
int key;
int value;
for (int i = 0; i < values.length - 1; ) {
try {
key = Integer.parseInt(values[i++]);
value = Integer.parseInt(values[i++]);
mDeviceStateRotationLockSettings.put(key, value);
} catch (NumberFormatException e) {
Log.wtf(TAG, "Error deserializing one of the saved settings", e);
fallbackOnDefaults();
return;
}
}
}
private void fallbackOnDefaults() {
loadDefaults();
persistSettings();
mDeviceStateRotationLockSettingsManager = deviceStateRotationLockSettingsManager;
}
@Override
@ -129,10 +72,17 @@ public final class DeviceStateRotationLockSettingController implements Listenabl
// is no user action.
mDeviceStateCallback = this::updateDeviceState;
mDeviceStateManager.registerCallback(mMainExecutor, mDeviceStateCallback);
mDeviceStateRotationLockSettingsListener = () -> readPersistedSetting(mDeviceState);
mDeviceStateRotationLockSettingsManager.registerListener(
mDeviceStateRotationLockSettingsListener);
} else {
if (mDeviceStateCallback != null) {
mDeviceStateManager.unregisterCallback(mDeviceStateCallback);
}
if (mDeviceStateRotationLockSettingsListener != null) {
mDeviceStateRotationLockSettingsManager.unregisterListener(
mDeviceStateRotationLockSettingsListener);
}
}
}
@ -143,7 +93,8 @@ public final class DeviceStateRotationLockSettingController implements Listenabl
return;
}
if (rotationLocked == isRotationLockedForCurrentState()) {
if (rotationLocked
== mDeviceStateRotationLockSettingsManager.isRotationLocked(mDeviceState)) {
Log.v(TAG, "Rotation lock same as the current setting, no need to update.");
return;
}
@ -152,19 +103,15 @@ public final class DeviceStateRotationLockSettingController implements Listenabl
}
private void saveNewRotationLockSetting(boolean isRotationLocked) {
Log.v(TAG, "saveNewRotationLockSetting [state=" + mDeviceState + "] [isRotationLocked="
+ isRotationLocked + "]");
Log.v(
TAG,
"saveNewRotationLockSetting [state="
+ mDeviceState
+ "] [isRotationLocked="
+ isRotationLocked
+ "]");
mDeviceStateRotationLockSettings.put(mDeviceState,
isRotationLocked
? DEVICE_STATE_ROTATION_LOCK_LOCKED
: DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
persistSettings();
}
private boolean isRotationLockedForCurrentState() {
return mDeviceStateRotationLockSettings.get(mDeviceState,
DEVICE_STATE_ROTATION_LOCK_IGNORED) == DEVICE_STATE_ROTATION_LOCK_LOCKED;
mDeviceStateRotationLockSettingsManager.updateSetting(mDeviceState, isRotationLocked);
}
private void updateDeviceState(int state) {
@ -173,8 +120,12 @@ public final class DeviceStateRotationLockSettingController implements Listenabl
return;
}
readPersistedSetting(state);
}
private void readPersistedSetting(int state) {
int rotationLockSetting =
mDeviceStateRotationLockSettings.get(state, DEVICE_STATE_ROTATION_LOCK_IGNORED);
mDeviceStateRotationLockSettingsManager.getRotationLockSetting(state);
if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_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
@ -186,54 +137,10 @@ public final class DeviceStateRotationLockSettingController implements Listenabl
// Accept the new state
mDeviceState = state;
// Update the rotation lock setting if needed for this new device state
// Update the rotation policy, if needed, for this new device state
boolean newRotationLockSetting = rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_LOCKED;
if (newRotationLockSetting != mRotationPolicyWrapper.isRotationLocked()) {
mRotationPolicyWrapper.setRotationLock(newRotationLockSetting);
}
}
private void persistSettings() {
if (mDeviceStateRotationLockSettings.size() == 0) {
mSecureSettings.putStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
/* value= */"", UserHandle.USER_CURRENT);
return;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(mDeviceStateRotationLockSettings.keyAt(0))
.append(SEPARATOR_REGEX)
.append(mDeviceStateRotationLockSettings.valueAt(0));
for (int i = 1; i < mDeviceStateRotationLockSettings.size(); i++) {
stringBuilder
.append(SEPARATOR_REGEX)
.append(mDeviceStateRotationLockSettings.keyAt(i))
.append(SEPARATOR_REGEX)
.append(mDeviceStateRotationLockSettings.valueAt(i));
}
mSecureSettings.putStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
stringBuilder.toString(), UserHandle.USER_CURRENT);
}
private void loadDefaults() {
if (mDeviceStateRotationLockDefaults.length == 0) {
Log.w(TAG, "Empty default settings");
mDeviceStateRotationLockSettings = new SparseIntArray(/* initialCapacity= */0);
return;
}
mDeviceStateRotationLockSettings =
new SparseIntArray(mDeviceStateRotationLockDefaults.length);
for (String serializedDefault : mDeviceStateRotationLockDefaults) {
String[] entry = serializedDefault.split(SEPARATOR_REGEX);
try {
int key = Integer.parseInt(entry[0]);
int value = Integer.parseInt(entry[1]);
mDeviceStateRotationLockSettings.put(key, value);
} catch (NumberFormatException e) {
Log.wtf(TAG, "Error deserializing default settings", e);
}
}
}
}

View File

@ -0,0 +1,266 @@
/*
* Copyright (C) 2022 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 static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseIntArray;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import java.util.HashSet;
import java.util.Set;
/**
* Manages device-state based rotation lock settings. Handles reading, writing, and listening for
* changes.
*/
public final class DeviceStateRotationLockSettingsManager {
private static final String TAG = "DSRotLockSettingsMngr";
private static final String SEPARATOR_REGEX = ":";
private static DeviceStateRotationLockSettingsManager sSingleton;
private final ContentResolver mContentResolver;
private final String[] mDeviceStateRotationLockDefaults;
private final Handler mMainHandler = Handler.getMain();
private final Set<DeviceStateRotationLockSettingsListener> mListeners = new HashSet<>();
private SparseIntArray mDeviceStateRotationLockSettings;
private DeviceStateRotationLockSettingsManager(Context context) {
mContentResolver = context.getContentResolver();
mDeviceStateRotationLockDefaults =
context.getResources()
.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
initializeInMemoryMap();
listenForSettingsChange(context);
}
/** Returns a singleton instance of this class */
public static synchronized DeviceStateRotationLockSettingsManager getInstance(Context context) {
if (sSingleton == null) {
sSingleton =
new DeviceStateRotationLockSettingsManager(context.getApplicationContext());
}
return sSingleton;
}
/** Returns true if device-state based rotation lock settings are enabled. */
public static boolean isDeviceStateRotationLockEnabled(Context context) {
return context.getResources()
.getStringArray(R.array.config_perDeviceStateRotationLockDefaults)
.length
> 0;
}
private void listenForSettingsChange(Context context) {
context.getContentResolver()
.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.DEVICE_STATE_ROTATION_LOCK),
/* notifyForDescendents= */ false, //NOTYPO
new ContentObserver(mMainHandler) {
@Override
public void onChange(boolean selfChange) {
onPersistedSettingsChanged();
}
},
UserHandle.USER_CURRENT);
}
/**
* Registers a {@link DeviceStateRotationLockSettingsListener} to be notified when the settings
* change. Can be called multiple times with different listeners.
*/
public void registerListener(DeviceStateRotationLockSettingsListener runnable) {
mListeners.add(runnable);
}
/**
* Unregisters a {@link DeviceStateRotationLockSettingsListener}. No-op if the given instance
* was never registered.
*/
public void unregisterListener(
DeviceStateRotationLockSettingsListener deviceStateRotationLockSettingsListener) {
if (!mListeners.remove(deviceStateRotationLockSettingsListener)) {
Log.w(TAG, "Attempting to unregister a listener hadn't been registered");
}
}
/** Updates the rotation lock setting for a specified device state. */
public void updateSetting(int deviceState, boolean rotationLocked) {
mDeviceStateRotationLockSettings.put(
deviceState,
rotationLocked
? DEVICE_STATE_ROTATION_LOCK_LOCKED
: DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
persistSettings();
}
/**
* Returns the {@link DeviceStateRotationLockSetting} for the given device state. If no setting
* is specified for this device state, it will return {@link
* DEVICE_STATE_ROTATION_LOCK_IGNORED}.
*/
@Settings.Secure.DeviceStateRotationLockSetting
public int getRotationLockSetting(int deviceState) {
return mDeviceStateRotationLockSettings.get(
deviceState, DEVICE_STATE_ROTATION_LOCK_IGNORED);
}
/** Returns true if the rotation is locked for the current device state */
public boolean isRotationLocked(int deviceState) {
return getRotationLockSetting(deviceState) == DEVICE_STATE_ROTATION_LOCK_LOCKED;
}
/**
* Returns true if there is no device state for which the current setting is {@link
* DEVICE_STATE_ROTATION_LOCK_UNLOCKED}.
*/
public boolean isRotationLockedForAllStates() {
for (int i = 0; i < mDeviceStateRotationLockSettings.size(); i++) {
if (mDeviceStateRotationLockSettings.valueAt(i)
== DEVICE_STATE_ROTATION_LOCK_UNLOCKED) {
return false;
}
}
return true;
}
private void initializeInMemoryMap() {
String serializedSetting =
Settings.Secure.getStringForUser(
mContentResolver,
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
UserHandle.USER_CURRENT);
if (TextUtils.isEmpty(serializedSetting)) {
// No settings saved, we should load the defaults and persist them.
fallbackOnDefaults();
return;
}
String[] values = serializedSetting.split(SEPARATOR_REGEX);
if (values.length % 2 != 0) {
// Each entry should be a key/value pair, so this is corrupt.
Log.wtf(TAG, "Can't deserialize saved settings, falling back on defaults");
fallbackOnDefaults();
return;
}
mDeviceStateRotationLockSettings = new SparseIntArray(values.length / 2);
int key;
int value;
for (int i = 0; i < values.length - 1; ) {
try {
key = Integer.parseInt(values[i++]);
value = Integer.parseInt(values[i++]);
mDeviceStateRotationLockSettings.put(key, value);
} catch (NumberFormatException e) {
Log.wtf(TAG, "Error deserializing one of the saved settings", e);
fallbackOnDefaults();
return;
}
}
}
private void fallbackOnDefaults() {
loadDefaults();
persistSettings();
}
private void persistSettings() {
if (mDeviceStateRotationLockSettings.size() == 0) {
Settings.Secure.putStringForUser(
mContentResolver,
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
/* value= */ "",
UserHandle.USER_CURRENT);
return;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder
.append(mDeviceStateRotationLockSettings.keyAt(0))
.append(SEPARATOR_REGEX)
.append(mDeviceStateRotationLockSettings.valueAt(0));
for (int i = 1; i < mDeviceStateRotationLockSettings.size(); i++) {
stringBuilder
.append(SEPARATOR_REGEX)
.append(mDeviceStateRotationLockSettings.keyAt(i))
.append(SEPARATOR_REGEX)
.append(mDeviceStateRotationLockSettings.valueAt(i));
}
Settings.Secure.putStringForUser(
mContentResolver,
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
stringBuilder.toString(),
UserHandle.USER_CURRENT);
}
private void loadDefaults() {
if (mDeviceStateRotationLockDefaults.length == 0) {
Log.w(TAG, "Empty default settings");
mDeviceStateRotationLockSettings = new SparseIntArray(/* initialCapacity= */ 0);
return;
}
mDeviceStateRotationLockSettings =
new SparseIntArray(mDeviceStateRotationLockDefaults.length);
for (String serializedDefault : mDeviceStateRotationLockDefaults) {
String[] entry = serializedDefault.split(SEPARATOR_REGEX);
try {
int key = Integer.parseInt(entry[0]);
int value = Integer.parseInt(entry[1]);
mDeviceStateRotationLockSettings.put(key, value);
} catch (NumberFormatException e) {
Log.wtf(TAG, "Error deserializing default settings", e);
}
}
}
/**
* Called when the persisted settings have changed, requiring a reinitialization of the
* in-memory map.
*/
@VisibleForTesting
public void onPersistedSettingsChanged() {
initializeInMemoryMap();
notifyListeners();
}
private void notifyListeners() {
for (DeviceStateRotationLockSettingsListener r : mListeners) {
r.onSettingsChanged();
}
}
/** Listener for changes in device-state based rotation lock settings */
public interface DeviceStateRotationLockSettingsListener {
/** Called whenever the settings have changed. */
void onSettingsChanged();
}
}

View File

@ -64,7 +64,6 @@ public final class RotationLockControllerImpl implements RotationLockController
mDeviceStateRotationLockSettingController = deviceStateRotationLockSettingController;
mIsPerDeviceStateRotationLockEnabled = deviceStateRotationLockDefaults.length > 0;
if (mIsPerDeviceStateRotationLockEnabled) {
deviceStateRotationLockSettingController.initialize();
mCallbacks.add(mDeviceStateRotationLockSettingController);
}

View File

@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy.dagger;
import android.content.Context;
import android.content.res.Resources;
import android.os.UserManager;
@ -35,6 +36,7 @@ import com.android.systemui.statusbar.policy.DeviceControlsController;
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.statusbar.policy.DevicePostureControllerImpl;
import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingsManager;
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
import com.android.systemui.statusbar.policy.FlashlightController;
@ -163,6 +165,14 @@ public interface StatusBarPolicyModule {
return controller;
}
/** Returns a singleton instance of DeviceStateRotationLockSettingsManager */
@SysUISingleton
@Provides
static DeviceStateRotationLockSettingsManager provideAutoRotateSettingsManager(
Context context) {
return DeviceStateRotationLockSettingsManager.getInstance(context);
}
/**
* Default values for per-device state rotation lock settings.
*/

View File

@ -16,6 +16,10 @@
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 static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@ -25,14 +29,15 @@ import android.hardware.devicestate.DeviceStateManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContentResolver;
import android.testing.TestableResources;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.internal.view.RotationPolicy;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;
@ -47,63 +52,55 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase {
private static final String[] DEFAULT_SETTINGS = new String[]{
"0:0",
"1:2"
};
private static final String[] DEFAULT_SETTINGS = new String[] {"0:0", "1:2"};
private final FakeSettings mFakeSettings = new FakeSettings();
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
@Mock DeviceStateManager mDeviceStateManager;
RotationPolicyWrapper mFakeRotationPolicy = new FakeRotationPolicy();
DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
private DeviceStateRotationLockSettingsManager mSettingsManager;
private TestableContentResolver mContentResolver;
@Before
public void setUp() {
MockitoAnnotations.initMocks(/* testClass= */ this);
TestableResources resources = mContext.getOrCreateTestableResources();
resources.addOverride(R.array.config_perDeviceStateRotationLockDefaults, DEFAULT_SETTINGS);
ArgumentCaptor<DeviceStateManager.DeviceStateCallback> deviceStateCallbackArgumentCaptor =
ArgumentCaptor.forClass(
DeviceStateManager.DeviceStateCallback.class);
ArgumentCaptor.forClass(DeviceStateManager.DeviceStateCallback.class);
mDeviceStateRotationLockSettingController = new DeviceStateRotationLockSettingController(
mFakeSettings,
mFakeRotationPolicy,
mDeviceStateManager,
mFakeExecutor,
DEFAULT_SETTINGS
);
mContentResolver = mContext.getContentResolver();
mSettingsManager = DeviceStateRotationLockSettingsManager.getInstance(mContext);
mDeviceStateRotationLockSettingController =
new DeviceStateRotationLockSettingController(
mFakeRotationPolicy, mDeviceStateManager, mFakeExecutor, mSettingsManager);
mDeviceStateRotationLockSettingController.setListening(true);
verify(mDeviceStateManager).registerCallback(any(),
deviceStateCallbackArgumentCaptor.capture());
verify(mDeviceStateManager)
.registerCallback(any(), deviceStateCallbackArgumentCaptor.capture());
mDeviceStateCallback = deviceStateCallbackArgumentCaptor.getValue();
}
@Test
public void whenSavedSettingsEmpty_defaultsLoadedAndSaved() {
mFakeSettings.putStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK, "",
UserHandle.USER_CURRENT);
initializeSettingsWith();
mDeviceStateRotationLockSettingController.initialize();
assertThat(mFakeSettings
.getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
UserHandle.USER_CURRENT))
assertThat(
Settings.Secure.getStringForUser(
mContentResolver,
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
UserHandle.USER_CURRENT))
.isEqualTo("0:0:1:2");
}
@Test
public void whenNoSavedValueForDeviceState_assumeIgnored() {
mFakeSettings.putStringForUser(
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
/* value= */"0:2:1:2",
UserHandle.USER_CURRENT);
initializeSettingsWith(
0, DEVICE_STATE_ROTATION_LOCK_UNLOCKED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
mFakeRotationPolicy.setRotationLock(true);
mDeviceStateRotationLockSettingController.initialize();
mDeviceStateCallback.onStateChanged(1);
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
@ -116,52 +113,43 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
@Test
public void whenDeviceStateSwitched_loadCorrectSetting() {
mFakeSettings.putStringForUser(
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
/* value= */"0:2:1:1",
UserHandle.USER_CURRENT);
initializeSettingsWith(
0, DEVICE_STATE_ROTATION_LOCK_UNLOCKED, 1, DEVICE_STATE_ROTATION_LOCK_LOCKED);
mFakeRotationPolicy.setRotationLock(true);
mDeviceStateRotationLockSettingController.initialize();
mDeviceStateCallback.onStateChanged(0);
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
mDeviceStateCallback.onStateChanged(1);
assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
}
@Test
public void whenUserChangesSetting_saveSettingForCurrentState() {
mFakeSettings.putStringForUser(
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
/* value= */"0:1:1:2",
UserHandle.USER_CURRENT);
initializeSettingsWith(
0, DEVICE_STATE_ROTATION_LOCK_LOCKED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
mSettingsManager.onPersistedSettingsChanged();
mFakeRotationPolicy.setRotationLock(true);
mDeviceStateRotationLockSettingController.initialize();
mDeviceStateCallback.onStateChanged(0);
assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
mDeviceStateRotationLockSettingController
.onRotationLockStateChanged(/* rotationLocked= */false,
/* affordanceVisible= */ true);
mDeviceStateRotationLockSettingController.onRotationLockStateChanged(
/* rotationLocked= */ false, /* affordanceVisible= */ true);
assertThat(mFakeSettings
.getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
UserHandle.USER_CURRENT))
assertThat(
Settings.Secure.getStringForUser(
mContentResolver,
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
UserHandle.USER_CURRENT))
.isEqualTo("0:2:1:2");
}
@Test
public void whenDeviceStateSwitchedToIgnoredState_usePreviousSetting() {
mFakeSettings.putStringForUser(
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
/* value= */"0:0:1:2",
UserHandle.USER_CURRENT);
initializeSettingsWith(
0, DEVICE_STATE_ROTATION_LOCK_IGNORED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
mFakeRotationPolicy.setRotationLock(true);
mDeviceStateRotationLockSettingController.initialize();
mDeviceStateCallback.onStateChanged(1);
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
@ -172,12 +160,9 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
@Test
public void whenDeviceStateSwitchedToIgnoredState_newSettingsSaveForPreviousState() {
mFakeSettings.putStringForUser(
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
/* value= */"0:0:1:2",
UserHandle.USER_CURRENT);
initializeSettingsWith(
0, DEVICE_STATE_ROTATION_LOCK_IGNORED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
mFakeRotationPolicy.setRotationLock(true);
mDeviceStateRotationLockSettingController.initialize();
mDeviceStateCallback.onStateChanged(1);
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
@ -185,16 +170,52 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
mDeviceStateCallback.onStateChanged(0);
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
mDeviceStateRotationLockSettingController
.onRotationLockStateChanged(/* rotationLocked= */true,
/* affordanceVisible= */ true);
mDeviceStateRotationLockSettingController.onRotationLockStateChanged(
/* rotationLocked= */ true, /* affordanceVisible= */ true);
assertThat(mFakeSettings
.getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
UserHandle.USER_CURRENT))
assertThat(
Settings.Secure.getStringForUser(
mContentResolver,
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
UserHandle.USER_CURRENT))
.isEqualTo("0:0:1:1");
}
@Test
public void whenSettingsChangedExternally_updateRotationPolicy() throws InterruptedException {
initializeSettingsWith(
0, DEVICE_STATE_ROTATION_LOCK_UNLOCKED,
1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
mFakeRotationPolicy.setRotationLock(false);
mDeviceStateCallback.onStateChanged(0);
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
// Changing device state 0 to LOCKED
initializeSettingsWith(
0, DEVICE_STATE_ROTATION_LOCK_LOCKED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
}
private void initializeSettingsWith(int... values) {
if (values.length % 2 != 0) {
throw new IllegalArgumentException("Expecting key-value pairs");
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < values.length; sb.append(":")) {
sb.append(values[i++]).append(":").append(values[i++]);
}
Settings.Secure.putStringForUser(
mContentResolver,
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
sb.toString(),
UserHandle.USER_CURRENT);
mSettingsManager.onPersistedSettingsChanged();
}
private static class FakeRotationPolicy implements RotationPolicyWrapper {
private boolean mRotationLock;
@ -230,8 +251,8 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
}
@Override
public void registerRotationPolicyListener(RotationPolicy.RotationPolicyListener listener,
int userHandle) {
public void registerRotationPolicyListener(
RotationPolicy.RotationPolicyListener listener, int userHandle) {
throw new AssertionError("Not implemented");
}

View File

@ -23,7 +23,6 @@ import static org.mockito.Mockito.verifyZeroInteractions;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableResources;
import androidx.test.filters.SmallTest;
@ -43,25 +42,19 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class RotationLockControllerImplTest extends SysuiTestCase {
private static final String[] DEFAULT_SETTINGS = new String[]{
"0:0",
"1:2"
};
private static final String[] DEFAULT_SETTINGS = new String[] {"0:0", "1:2"};
@Mock RotationPolicyWrapper mRotationPolicyWrapper;
@Mock DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
private TestableResources mResources;
private ArgumentCaptor<RotationPolicy.RotationPolicyListener>
mRotationPolicyListenerCaptor;
private ArgumentCaptor<RotationPolicy.RotationPolicyListener> mRotationPolicyListenerCaptor;
@Before
public void setUp() {
MockitoAnnotations.initMocks(/* testClass= */ this);
mResources = mContext.getOrCreateTestableResources();
mRotationPolicyListenerCaptor = ArgumentCaptor.forClass(
RotationPolicy.RotationPolicyListener.class);
mRotationPolicyListenerCaptor =
ArgumentCaptor.forClass(RotationPolicy.RotationPolicyListener.class);
}
@Test
@ -79,14 +72,7 @@ public class RotationLockControllerImplTest extends SysuiTestCase {
}
@Test
public void whenFlagOn_initializesDeviceStateRotationController() {
createRotationLockController();
verify(mDeviceStateRotationLockSettingController).initialize();
}
@Test
public void whenFlagOn_dviceStateRotationControllerAddedToCallbacks() {
public void whenFlagOn_deviceStateRotationControllerAddedToCallbacks() {
createRotationLockController();
captureRotationPolicyListener().onChange();
@ -103,11 +89,11 @@ public class RotationLockControllerImplTest extends SysuiTestCase {
private void createRotationLockController() {
createRotationLockController(DEFAULT_SETTINGS);
}
private void createRotationLockController(String[] deviceStateRotationLockDefaults) {
new RotationLockControllerImpl(
mRotationPolicyWrapper,
mDeviceStateRotationLockSettingController,
deviceStateRotationLockDefaults
);
deviceStateRotationLockDefaults);
}
}