Merge "Remove logging only boolean parameter from KeyguardUpdateMonitor#requestFaceAuth" into tm-qpr-dev
diff --git a/core/java/android/hardware/radio/ProgramList.java b/core/java/android/hardware/radio/ProgramList.java
index f2525d1..ade9fd6 100644
--- a/core/java/android/hardware/radio/ProgramList.java
+++ b/core/java/android/hardware/radio/ProgramList.java
@@ -160,6 +160,7 @@
* Disables list updates and releases all resources.
*/
public void close() {
+ OnCloseListener onCompleteListenersCopied = null;
synchronized (mLock) {
if (mIsClosed) return;
mIsClosed = true;
@@ -167,10 +168,14 @@
mListCallbacks.clear();
mOnCompleteListeners.clear();
if (mOnCloseListener != null) {
- mOnCloseListener.onClose();
+ onCompleteListenersCopied = mOnCloseListener;
mOnCloseListener = null;
}
}
+
+ if (onCompleteListenersCopied != null) {
+ onCompleteListenersCopied.onClose();
+ }
}
void apply(Chunk chunk) {
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index 0aafaf4..6091bf9 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -50,10 +50,10 @@
private final Context mContext;
@GuardedBy("mBrokenListeners")
- private final ArrayList<AllVibratorsStateListener> mBrokenListeners = new ArrayList<>();
+ private final ArrayList<MultiVibratorStateListener> mBrokenListeners = new ArrayList<>();
@GuardedBy("mRegisteredListeners")
- private final ArrayMap<OnVibratorStateChangedListener, AllVibratorsStateListener>
+ private final ArrayMap<OnVibratorStateChangedListener, MultiVibratorStateListener>
mRegisteredListeners = new ArrayMap<>();
private final Object mLock = new Object();
@@ -147,7 +147,7 @@
Log.w(TAG, "Failed to add vibrate state listener; no vibrator manager.");
return;
}
- AllVibratorsStateListener delegate = null;
+ MultiVibratorStateListener delegate = null;
try {
synchronized (mRegisteredListeners) {
// If listener is already registered, reject and return.
@@ -155,7 +155,7 @@
Log.w(TAG, "Listener already registered.");
return;
}
- delegate = new AllVibratorsStateListener(executor, listener);
+ delegate = new MultiVibratorStateListener(executor, listener);
delegate.register(mVibratorManager);
mRegisteredListeners.put(listener, delegate);
delegate = null;
@@ -181,7 +181,7 @@
}
synchronized (mRegisteredListeners) {
if (mRegisteredListeners.containsKey(listener)) {
- AllVibratorsStateListener delegate = mRegisteredListeners.get(listener);
+ MultiVibratorStateListener delegate = mRegisteredListeners.get(listener);
delegate.unregister(mVibratorManager);
mRegisteredListeners.remove(listener);
}
@@ -238,7 +238,7 @@
* Tries to unregister individual {@link android.os.Vibrator.OnVibratorStateChangedListener}
* that were left registered to vibrators after failures to register them to all vibrators.
*
- * <p>This might happen if {@link AllVibratorsStateListener} fails to register to any vibrator
+ * <p>This might happen if {@link MultiVibratorStateListener} fails to register to any vibrator
* and also fails to unregister any previously registered single listeners to other vibrators.
*
* <p>This method never throws {@link RuntimeException} if it fails to unregister again, it will
@@ -259,10 +259,10 @@
/** Listener for a single vibrator state change. */
private static class SingleVibratorStateListener implements OnVibratorStateChangedListener {
- private final AllVibratorsStateListener mAllVibratorsListener;
+ private final MultiVibratorStateListener mAllVibratorsListener;
private final int mVibratorIdx;
- SingleVibratorStateListener(AllVibratorsStateListener listener, int vibratorIdx) {
+ SingleVibratorStateListener(MultiVibratorStateListener listener, int vibratorIdx) {
mAllVibratorsListener = listener;
mVibratorIdx = vibratorIdx;
}
@@ -552,8 +552,16 @@
}
}
- /** Listener for all vibrators state change. */
- private static class AllVibratorsStateListener {
+ /**
+ * Listener for all vibrators state change.
+ *
+ * <p>This registers a listener to all vibrators to merge the callbacks into a single state
+ * that is set to true if any individual vibrator is also true, and false otherwise.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public static class MultiVibratorStateListener {
private final Object mLock = new Object();
private final Executor mExecutor;
private final OnVibratorStateChangedListener mDelegate;
@@ -567,19 +575,21 @@
@GuardedBy("mLock")
private int mVibratingMask;
- AllVibratorsStateListener(@NonNull Executor executor,
+ public MultiVibratorStateListener(@NonNull Executor executor,
@NonNull OnVibratorStateChangedListener listener) {
mExecutor = executor;
mDelegate = listener;
}
- boolean hasRegisteredListeners() {
+ /** Returns true if at least one listener was registered to an individual vibrator. */
+ public boolean hasRegisteredListeners() {
synchronized (mLock) {
return mVibratorListeners.size() > 0;
}
}
- void register(VibratorManager vibratorManager) {
+ /** Registers a listener to all individual vibrators in {@link VibratorManager}. */
+ public void register(VibratorManager vibratorManager) {
int[] vibratorIds = vibratorManager.getVibratorIds();
synchronized (mLock) {
for (int i = 0; i < vibratorIds.length; i++) {
@@ -603,7 +613,8 @@
}
}
- void unregister(VibratorManager vibratorManager) {
+ /** Unregisters the listeners from all individual vibrators in {@link VibratorManager}. */
+ public void unregister(VibratorManager vibratorManager) {
synchronized (mLock) {
for (int i = mVibratorListeners.size(); --i >= 0; ) {
int vibratorId = mVibratorListeners.keyAt(i);
@@ -614,30 +625,44 @@
}
}
- void onVibrating(int vibratorIdx, boolean vibrating) {
+ /** Callback triggered by {@link SingleVibratorStateListener} for each vibrator. */
+ public void onVibrating(int vibratorIdx, boolean vibrating) {
mExecutor.execute(() -> {
- boolean anyVibrating;
+ boolean shouldNotifyStateChange;
+ boolean isAnyVibrating;
synchronized (mLock) {
+ // Bitmask indicating that all vibrators have been initialized.
int allInitializedMask = (1 << mVibratorListeners.size()) - 1;
- int vibratorMask = 1 << vibratorIdx;
- if ((mInitializedMask & vibratorMask) == 0) {
- // First state report for this vibrator, set vibrating initial value.
- mInitializedMask |= vibratorMask;
- mVibratingMask |= vibrating ? vibratorMask : 0;
- } else {
- // Flip vibrating value, if changed.
- boolean prevVibrating = (mVibratingMask & vibratorMask) != 0;
- if (prevVibrating != vibrating) {
- mVibratingMask ^= vibratorMask;
- }
+
+ // Save current global state before processing this vibrator state change.
+ boolean previousIsAnyVibrating = (mVibratingMask != 0);
+ boolean previousAreAllInitialized = (mInitializedMask == allInitializedMask);
+
+ // Mark this vibrator as initialized.
+ int vibratorMask = (1 << vibratorIdx);
+ mInitializedMask |= vibratorMask;
+
+ // Flip the vibrating bit flag for this vibrator, only if the state is changing.
+ boolean previousVibrating = (mVibratingMask & vibratorMask) != 0;
+ if (previousVibrating != vibrating) {
+ mVibratingMask ^= vibratorMask;
}
- if (mInitializedMask != allInitializedMask) {
- // Wait for all vibrators initial state to be reported before delegating.
- return;
- }
- anyVibrating = mVibratingMask != 0;
+
+ // Check new global state after processing this vibrator state change.
+ isAnyVibrating = (mVibratingMask != 0);
+ boolean areAllInitialized = (mInitializedMask == allInitializedMask);
+
+ // Prevent multiple triggers with the same state.
+ // Trigger once when all vibrators have reported their state, and then only when
+ // the merged vibrating state changes.
+ boolean isStateChanging = (previousIsAnyVibrating != isAnyVibrating);
+ shouldNotifyStateChange =
+ areAllInitialized && (!previousAreAllInitialized || isStateChanging);
}
- mDelegate.onVibratorStateChanged(anyVibrating);
+ // Notify delegate listener outside the lock, only if merged state is changing.
+ if (shouldNotifyStateChange) {
+ mDelegate.onVibratorStateChanged(isAnyVibrating);
+ }
});
}
}
diff --git a/core/tests/coretests/src/android/os/VibratorTest.java b/core/tests/coretests/src/android/os/VibratorTest.java
index 7a66bef..7ebebc9 100644
--- a/core/tests/coretests/src/android/os/VibratorTest.java
+++ b/core/tests/coretests/src/android/os/VibratorTest.java
@@ -21,12 +21,17 @@
import static junit.framework.TestCase.assertEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
@@ -34,6 +39,7 @@
import android.content.ContextWrapper;
import android.hardware.vibrator.IVibrator;
import android.media.AudioAttributes;
+import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
@@ -46,6 +52,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.junit.MockitoJUnitRunner;
/**
@@ -65,6 +72,7 @@
private Context mContextSpy;
private Vibrator mVibratorSpy;
+ private TestLooper mTestLooper;
@Before
public void setUp() {
@@ -73,6 +81,7 @@
ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
mVibratorSpy = spy(new SystemVibrator(mContextSpy));
+ mTestLooper = new TestLooper();
}
@Test
@@ -395,6 +404,108 @@
}
@Test
+ public void onVibratorStateChanged_noVibrator_registersNoListenerToVibratorManager() {
+ VibratorManager mockVibratorManager = mock(VibratorManager.class);
+ when(mockVibratorManager.getVibratorIds()).thenReturn(new int[0]);
+
+ Vibrator.OnVibratorStateChangedListener mockListener =
+ mock(Vibrator.OnVibratorStateChangedListener.class);
+ SystemVibrator.MultiVibratorStateListener multiVibratorListener =
+ new SystemVibrator.MultiVibratorStateListener(
+ mTestLooper.getNewExecutor(), mockListener);
+
+ multiVibratorListener.register(mockVibratorManager);
+
+ // Never tries to register a listener to an individual vibrator.
+ assertFalse(multiVibratorListener.hasRegisteredListeners());
+ verify(mockVibratorManager, never()).getVibrator(anyInt());
+ }
+
+ @Test
+ public void onVibratorStateChanged_singleVibrator_forwardsAllCallbacks() {
+ VibratorManager mockVibratorManager = mock(VibratorManager.class);
+ when(mockVibratorManager.getVibratorIds()).thenReturn(new int[] { 1 });
+ when(mockVibratorManager.getVibrator(anyInt())).thenReturn(NullVibrator.getInstance());
+
+ Vibrator.OnVibratorStateChangedListener mockListener =
+ mock(Vibrator.OnVibratorStateChangedListener.class);
+ SystemVibrator.MultiVibratorStateListener multiVibratorListener =
+ new SystemVibrator.MultiVibratorStateListener(
+ mTestLooper.getNewExecutor(), mockListener);
+
+ multiVibratorListener.register(mockVibratorManager);
+ assertTrue(multiVibratorListener.hasRegisteredListeners());
+
+ multiVibratorListener.onVibrating(/* vibratorIdx= */ 0, /* vibrating= */ false);
+ multiVibratorListener.onVibrating(/* vibratorIdx= */ 0, /* vibrating= */ true);
+ multiVibratorListener.onVibrating(/* vibratorIdx= */ 0, /* vibrating= */ false);
+
+ mTestLooper.dispatchAll();
+
+ InOrder inOrder = inOrder(mockListener);
+ inOrder.verify(mockListener).onVibratorStateChanged(eq(false));
+ inOrder.verify(mockListener).onVibratorStateChanged(eq(true));
+ inOrder.verify(mockListener).onVibratorStateChanged(eq(false));
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void onVibratorStateChanged_multipleVibrators_triggersOnlyWhenAllVibratorsInitialized() {
+ VibratorManager mockVibratorManager = mock(VibratorManager.class);
+ when(mockVibratorManager.getVibratorIds()).thenReturn(new int[] { 1, 2 });
+ when(mockVibratorManager.getVibrator(anyInt())).thenReturn(NullVibrator.getInstance());
+
+ Vibrator.OnVibratorStateChangedListener mockListener =
+ mock(Vibrator.OnVibratorStateChangedListener.class);
+ SystemVibrator.MultiVibratorStateListener multiVibratorListener =
+ new SystemVibrator.MultiVibratorStateListener(
+ mTestLooper.getNewExecutor(), mockListener);
+
+ multiVibratorListener.register(mockVibratorManager);
+ assertTrue(multiVibratorListener.hasRegisteredListeners());
+
+ multiVibratorListener.onVibrating(/* vibratorIdx= */ 0, /* vibrating= */ false);
+ mTestLooper.dispatchAll();
+ verify(mockListener, never()).onVibratorStateChanged(anyBoolean());
+
+ multiVibratorListener.onVibrating(/* vibratorIdx= */ 1, /* vibrating= */ false);
+ mTestLooper.dispatchAll();
+ verify(mockListener).onVibratorStateChanged(eq(false));
+ verifyNoMoreInteractions(mockListener);
+ }
+
+ @Test
+ public void onVibratorStateChanged_multipleVibrators_stateChangeIsDeduped() {
+ VibratorManager mockVibratorManager = mock(VibratorManager.class);
+ when(mockVibratorManager.getVibratorIds()).thenReturn(new int[] { 1, 2 });
+ when(mockVibratorManager.getVibrator(anyInt())).thenReturn(NullVibrator.getInstance());
+
+ Vibrator.OnVibratorStateChangedListener mockListener =
+ mock(Vibrator.OnVibratorStateChangedListener.class);
+ SystemVibrator.MultiVibratorStateListener multiVibratorListener =
+ new SystemVibrator.MultiVibratorStateListener(
+ mTestLooper.getNewExecutor(), mockListener);
+
+ multiVibratorListener.register(mockVibratorManager);
+ assertTrue(multiVibratorListener.hasRegisteredListeners());
+
+ multiVibratorListener.onVibrating(/* vibratorIdx= */ 0, /* vibrating= */ false); // none
+ multiVibratorListener.onVibrating(/* vibratorIdx= */ 1, /* vibrating= */ false); // false
+ multiVibratorListener.onVibrating(/* vibratorIdx= */ 0, /* vibrating= */ true); // true
+ multiVibratorListener.onVibrating(/* vibratorIdx= */ 1, /* vibrating= */ true); // true
+ multiVibratorListener.onVibrating(/* vibratorIdx= */ 0, /* vibrating= */ false); // true
+ multiVibratorListener.onVibrating(/* vibratorIdx= */ 1, /* vibrating= */ false); // false
+
+ mTestLooper.dispatchAll();
+
+ InOrder inOrder = inOrder(mockListener);
+ inOrder.verify(mockListener).onVibratorStateChanged(eq(false));
+ inOrder.verify(mockListener).onVibratorStateChanged(eq(true));
+ inOrder.verify(mockListener).onVibratorStateChanged(eq(false));
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
public void vibrate_withVibrationAttributes_usesGivenAttributes() {
VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
VibrationAttributes attributes = new VibrationAttributes.Builder().setUsage(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 528af2e..cd667ca 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -48,6 +48,7 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -376,8 +377,8 @@
Setting newSetting = new Setting(name, oldSetting.getValue(), null,
oldSetting.getPackageName(), oldSetting.getTag(), false,
oldSetting.getId());
- int newSize = getNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), oldValue,
- newSetting.getValue(), oldDefaultValue, newSetting.getDefaultValue());
+ int newSize = getNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), 0,
+ oldValue, newSetting.getValue(), oldDefaultValue, newSetting.getDefaultValue());
checkNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize);
mSettings.put(name, newSetting);
updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize);
@@ -414,8 +415,9 @@
String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null;
String newDefaultValue = makeDefault ? value : oldDefaultValue;
- int newSize = getNewMemoryUsagePerPackageLocked(packageName, oldValue, value,
- oldDefaultValue, newDefaultValue);
+ int newSize = getNewMemoryUsagePerPackageLocked(packageName,
+ oldValue == null ? name.length() : 0 /* deltaKeySize */,
+ oldValue, value, oldDefaultValue, newDefaultValue);
checkNewMemoryUsagePerPackageLocked(packageName, newSize);
Setting newState;
@@ -559,8 +561,12 @@
}
Setting oldState = mSettings.remove(name);
- int newSize = getNewMemoryUsagePerPackageLocked(oldState.packageName, oldState.value,
- null, oldState.defaultValue, null);
+ if (oldState == null) {
+ return false;
+ }
+ int newSize = getNewMemoryUsagePerPackageLocked(oldState.packageName,
+ -name.length() /* deltaKeySize */,
+ oldState.value, null, oldState.defaultValue, null);
FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, name, /* value= */ "",
/* newValue= */ "", oldState.value, /* tag */ "", false, getUserIdFromKey(mKey),
@@ -583,15 +589,16 @@
}
Setting setting = mSettings.get(name);
+ if (setting == null) {
+ return false;
+ }
Setting oldSetting = new Setting(setting);
String oldValue = setting.getValue();
String oldDefaultValue = setting.getDefaultValue();
- String newValue = oldDefaultValue;
- String newDefaultValue = oldDefaultValue;
- int newSize = getNewMemoryUsagePerPackageLocked(setting.packageName, oldValue,
- newValue, oldDefaultValue, newDefaultValue);
+ int newSize = getNewMemoryUsagePerPackageLocked(setting.packageName, 0, oldValue,
+ oldDefaultValue, oldDefaultValue, oldDefaultValue);
checkNewMemoryUsagePerPackageLocked(setting.packageName, newSize);
if (!setting.reset()) {
@@ -725,8 +732,8 @@
}
@GuardedBy("mLock")
- private int getNewMemoryUsagePerPackageLocked(String packageName, String oldValue,
- String newValue, String oldDefaultValue, String newDefaultValue) {
+ private int getNewMemoryUsagePerPackageLocked(String packageName, int deltaKeySize,
+ String oldValue, String newValue, String oldDefaultValue, String newDefaultValue) {
if (isExemptFromMemoryUsageCap(packageName)) {
return 0;
}
@@ -735,7 +742,7 @@
final int newValueSize = (newValue != null) ? newValue.length() : 0;
final int oldDefaultValueSize = (oldDefaultValue != null) ? oldDefaultValue.length() : 0;
final int newDefaultValueSize = (newDefaultValue != null) ? newDefaultValue.length() : 0;
- final int deltaSize = newValueSize + newDefaultValueSize
+ final int deltaSize = deltaKeySize + newValueSize + newDefaultValueSize
- oldValueSize - oldDefaultValueSize;
return Math.max((currentSize != null) ? currentSize + deltaSize : deltaSize, 0);
}
@@ -1577,4 +1584,11 @@
}
return false;
}
+
+ @VisibleForTesting
+ public int getMemoryUsage(String packageName) {
+ synchronized (mLock) {
+ return mPackageToMemoryUsage.getOrDefault(packageName, 0);
+ }
+ }
}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 66b809a..f6d4329 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -295,7 +295,7 @@
settingsState.deleteSettingLocked(SETTING_NAME);
// Should not throw if usage is under the cap
- settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 19999),
+ settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 19975),
null, false, "p1");
settingsState.deleteSettingLocked(SETTING_NAME);
try {
@@ -313,5 +313,97 @@
assertTrue(ex.getMessage().contains("p1"));
}
assertTrue(settingsState.getSettingLocked(SETTING_NAME).isNull());
+ try {
+ settingsState.insertSettingLocked(Strings.repeat("A", 20001), "",
+ null, false, "p1");
+ fail("Should throw because it exceeded per package memory usage");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("You are adding too many system settings"));
+ }
+ }
+
+ public void testMemoryUsagePerPackage() {
+ SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
+ SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
+
+ // Test inserting one key with default
+ final String testKey1 = SETTING_NAME;
+ final String testValue1 = Strings.repeat("A", 100);
+ settingsState.insertSettingLocked(testKey1, testValue1, null, true, TEST_PACKAGE);
+ int expectedMemUsage = testKey1.length() + testValue1.length()
+ + testValue1.length() /* size for default */;
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test inserting another key
+ final String testKey2 = SETTING_NAME + "2";
+ settingsState.insertSettingLocked(testKey2, testValue1, null, false, TEST_PACKAGE);
+ expectedMemUsage += testKey2.length() + testValue1.length();
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test updating first key with new default
+ final String testValue2 = Strings.repeat("A", 300);
+ settingsState.insertSettingLocked(testKey1, testValue2, null, true, TEST_PACKAGE);
+ expectedMemUsage += (testValue2.length() - testValue1.length()) * 2;
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test updating first key without new default
+ final String testValue3 = Strings.repeat("A", 50);
+ settingsState.insertSettingLocked(testKey1, testValue3, null, false, TEST_PACKAGE);
+ expectedMemUsage -= testValue2.length() - testValue3.length();
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test updating second key
+ settingsState.insertSettingLocked(testKey2, testValue2, null, false, TEST_PACKAGE);
+ expectedMemUsage -= testValue1.length() - testValue2.length();
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test resetting key
+ settingsState.resetSettingLocked(testKey1);
+ expectedMemUsage += testValue2.length() - testValue3.length();
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test resetting default value
+ settingsState.resetSettingDefaultValueLocked(testKey1);
+ expectedMemUsage -= testValue2.length();
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test deletion
+ settingsState.deleteSettingLocked(testKey2);
+ expectedMemUsage -= testValue2.length() + testKey2.length() /* key is deleted too */;
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test another package with a different key
+ final String testPackage2 = TEST_PACKAGE + "2";
+ final String testKey3 = SETTING_NAME + "3";
+ settingsState.insertSettingLocked(testKey3, testValue1, null, true, testPackage2);
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+ final int expectedMemUsage2 = testKey3.length() + testValue1.length() * 2;
+ assertEquals(expectedMemUsage2, settingsState.getMemoryUsage(testPackage2));
+
+ // Test system package
+ settingsState.insertSettingLocked(testKey1, testValue1, null, true, SYSTEM_PACKAGE);
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+ assertEquals(expectedMemUsage2, settingsState.getMemoryUsage(testPackage2));
+ assertEquals(0, settingsState.getMemoryUsage(SYSTEM_PACKAGE));
+
+ // Test invalid value
+ try {
+ settingsState.insertSettingLocked(testKey1, Strings.repeat("A", 20001), null, false,
+ TEST_PACKAGE);
+ fail("Should throw because it exceeded per package memory usage");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("You are adding too many system settings"));
+ }
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test invalid key
+ try {
+ settingsState.insertSettingLocked(Strings.repeat("A", 20001), "", null, false,
+ TEST_PACKAGE);
+ fail("Should throw because it exceeded per package memory usage");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("You are adding too many system settings"));
+ }
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index e47e636..6db56210 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -84,6 +84,7 @@
import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
import com.android.systemui.statusbar.window.StatusBarWindowModule;
import com.android.systemui.telephony.data.repository.TelephonyRepositoryModule;
+import com.android.systemui.temporarydisplay.dagger.TemporaryDisplayModule;
import com.android.systemui.tuner.dagger.TunerModule;
import com.android.systemui.unfold.SysUIUnfoldModule;
import com.android.systemui.user.UserModule;
@@ -150,6 +151,7 @@
SysUIConcurrencyModule.class,
SysUIUnfoldModule.class,
TelephonyRepositoryModule.class,
+ TemporaryDisplayModule.class,
TunerModule.class,
UserModule.class,
UtilModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 561222f..aa0ca20 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -193,7 +193,7 @@
// 802 - wallpaper rendering
// TODO(b/254512923): Tracking Bug
- @JvmField val USE_CANVAS_RENDERER = ReleasedFlag(802)
+ @JvmField val USE_CANVAS_RENDERER = UnreleasedFlag(802, teamfood = true)
// 803 - screen contents translation
// TODO(b/254513187): Tracking Bug
@@ -227,15 +227,9 @@
// 1000 - dock
val SIMULATE_DOCK_THROUGH_CHARGING = ReleasedFlag(1000)
- // TODO(b/254512444): Tracking Bug
- @JvmField val DOCK_SETUP_ENABLED = ReleasedFlag(1001)
-
// TODO(b/254512758): Tracking Bug
@JvmField val ROUNDED_BOX_RIPPLE = ReleasedFlag(1002)
- // TODO(b/254512525): Tracking Bug
- @JvmField val REFACTORED_DOCK_SETUP = ReleasedFlag(1003, teamfood = true)
-
// 1100 - windowing
@Keep
val WM_ENABLE_SHELL_TRANSITIONS =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index d3bb34c..c600e13 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -53,19 +53,19 @@
override val key: String = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS
- override val state: Flow<KeyguardQuickAffordanceConfig.State> =
+ override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
component.canShowWhileLockedSetting.flatMapLatest { canShowWhileLocked ->
if (canShowWhileLocked) {
stateInternal(component.getControlsListingController().getOrNull())
} else {
- flowOf(KeyguardQuickAffordanceConfig.State.Hidden)
+ flowOf(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
}
}
- override fun onQuickAffordanceClicked(
+ override fun onTriggered(
expandable: Expandable?,
- ): KeyguardQuickAffordanceConfig.OnClickedResult {
- return KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity(
+ ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
+ return KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity(
intent =
Intent(appContext, ControlsActivity::class.java)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
@@ -79,9 +79,9 @@
private fun stateInternal(
listingController: ControlsListingController?,
- ): Flow<KeyguardQuickAffordanceConfig.State> {
+ ): Flow<KeyguardQuickAffordanceConfig.LockScreenState> {
if (listingController == null) {
- return flowOf(KeyguardQuickAffordanceConfig.State.Hidden)
+ return flowOf(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
}
return conflatedCallbackFlow {
@@ -116,7 +116,7 @@
hasServiceInfos: Boolean,
visibility: ControlsComponent.Visibility,
@DrawableRes iconResourceId: Int?,
- ): KeyguardQuickAffordanceConfig.State {
+ ): KeyguardQuickAffordanceConfig.LockScreenState {
return if (
isFeatureEnabled &&
hasFavorites &&
@@ -124,7 +124,7 @@
iconResourceId != null &&
visibility == ControlsComponent.Visibility.AVAILABLE
) {
- KeyguardQuickAffordanceConfig.State.Visible(
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon =
Icon.Resource(
res = iconResourceId,
@@ -135,7 +135,7 @@
),
)
} else {
- KeyguardQuickAffordanceConfig.State.Hidden
+ KeyguardQuickAffordanceConfig.LockScreenState.Hidden
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
index 0dd0ad7..0a8090b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
@@ -20,7 +20,7 @@
import android.content.Intent
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
+import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import kotlinx.coroutines.flow.Flow
/** Defines interface that can act as data source for a single quick affordance model. */
@@ -29,51 +29,54 @@
/** Unique identifier for this quick affordance. It must be globally unique. */
val key: String
- /** The observable [State] of the affordance. */
- val state: Flow<State>
+ /**
+ * The ever-changing state of the affordance.
+ *
+ * Used to populate the lock screen.
+ */
+ val lockScreenState: Flow<LockScreenState>
/**
* Notifies that the affordance was clicked by the user.
*
* @param expandable An [Expandable] to use when animating dialogs or activities
- * @return An [OnClickedResult] telling the caller what to do next
+ * @return An [OnTriggeredResult] telling the caller what to do next
*/
- fun onQuickAffordanceClicked(expandable: Expandable?): OnClickedResult
+ fun onTriggered(expandable: Expandable?): OnTriggeredResult
/**
* Encapsulates the state of a "quick affordance" in the keyguard bottom area (for example, a
* button on the lock-screen).
*/
- sealed class State {
+ sealed class LockScreenState {
/** No affordance should show up. */
- object Hidden : State()
+ object Hidden : LockScreenState()
/** An affordance is visible. */
data class Visible(
/** An icon for the affordance. */
val icon: Icon,
- /** The toggle state for the affordance. */
- val toggle: KeyguardQuickAffordanceToggleState =
- KeyguardQuickAffordanceToggleState.NotSupported,
- ) : State()
+ /** The activation state of the affordance. */
+ val activationState: ActivationState = ActivationState.NotSupported,
+ ) : LockScreenState()
}
- sealed class OnClickedResult {
+ sealed class OnTriggeredResult {
/**
- * Returning this as a result from the [onQuickAffordanceClicked] method means that the
- * implementation has taken care of the click, the system will do nothing.
+ * Returning this as a result from the [onTriggered] method means that the implementation
+ * has taken care of the action, the system will do nothing.
*/
- object Handled : OnClickedResult()
+ object Handled : OnTriggeredResult()
/**
- * Returning this as a result from the [onQuickAffordanceClicked] method means that the
- * implementation has _not_ taken care of the click and the system should start an activity
- * using the given [Intent].
+ * Returning this as a result from the [onTriggered] method means that the implementation
+ * has _not_ taken care of the action and the system should start an activity using the
+ * given [Intent].
*/
data class StartActivity(
val intent: Intent,
val canShowWhileLocked: Boolean,
- ) : OnClickedResult()
+ ) : OnTriggeredResult()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
index 9a44139..d620b2a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
@@ -39,46 +39,47 @@
override val key: String = BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER
- override val state: Flow<KeyguardQuickAffordanceConfig.State> = conflatedCallbackFlow {
- val callback =
- object : QRCodeScannerController.Callback {
- override fun onQRCodeScannerActivityChanged() {
- trySendWithFailureLogging(state(), TAG)
+ override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
+ conflatedCallbackFlow {
+ val callback =
+ object : QRCodeScannerController.Callback {
+ override fun onQRCodeScannerActivityChanged() {
+ trySendWithFailureLogging(state(), TAG)
+ }
+ override fun onQRCodeScannerPreferenceChanged() {
+ trySendWithFailureLogging(state(), TAG)
+ }
}
- override fun onQRCodeScannerPreferenceChanged() {
- trySendWithFailureLogging(state(), TAG)
- }
- }
- controller.addCallback(callback)
- controller.registerQRCodeScannerChangeObservers(
- QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
- QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE
- )
- // Registering does not push an initial update.
- trySendWithFailureLogging(state(), "initial state", TAG)
-
- awaitClose {
- controller.unregisterQRCodeScannerChangeObservers(
+ controller.addCallback(callback)
+ controller.registerQRCodeScannerChangeObservers(
QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE
)
- controller.removeCallback(callback)
- }
- }
+ // Registering does not push an initial update.
+ trySendWithFailureLogging(state(), "initial state", TAG)
- override fun onQuickAffordanceClicked(
+ awaitClose {
+ controller.unregisterQRCodeScannerChangeObservers(
+ QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
+ QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE
+ )
+ controller.removeCallback(callback)
+ }
+ }
+
+ override fun onTriggered(
expandable: Expandable?,
- ): KeyguardQuickAffordanceConfig.OnClickedResult {
- return KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity(
+ ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
+ return KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity(
intent = controller.intent,
canShowWhileLocked = true,
)
}
- private fun state(): KeyguardQuickAffordanceConfig.State {
+ private fun state(): KeyguardQuickAffordanceConfig.LockScreenState {
return if (controller.isEnabledForLockScreenButton) {
- KeyguardQuickAffordanceConfig.State.Visible(
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon =
Icon.Resource(
res = R.drawable.ic_qr_code_scanner,
@@ -89,7 +90,7 @@
),
)
} else {
- KeyguardQuickAffordanceConfig.State.Hidden
+ KeyguardQuickAffordanceConfig.LockScreenState.Hidden
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index 8a1267e..be57a32 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -46,63 +46,64 @@
override val key: String = BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
- override val state: Flow<KeyguardQuickAffordanceConfig.State> = conflatedCallbackFlow {
- val callback =
- object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
- override fun onWalletCardsRetrieved(response: GetWalletCardsResponse?) {
- trySendWithFailureLogging(
- state(
- isFeatureEnabled = walletController.isWalletEnabled,
- hasCard = response?.walletCards?.isNotEmpty() == true,
- tileIcon = walletController.walletClient.tileIcon,
- ),
- TAG,
- )
+ override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
+ conflatedCallbackFlow {
+ val callback =
+ object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
+ override fun onWalletCardsRetrieved(response: GetWalletCardsResponse?) {
+ trySendWithFailureLogging(
+ state(
+ isFeatureEnabled = walletController.isWalletEnabled,
+ hasCard = response?.walletCards?.isNotEmpty() == true,
+ tileIcon = walletController.walletClient.tileIcon,
+ ),
+ TAG,
+ )
+ }
+
+ override fun onWalletCardRetrievalError(error: GetWalletCardsError?) {
+ Log.e(TAG, "Wallet card retrieval error, message: \"${error?.message}\"")
+ trySendWithFailureLogging(
+ KeyguardQuickAffordanceConfig.LockScreenState.Hidden,
+ TAG,
+ )
+ }
}
- override fun onWalletCardRetrievalError(error: GetWalletCardsError?) {
- Log.e(TAG, "Wallet card retrieval error, message: \"${error?.message}\"")
- trySendWithFailureLogging(
- KeyguardQuickAffordanceConfig.State.Hidden,
- TAG,
- )
- }
- }
-
- walletController.setupWalletChangeObservers(
- callback,
- QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
- QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
- )
- walletController.updateWalletPreference()
- walletController.queryWalletCards(callback)
-
- awaitClose {
- walletController.unregisterWalletChangeObservers(
+ walletController.setupWalletChangeObservers(
+ callback,
QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
)
- }
- }
+ walletController.updateWalletPreference()
+ walletController.queryWalletCards(callback)
- override fun onQuickAffordanceClicked(
+ awaitClose {
+ walletController.unregisterWalletChangeObservers(
+ QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
+ QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
+ )
+ }
+ }
+
+ override fun onTriggered(
expandable: Expandable?,
- ): KeyguardQuickAffordanceConfig.OnClickedResult {
+ ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
walletController.startQuickAccessUiIntent(
activityStarter,
expandable?.activityLaunchController(),
/* hasCard= */ true,
)
- return KeyguardQuickAffordanceConfig.OnClickedResult.Handled
+ return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
}
private fun state(
isFeatureEnabled: Boolean,
hasCard: Boolean,
tileIcon: Drawable?,
- ): KeyguardQuickAffordanceConfig.State {
+ ): KeyguardQuickAffordanceConfig.LockScreenState {
return if (isFeatureEnabled && hasCard && tileIcon != null) {
- KeyguardQuickAffordanceConfig.State.Visible(
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon =
Icon.Loaded(
drawable = tileIcon,
@@ -113,7 +114,7 @@
),
)
} else {
- KeyguardQuickAffordanceConfig.State.Hidden
+ KeyguardQuickAffordanceConfig.LockScreenState.Hidden
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 914b9fc..13d97aa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -62,25 +62,25 @@
}
/**
- * Notifies that a quick affordance has been clicked by the user.
+ * Notifies that a quick affordance has been "triggered" (clicked) by the user.
*
* @param configKey The configuration key corresponding to the [KeyguardQuickAffordanceModel] of
* the affordance that was clicked
* @param expandable An optional [Expandable] for the activity- or dialog-launch animation
*/
- fun onQuickAffordanceClicked(
+ fun onQuickAffordanceTriggered(
configKey: String,
expandable: Expandable?,
) {
@Suppress("UNCHECKED_CAST") val config = registry.get(configKey)
- when (val result = config.onQuickAffordanceClicked(expandable)) {
- is KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity ->
+ when (val result = config.onTriggered(expandable)) {
+ is KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity ->
launchQuickAffordance(
intent = result.intent,
canShowWhileLocked = result.canShowWhileLocked,
expandable = expandable,
)
- is KeyguardQuickAffordanceConfig.OnClickedResult.Handled -> Unit
+ is KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled -> Unit
}
}
@@ -94,16 +94,20 @@
// value and avoid subtle bugs where the downstream isn't receiving any values
// because one config implementation is not emitting an initial value. For example,
// see b/244296596.
- config.state.onStart { emit(KeyguardQuickAffordanceConfig.State.Hidden) }
+ config.lockScreenState.onStart {
+ emit(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
+ }
}
) { states ->
- val index = states.indexOfFirst { it is KeyguardQuickAffordanceConfig.State.Visible }
+ val index =
+ states.indexOfFirst { it is KeyguardQuickAffordanceConfig.LockScreenState.Visible }
if (index != -1) {
- val visibleState = states[index] as KeyguardQuickAffordanceConfig.State.Visible
+ val visibleState =
+ states[index] as KeyguardQuickAffordanceConfig.LockScreenState.Visible
KeyguardQuickAffordanceModel.Visible(
configKey = configs[index].key,
icon = visibleState.icon,
- toggle = visibleState.toggle,
+ activationState = visibleState.activationState,
)
} else {
KeyguardQuickAffordanceModel.Hidden
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
index fc644a9..32560af 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
@@ -18,7 +18,7 @@
package com.android.systemui.keyguard.domain.model
import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
+import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
/**
* Models a "quick affordance" in the keyguard bottom area (for example, a button on the
@@ -34,7 +34,7 @@
val configKey: String,
/** An icon for the affordance. */
val icon: Icon,
- /** The toggle state for the affordance. */
- val toggle: KeyguardQuickAffordanceToggleState,
+ /** The activation state of the affordance. */
+ val activationState: ActivationState,
) : KeyguardQuickAffordanceModel()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordanceToggleState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/ActivationState.kt
similarity index 68%
rename from packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordanceToggleState.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/ActivationState.kt
index 55d38a4..a68d190 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordanceToggleState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/ActivationState.kt
@@ -17,12 +17,12 @@
package com.android.systemui.keyguard.shared.quickaffordance
-/** Enumerates all possible toggle states for a quick affordance on the lock-screen. */
-sealed class KeyguardQuickAffordanceToggleState {
- /** Toggling is not supported. */
- object NotSupported : KeyguardQuickAffordanceToggleState()
+/** Enumerates all possible activation states for a quick affordance on the lock-screen. */
+sealed class ActivationState {
+ /** Activation is not supported. */
+ object NotSupported : ActivationState()
/** The quick affordance is on. */
- object On : KeyguardQuickAffordanceToggleState()
+ object Active : ActivationState()
/** The quick affordance is off. */
- object Off : KeyguardQuickAffordanceToggleState()
+ object Inactive : ActivationState()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
index 6aac912..b6b2304 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
@@ -22,8 +22,8 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
+import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
-import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -118,13 +118,13 @@
animateReveal = animateReveal,
icon = icon,
onClicked = { parameters ->
- quickAffordanceInteractor.onQuickAffordanceClicked(
+ quickAffordanceInteractor.onQuickAffordanceTriggered(
configKey = parameters.configKey,
expandable = parameters.expandable,
)
},
isClickable = isClickable,
- isActivated = toggle is KeyguardQuickAffordanceToggleState.On,
+ isActivated = activationState is ActivationState.Active,
)
is KeyguardQuickAffordanceModel.Hidden -> KeyguardQuickAffordanceViewModel()
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
index 0a60437..769494a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
@@ -27,10 +27,11 @@
/** Utility methods for media tap-to-transfer. */
class MediaTttUtils {
companion object {
- // Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and
- // UpdateMediaTapToTransferReceiverDisplayTest
- const val WINDOW_TITLE = "Media Transfer Chip View"
- const val WAKE_REASON = "MEDIA_TRANSFER_ACTIVATED"
+ const val WINDOW_TITLE_SENDER = "Media Transfer Chip View (Sender)"
+ const val WINDOW_TITLE_RECEIVER = "Media Transfer Chip View (Receiver)"
+
+ const val WAKE_REASON_SENDER = "MEDIA_TRANSFER_ACTIVATED_SENDER"
+ const val WAKE_REASON_RECEIVER = "MEDIA_TRANSFER_ACTIVATED_RECEIVER"
/**
* Returns the information needed to display the icon in [Icon] form.
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index dc794e6..7dd9fb4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -40,7 +40,6 @@
import com.android.systemui.media.taptotransfer.common.MediaTttUtils
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.util.animation.AnimationUtil.Companion.frames
@@ -78,8 +77,6 @@
configurationController,
powerManager,
R.layout.media_ttt_chip_receiver,
- MediaTttUtils.WINDOW_TITLE,
- MediaTttUtils.WAKE_REASON,
) {
@SuppressLint("WrongConstant") // We're allowed to use LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
override val windowLayoutParams = commonWindowLayoutParams.apply {
@@ -231,7 +228,7 @@
data class ChipReceiverInfo(
val routeInfo: MediaRoute2Info,
val appIconDrawableOverride: Drawable?,
- val appNameOverride: CharSequence?
-) : TemporaryViewInfo {
- override fun getTimeoutMs() = DEFAULT_TIMEOUT_MILLIS
-}
+ val appNameOverride: CharSequence?,
+ override val windowTitle: String = MediaTttUtils.WINDOW_TITLE_RECEIVER,
+ override val wakeReason: String = MediaTttUtils.WAKE_REASON_RECEIVER,
+) : TemporaryViewInfo()
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
index 6e596ee..af7317c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
@@ -43,7 +43,7 @@
@StringRes val stringResId: Int?,
val transferStatus: TransferStatus,
val endItem: SenderEndItem?,
- val timeout: Long = DEFAULT_TIMEOUT_MILLIS
+ val timeout: Int = DEFAULT_TIMEOUT_MILLIS,
) {
/**
* A state representing that the two devices are close but not close enough to *start* a cast to
@@ -223,6 +223,6 @@
// Give the Transfer*Triggered states a longer timeout since those states represent an active
// process and we should keep the user informed about it as long as possible (but don't allow it to
// continue indefinitely).
-private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 30000L
+private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 30000
private const val TAG = "ChipStateSender"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
index 1fa8fae..d1ea2d0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
@@ -159,6 +159,9 @@
}
},
vibrationEffect = chipStateSender.transferStatus.vibrationEffect,
+ windowTitle = MediaTttUtils.WINDOW_TITLE_SENDER,
+ wakeReason = MediaTttUtils.WAKE_REASON_SENDER,
+ timeoutMs = chipStateSender.timeout,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
index f0a50de..637fac0 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -44,11 +44,6 @@
*
* The generic type T is expected to contain all the information necessary for the subclasses to
* display the view in a certain state, since they receive <T> in [updateView].
- *
- * @property windowTitle the title to use for the window that displays the temporary view. Should be
- * normally cased, like "Window Title".
- * @property wakeReason a string used for logging if we needed to wake the screen in order to
- * display the temporary view. Should be screaming snake cased, like WAKE_REASON.
*/
abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : TemporaryViewLogger>(
internal val context: Context,
@@ -59,8 +54,6 @@
private val configurationController: ConfigurationController,
private val powerManager: PowerManager,
@LayoutRes private val viewLayoutRes: Int,
- private val windowTitle: String,
- private val wakeReason: String,
) : CoreStartable {
/**
* Window layout params that will be used as a starting point for the [windowLayoutParams] of
@@ -72,7 +65,6 @@
type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR
flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- title = windowTitle
format = PixelFormat.TRANSLUCENT
setTrustedOverlay()
}
@@ -100,29 +92,40 @@
fun displayView(newInfo: T) {
val currentDisplayInfo = displayInfo
- if (currentDisplayInfo != null) {
+ if (currentDisplayInfo != null &&
+ currentDisplayInfo.info.windowTitle == newInfo.windowTitle) {
+ // We're already displaying information in the correctly-titled window, so we just need
+ // to update the view.
currentDisplayInfo.info = newInfo
updateView(currentDisplayInfo.info, currentDisplayInfo.view)
} else {
- // The view is new, so set up all our callbacks and inflate the view
+ if (currentDisplayInfo != null) {
+ // We're already displaying information but that information is under a different
+ // window title. So, we need to remove the old window with the old title and add a
+ // new window with the new title.
+ removeView(removalReason = "New info has new window title: ${newInfo.windowTitle}")
+ }
+
+ // At this point, we're guaranteed to no longer be displaying a view.
+ // So, set up all our callbacks and inflate the view.
configurationController.addCallback(displayScaleListener)
// Wake the screen if necessary so the user will see the view. (Per b/239426653, we want
// the view to show over the dream state, so we should only wake up if the screen is
// completely off.)
if (!powerManager.isScreenOn) {
powerManager.wakeUp(
- SystemClock.uptimeMillis(),
- PowerManager.WAKE_REASON_APPLICATION,
- "com.android.systemui:$wakeReason",
+ SystemClock.uptimeMillis(),
+ PowerManager.WAKE_REASON_APPLICATION,
+ "com.android.systemui:${newInfo.wakeReason}",
)
}
- logger.logChipAddition()
+ logger.logViewAddition(newInfo.windowTitle)
inflateAndUpdateView(newInfo)
}
// Cancel and re-set the view timeout each time we get a new state.
val timeout = accessibilityManager.getRecommendedTimeoutMillis(
- newInfo.getTimeoutMs().toInt(),
+ newInfo.timeoutMs,
// Not all views have controls so FLAG_CONTENT_CONTROLS might be superfluous, but
// include it just to be safe.
FLAG_CONTENT_ICONS or FLAG_CONTENT_TEXT or FLAG_CONTENT_CONTROLS
@@ -147,7 +150,12 @@
val newDisplayInfo = DisplayInfo(newView, newInfo)
displayInfo = newDisplayInfo
updateView(newDisplayInfo.info, newDisplayInfo.view)
- windowManager.addView(newView, windowLayoutParams)
+
+ val paramsWithTitle = WindowManager.LayoutParams().also {
+ it.copyFrom(windowLayoutParams)
+ it.title = newInfo.windowTitle
+ }
+ windowManager.addView(newView, paramsWithTitle)
animateViewIn(newView)
}
@@ -177,7 +185,7 @@
val currentView = currentDisplayInfo.view
animateViewOut(currentView) { windowManager.removeView(currentView) }
- logger.logChipRemoval(removalReason)
+ logger.logViewRemoval(removalReason)
configurationController.removeCallback(displayScaleListener)
// Re-set to null immediately (instead as part of the animation end runnable) so
// that if a new view event comes in while this view is animating out, we still display the
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
index 4fe753a..cbb5002 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
@@ -19,12 +19,24 @@
/**
* A superclass view state used with [TemporaryViewDisplayController].
*/
-interface TemporaryViewInfo {
+abstract class TemporaryViewInfo {
/**
- * Returns the amount of time the given view state should display on the screen before it times
- * out and disappears.
+ * The title to use for the window that displays the temporary view. Should be normally cased,
+ * like "Window Title".
*/
- fun getTimeoutMs(): Long = DEFAULT_TIMEOUT_MILLIS
+ abstract val windowTitle: String
+
+ /**
+ * A string used for logging if we needed to wake the screen in order to display the temporary
+ * view. Should be screaming snake cased, like WAKE_REASON.
+ */
+ abstract val wakeReason: String
+
+ /**
+ * The amount of time the given view state should display on the screen before it times out and
+ * disappears.
+ */
+ open val timeoutMs: Int = DEFAULT_TIMEOUT_MILLIS
}
-const val DEFAULT_TIMEOUT_MILLIS = 10000L
+const val DEFAULT_TIMEOUT_MILLIS = 10000
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
index a7185cb..428a104 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
@@ -24,13 +24,13 @@
internal val buffer: LogBuffer,
internal val tag: String,
) {
- /** Logs that we added the chip to a new window. */
- fun logChipAddition() {
- buffer.log(tag, LogLevel.DEBUG, {}, { "Chip added" })
+ /** Logs that we added the view in a window titled [windowTitle]. */
+ fun logViewAddition(windowTitle: String) {
+ buffer.log(tag, LogLevel.DEBUG, { str1 = windowTitle }, { "View added. window=$str1" })
}
/** Logs that we removed the chip for the given [reason]. */
- fun logChipRemoval(reason: String) {
- buffer.log(tag, LogLevel.DEBUG, { str1 = reason }, { "Chip removed due to $str1" })
+ fun logViewRemoval(reason: String) {
+ buffer.log(tag, LogLevel.DEBUG, { str1 = reason }, { "View removed due to: $str1" })
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
index b8930a4..87b6e8d 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
@@ -38,9 +38,6 @@
import com.android.systemui.common.ui.binder.TextViewBinder
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.media.taptotransfer.common.MediaTttLogger
-import com.android.systemui.media.taptotransfer.common.MediaTttUtils
-import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -64,14 +61,11 @@
* Only one chipbar may be shown at a time.
* TODO(b/245610654): Should we just display whichever chipbar was most recently requested, or do we
* need to maintain a priority ordering?
- *
- * TODO(b/245610654): Remove all media-related items from this class so it's just for generic
- * chipbars.
*/
@SysUISingleton
open class ChipbarCoordinator @Inject constructor(
context: Context,
- @MediaTttSenderLogger logger: MediaTttLogger,
+ logger: ChipbarLogger,
windowManager: WindowManager,
@Main mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,
@@ -81,7 +75,7 @@
private val falsingCollector: FalsingCollector,
private val viewUtil: ViewUtil,
private val vibratorHelper: VibratorHelper,
-) : TemporaryViewDisplayController<ChipbarInfo, MediaTttLogger>(
+) : TemporaryViewDisplayController<ChipbarInfo, ChipbarLogger>(
context,
logger,
windowManager,
@@ -90,8 +84,6 @@
configurationController,
powerManager,
R.layout.chipbar,
- MediaTttUtils.WINDOW_TITLE,
- MediaTttUtils.WAKE_REASON,
) {
private lateinit var parent: ChipbarRootView
@@ -106,7 +98,16 @@
newInfo: ChipbarInfo,
currentView: ViewGroup
) {
- // TODO(b/245610654): Adding logging here.
+ logger.logViewUpdate(
+ newInfo.windowTitle,
+ newInfo.text.loadText(context),
+ when (newInfo.endItem) {
+ null -> "null"
+ is ChipbarEndItem.Loading -> "loading"
+ is ChipbarEndItem.Error -> "error"
+ is ChipbarEndItem.Button -> "button(${newInfo.endItem.text.loadText(context)})"
+ }
+ )
// Detect falsing touches on the chip.
parent = currentView.requireViewById(R.id.chipbar_root_view)
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt
index 57fde87..6237365 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt
@@ -37,7 +37,10 @@
val text: Text,
val endItem: ChipbarEndItem?,
val vibrationEffect: VibrationEffect? = null,
-) : TemporaryViewInfo
+ override val windowTitle: String,
+ override val wakeReason: String,
+ override val timeoutMs: Int,
+) : TemporaryViewInfo()
/** The possible items to display at the end of the chipbar. */
sealed class ChipbarEndItem {
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
new file mode 100644
index 0000000..e477cd6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.temporarydisplay.chipbar
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.temporarydisplay.TemporaryViewLogger
+import com.android.systemui.temporarydisplay.dagger.ChipbarLog
+import javax.inject.Inject
+
+/** A logger for the chipbar. */
+@SysUISingleton
+class ChipbarLogger
+@Inject
+constructor(
+ @ChipbarLog buffer: LogBuffer,
+) : TemporaryViewLogger(buffer, "ChipbarLog") {
+ /**
+ * Logs that the chipbar was updated to display in a window named [windowTitle], with [text] and
+ * [endItemDesc].
+ */
+ fun logViewUpdate(windowTitle: String, text: String?, endItemDesc: String) {
+ buffer.log(
+ tag,
+ LogLevel.DEBUG,
+ {
+ str1 = windowTitle
+ str2 = text
+ str3 = endItemDesc
+ },
+ { "Chipbar updated. window=$str1 text=$str2 endItem=$str3" }
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/ChipbarLog.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/ChipbarLog.kt
new file mode 100644
index 0000000..5f101f2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/ChipbarLog.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.temporarydisplay.dagger
+
+import javax.inject.Qualifier
+
+/** Status bar connectivity logs in table format. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class ChipbarLog
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
new file mode 100644
index 0000000..cf0a183
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.temporarydisplay.dagger
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.plugins.log.LogBuffer
+import dagger.Module
+import dagger.Provides
+
+@Module
+interface TemporaryDisplayModule {
+ @Module
+ companion object {
+ @JvmStatic
+ @Provides
+ @SysUISingleton
+ @ChipbarLog
+ fun provideChipbarLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("ChipbarLog", 40)
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
index ce11008..f18acba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
@@ -18,7 +18,7 @@
package com.android.systemui.keyguard.data.quickaffordance
import com.android.systemui.animation.Expandable
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.yield
@@ -33,22 +33,23 @@
override val key: String,
) : KeyguardQuickAffordanceConfig {
- var onClickedResult: OnClickedResult = OnClickedResult.Handled
+ var onTriggeredResult: OnTriggeredResult = OnTriggeredResult.Handled
- private val _state =
- MutableStateFlow<KeyguardQuickAffordanceConfig.State>(
- KeyguardQuickAffordanceConfig.State.Hidden
+ private val _lockScreenState =
+ MutableStateFlow<KeyguardQuickAffordanceConfig.LockScreenState>(
+ KeyguardQuickAffordanceConfig.LockScreenState.Hidden
)
- override val state: Flow<KeyguardQuickAffordanceConfig.State> = _state
+ override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
+ _lockScreenState
- override fun onQuickAffordanceClicked(
+ override fun onTriggered(
expandable: Expandable?,
- ): OnClickedResult {
- return onClickedResult
+ ): OnTriggeredResult {
+ return onTriggeredResult
}
- suspend fun setState(state: KeyguardQuickAffordanceConfig.State) {
- _state.value = state
+ suspend fun setState(lockScreenState: KeyguardQuickAffordanceConfig.LockScreenState) {
+ _lockScreenState.value = lockScreenState
// Yield to allow the test's collection coroutine to "catch up" and collect this value
// before the test continues to the next line.
// TODO(b/239834928): once coroutines.test is updated, switch to the approach described in
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
index b120303..c94cec6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
@@ -122,8 +122,8 @@
emptyList()
}
)
- val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
- val job = underTest.state.onEach(values::add).launchIn(this)
+ val values = mutableListOf<KeyguardQuickAffordanceConfig.LockScreenState>()
+ val job = underTest.lockScreenState.onEach(values::add).launchIn(this)
if (canShowWhileLocked) {
verify(controlsListingController).addCallback(callbackCaptor.capture())
@@ -139,9 +139,9 @@
assertThat(values.last())
.isInstanceOf(
if (isVisibleExpected) {
- KeyguardQuickAffordanceConfig.State.Visible::class.java
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java
} else {
- KeyguardQuickAffordanceConfig.State.Hidden::class.java
+ KeyguardQuickAffordanceConfig.LockScreenState.Hidden::class.java
}
)
job.cancel()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index ce8d36d..659c1e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -23,7 +23,7 @@
import com.android.systemui.animation.Expandable
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.dagger.ControlsComponent
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import java.util.Optional
@@ -72,11 +72,11 @@
whenever(component.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
whenever(controlsController.getFavorites()).thenReturn(listOf(mock()))
- val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
- val job = underTest.state.onEach(values::add).launchIn(this)
+ val values = mutableListOf<KeyguardQuickAffordanceConfig.LockScreenState>()
+ val job = underTest.lockScreenState.onEach(values::add).launchIn(this)
assertThat(values.last())
- .isInstanceOf(KeyguardQuickAffordanceConfig.State.Hidden::class.java)
+ .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Hidden::class.java)
job.cancel()
}
@@ -91,31 +91,32 @@
whenever(component.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
whenever(controlsController.getFavorites()).thenReturn(listOf(mock()))
- val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
- val job = underTest.state.onEach(values::add).launchIn(this)
+ val values = mutableListOf<KeyguardQuickAffordanceConfig.LockScreenState>()
+ val job = underTest.lockScreenState.onEach(values::add).launchIn(this)
assertThat(values.last())
- .isInstanceOf(KeyguardQuickAffordanceConfig.State.Hidden::class.java)
+ .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Hidden::class.java)
job.cancel()
}
@Test
- fun `onQuickAffordanceClicked - canShowWhileLockedSetting is true`() = runBlockingTest {
+ fun `onQuickAffordanceTriggered - canShowWhileLockedSetting is true`() = runBlockingTest {
whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true))
- val onClickedResult = underTest.onQuickAffordanceClicked(expandable)
+ val onClickedResult = underTest.onTriggered(expandable)
- assertThat(onClickedResult).isInstanceOf(OnClickedResult.StartActivity::class.java)
- assertThat((onClickedResult as OnClickedResult.StartActivity).canShowWhileLocked).isTrue()
+ assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java)
+ assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked).isTrue()
}
@Test
- fun `onQuickAffordanceClicked - canShowWhileLockedSetting is false`() = runBlockingTest {
+ fun `onQuickAffordanceTriggered - canShowWhileLockedSetting is false`() = runBlockingTest {
whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false))
- val onClickedResult = underTest.onQuickAffordanceClicked(expandable)
+ val onClickedResult = underTest.onTriggered(expandable)
- assertThat(onClickedResult).isInstanceOf(OnClickedResult.StartActivity::class.java)
- assertThat((onClickedResult as OnClickedResult.StartActivity).canShowWhileLocked).isFalse()
+ assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java)
+ assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked)
+ .isFalse()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
index 9346440..61a3f9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
@@ -20,7 +20,7 @@
import android.content.Intent
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
@@ -56,9 +56,9 @@
@Test
fun `affordance - sets up registration and delivers initial model`() = runBlockingTest {
whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
- var latest: KeyguardQuickAffordanceConfig.State? = null
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
- val job = underTest.state.onEach { latest = it }.launchIn(this)
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
verify(controller).addCallback(callbackCaptor.capture())
@@ -77,8 +77,8 @@
fun `affordance - scanner activity changed - delivers model with updated intent`() =
runBlockingTest {
whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
- var latest: KeyguardQuickAffordanceConfig.State? = null
- val job = underTest.state.onEach { latest = it }.launchIn(this)
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
verify(controller).addCallback(callbackCaptor.capture())
@@ -93,8 +93,8 @@
@Test
fun `affordance - scanner preference changed - delivers visible model`() = runBlockingTest {
- var latest: KeyguardQuickAffordanceConfig.State? = null
- val job = underTest.state.onEach { latest = it }.launchIn(this)
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
verify(controller).addCallback(callbackCaptor.capture())
@@ -109,34 +109,35 @@
@Test
fun `affordance - scanner preference changed - delivers none`() = runBlockingTest {
- var latest: KeyguardQuickAffordanceConfig.State? = null
- val job = underTest.state.onEach { latest = it }.launchIn(this)
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
verify(controller).addCallback(callbackCaptor.capture())
whenever(controller.isEnabledForLockScreenButton).thenReturn(false)
callbackCaptor.value.onQRCodeScannerPreferenceChanged()
- assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden)
+ assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
job.cancel()
verify(controller).removeCallback(callbackCaptor.value)
}
@Test
- fun onQuickAffordanceClicked() {
- assertThat(underTest.onQuickAffordanceClicked(mock()))
+ fun onQuickAffordanceTriggered() {
+ assertThat(underTest.onTriggered(mock()))
.isEqualTo(
- OnClickedResult.StartActivity(
+ OnTriggeredResult.StartActivity(
intent = INTENT_1,
canShowWhileLocked = true,
)
)
}
- private fun assertVisibleState(latest: KeyguardQuickAffordanceConfig.State?) {
- assertThat(latest).isInstanceOf(KeyguardQuickAffordanceConfig.State.Visible::class.java)
- val visibleState = latest as KeyguardQuickAffordanceConfig.State.Visible
+ private fun assertVisibleState(latest: KeyguardQuickAffordanceConfig.LockScreenState?) {
+ assertThat(latest)
+ .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java)
+ val visibleState = latest as KeyguardQuickAffordanceConfig.LockScreenState.Visible
assertThat(visibleState.icon).isNotNull()
assertThat(visibleState.icon.contentDescription).isNotNull()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
index ae9e3c7..c05beef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
@@ -67,11 +67,11 @@
@Test
fun `affordance - keyguard showing - has wallet card - visible model`() = runBlockingTest {
setUpState()
- var latest: KeyguardQuickAffordanceConfig.State? = null
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
- val job = underTest.state.onEach { latest = it }.launchIn(this)
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
- val visibleModel = latest as KeyguardQuickAffordanceConfig.State.Visible
+ val visibleModel = latest as KeyguardQuickAffordanceConfig.LockScreenState.Visible
assertThat(visibleModel.icon)
.isEqualTo(
Icon.Loaded(
@@ -88,11 +88,11 @@
@Test
fun `affordance - wallet not enabled - model is none`() = runBlockingTest {
setUpState(isWalletEnabled = false)
- var latest: KeyguardQuickAffordanceConfig.State? = null
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
- val job = underTest.state.onEach { latest = it }.launchIn(this)
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
- assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden)
+ assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
job.cancel()
}
@@ -100,11 +100,11 @@
@Test
fun `affordance - query not successful - model is none`() = runBlockingTest {
setUpState(isWalletQuerySuccessful = false)
- var latest: KeyguardQuickAffordanceConfig.State? = null
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
- val job = underTest.state.onEach { latest = it }.launchIn(this)
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
- assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden)
+ assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
job.cancel()
}
@@ -112,11 +112,11 @@
@Test
fun `affordance - missing icon - model is none`() = runBlockingTest {
setUpState(hasWalletIcon = false)
- var latest: KeyguardQuickAffordanceConfig.State? = null
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
- val job = underTest.state.onEach { latest = it }.launchIn(this)
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
- assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden)
+ assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
job.cancel()
}
@@ -124,24 +124,24 @@
@Test
fun `affordance - no selected card - model is none`() = runBlockingTest {
setUpState(hasWalletIcon = false)
- var latest: KeyguardQuickAffordanceConfig.State? = null
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
- val job = underTest.state.onEach { latest = it }.launchIn(this)
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
- assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden)
+ assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
job.cancel()
}
@Test
- fun onQuickAffordanceClicked() {
+ fun onQuickAffordanceTriggered() {
val animationController: ActivityLaunchAnimator.Controller = mock()
val expandable: Expandable = mock {
whenever(this.activityLaunchController()).thenReturn(animationController)
}
- assertThat(underTest.onQuickAffordanceClicked(expandable))
- .isEqualTo(KeyguardQuickAffordanceConfig.OnClickedResult.Handled)
+ assertThat(underTest.onTriggered(expandable))
+ .isEqualTo(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled)
verify(walletController)
.startQuickAccessUiIntent(
activityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index 114cf19..7116cc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -248,29 +248,29 @@
}
@Test
- fun onQuickAffordanceClicked() = runBlockingTest {
+ fun onQuickAffordanceTriggered() = runBlockingTest {
setUpMocks(
needStrongAuthAfterBoot = needStrongAuthAfterBoot,
keyguardIsUnlocked = keyguardIsUnlocked,
)
homeControls.setState(
- state =
- KeyguardQuickAffordanceConfig.State.Visible(
+ lockScreenState =
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon = DRAWABLE,
)
)
- homeControls.onClickedResult =
+ homeControls.onTriggeredResult =
if (startActivity) {
- KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity(
+ KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity(
intent = INTENT,
canShowWhileLocked = canShowWhileLocked,
)
} else {
- KeyguardQuickAffordanceConfig.OnClickedResult.Handled
+ KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
}
- underTest.onQuickAffordanceClicked(
+ underTest.onQuickAffordanceTriggered(
configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS,
expandable = expandable,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 1a1ee8a..ae32ba6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -28,8 +28,8 @@
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
+import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
-import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -114,9 +114,9 @@
fun `quickAffordance - bottom start affordance is visible`() = runBlockingTest {
val configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS
homeControls.setState(
- KeyguardQuickAffordanceConfig.State.Visible(
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon = ICON,
- toggle = KeyguardQuickAffordanceToggleState.On,
+ activationState = ActivationState.Active,
)
)
@@ -137,7 +137,7 @@
assertThat(visibleModel.icon).isEqualTo(ICON)
assertThat(visibleModel.icon.contentDescription)
.isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
- assertThat(visibleModel.toggle).isEqualTo(KeyguardQuickAffordanceToggleState.On)
+ assertThat(visibleModel.activationState).isEqualTo(ActivationState.Active)
job.cancel()
}
@@ -145,7 +145,7 @@
fun `quickAffordance - bottom end affordance is visible`() = runBlockingTest {
val configKey = BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
quickAccessWallet.setState(
- KeyguardQuickAffordanceConfig.State.Visible(
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon = ICON,
)
)
@@ -167,7 +167,7 @@
assertThat(visibleModel.icon).isEqualTo(ICON)
assertThat(visibleModel.icon.contentDescription)
.isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
- assertThat(visibleModel.toggle).isEqualTo(KeyguardQuickAffordanceToggleState.NotSupported)
+ assertThat(visibleModel.activationState).isEqualTo(ActivationState.NotSupported)
job.cancel()
}
@@ -175,7 +175,7 @@
fun `quickAffordance - bottom start affordance hidden while dozing`() = runBlockingTest {
repository.setDozing(true)
homeControls.setState(
- KeyguardQuickAffordanceConfig.State.Visible(
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon = ICON,
)
)
@@ -195,7 +195,7 @@
runBlockingTest {
repository.setKeyguardShowing(false)
homeControls.setState(
- KeyguardQuickAffordanceConfig.State.Visible(
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon = ICON,
)
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index f9be067..f73d1ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -31,8 +31,8 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
+import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
-import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -508,28 +508,28 @@
KeyguardQuickAffordancePosition.BOTTOM_END -> quickAccessWalletAffordanceConfig
}
- val state =
+ val lockScreenState =
if (testConfig.isVisible) {
if (testConfig.intent != null) {
- config.onClickedResult =
- KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity(
+ config.onTriggeredResult =
+ KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity(
intent = testConfig.intent,
canShowWhileLocked = testConfig.canShowWhileLocked,
)
}
- KeyguardQuickAffordanceConfig.State.Visible(
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon = testConfig.icon ?: error("Icon is unexpectedly null!"),
- toggle =
+ activationState =
when (testConfig.isActivated) {
- true -> KeyguardQuickAffordanceToggleState.On
- false -> KeyguardQuickAffordanceToggleState.Off
- null -> KeyguardQuickAffordanceToggleState.NotSupported
+ true -> ActivationState.Active
+ false -> ActivationState.Inactive
+ null -> ActivationState.NotSupported
}
)
} else {
- KeyguardQuickAffordanceConfig.State.Hidden
+ KeyguardQuickAffordanceConfig.LockScreenState.Hidden
}
- config.setState(state)
+ config.setState(lockScreenState)
return config.key
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
index fdeb3f5..ad19bc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
@@ -45,6 +45,7 @@
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
+import com.android.systemui.temporarydisplay.chipbar.ChipbarLogger
import com.android.systemui.temporarydisplay.chipbar.FakeChipbarCoordinator
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -80,6 +81,7 @@
@Mock private lateinit var configurationController: ConfigurationController
@Mock private lateinit var falsingManager: FalsingManager
@Mock private lateinit var falsingCollector: FalsingCollector
+ @Mock private lateinit var chipbarLogger: ChipbarLogger
@Mock private lateinit var logger: MediaTttLogger
@Mock private lateinit var mediaTttFlags: MediaTttFlags
@Mock private lateinit var packageManager: PackageManager
@@ -122,7 +124,7 @@
chipbarCoordinator =
FakeChipbarCoordinator(
context,
- logger,
+ chipbarLogger,
windowManager,
fakeExecutor,
accessibilityManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
index b68eb88..91b5c35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -41,6 +41,7 @@
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@@ -85,10 +86,29 @@
}
@Test
- fun displayView_viewAdded() {
- underTest.displayView(getState())
+ fun displayView_viewAddedWithCorrectTitle() {
+ underTest.displayView(
+ ViewInfo(
+ name = "name",
+ windowTitle = "Fake Window Title",
+ )
+ )
- verify(windowManager).addView(any(), any())
+ val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>()
+ verify(windowManager).addView(any(), capture(windowParamsCaptor))
+ assertThat(windowParamsCaptor.value!!.title).isEqualTo("Fake Window Title")
+ }
+
+ @Test
+ fun displayView_logged() {
+ underTest.displayView(
+ ViewInfo(
+ name = "name",
+ windowTitle = "Fake Window Title",
+ )
+ )
+
+ verify(logger).logViewAddition("Fake Window Title")
}
@Test
@@ -110,7 +130,7 @@
}
@Test
- fun displayView_twice_viewNotAddedTwice() {
+ fun displayView_twiceWithSameWindowTitle_viewNotAddedTwice() {
underTest.displayView(getState())
reset(windowManager)
@@ -119,6 +139,32 @@
}
@Test
+ fun displayView_twiceWithDifferentWindowTitles_oldViewRemovedNewViewAdded() {
+ underTest.displayView(
+ ViewInfo(
+ name = "name",
+ windowTitle = "First Fake Window Title",
+ )
+ )
+
+ underTest.displayView(
+ ViewInfo(
+ name = "name",
+ windowTitle = "Second Fake Window Title",
+ )
+ )
+
+ val viewCaptor = argumentCaptor<View>()
+ val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>()
+
+ verify(windowManager, times(2)).addView(capture(viewCaptor), capture(windowParamsCaptor))
+
+ assertThat(windowParamsCaptor.allValues[0].title).isEqualTo("First Fake Window Title")
+ assertThat(windowParamsCaptor.allValues[1].title).isEqualTo("Second Fake Window Title")
+ verify(windowManager).removeView(viewCaptor.allValues[0])
+ }
+
+ @Test
fun displayView_viewDoesNotDisappearsBeforeTimeout() {
val state = getState()
underTest.displayView(state)
@@ -197,7 +243,7 @@
underTest.removeView(reason)
verify(windowManager).removeView(any())
- verify(logger).logChipRemoval(reason)
+ verify(logger).logViewRemoval(reason)
}
@Test
@@ -232,8 +278,6 @@
configurationController,
powerManager,
R.layout.chipbar,
- "Window Title",
- "WAKE_REASON",
) {
var mostRecentViewInfo: ViewInfo? = null
@@ -250,9 +294,12 @@
}
}
- inner class ViewInfo(val name: String) : TemporaryViewInfo {
- override fun getTimeoutMs() = 1L
- }
+ inner class ViewInfo(
+ val name: String,
+ override val windowTitle: String = "Window Title",
+ override val wakeReason: String = "WAKE_REASON",
+ override val timeoutMs: Int = 1
+ ) : TemporaryViewInfo()
}
private const val TIMEOUT_MS = 10000L
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
index 13e9f60..d155050 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
@@ -43,20 +43,21 @@
}
@Test
- fun logChipAddition_bufferHasLog() {
- logger.logChipAddition()
+ fun logViewAddition_bufferHasLog() {
+ logger.logViewAddition("Test Window Title")
val stringWriter = StringWriter()
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
val actualString = stringWriter.toString()
assertThat(actualString).contains(TAG)
+ assertThat(actualString).contains("Test Window Title")
}
@Test
- fun logChipRemoval_bufferHasTagAndReason() {
+ fun logViewRemoval_bufferHasTagAndReason() {
val reason = "test reason"
- logger.logChipRemoval(reason)
+ logger.logViewRemoval(reason)
val stringWriter = StringWriter()
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
index 9fbf159..f643973 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
@@ -35,12 +35,12 @@
import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
-import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat
@@ -60,7 +60,7 @@
class ChipbarCoordinatorTest : SysuiTestCase() {
private lateinit var underTest: FakeChipbarCoordinator
- @Mock private lateinit var logger: MediaTttLogger
+ @Mock private lateinit var logger: ChipbarLogger
@Mock private lateinit var accessibilityManager: AccessibilityManager
@Mock private lateinit var configurationController: ConfigurationController
@Mock private lateinit var powerManager: PowerManager
@@ -105,7 +105,7 @@
val drawable = context.getDrawable(R.drawable.ic_celebration)!!
underTest.displayView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")),
Text.Loaded("text"),
endItem = null,
@@ -121,7 +121,7 @@
fun displayView_resourceIcon_correctlyRendered() {
val contentDescription = ContentDescription.Resource(R.string.controls_error_timeout)
underTest.displayView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Resource(R.drawable.ic_cake, contentDescription),
Text.Loaded("text"),
endItem = null,
@@ -136,7 +136,7 @@
@Test
fun displayView_loadedText_correctlyRendered() {
underTest.displayView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("display view text here"),
endItem = null,
@@ -149,7 +149,7 @@
@Test
fun displayView_resourceText_correctlyRendered() {
underTest.displayView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Resource(R.string.screenrecord_start_error),
endItem = null,
@@ -163,7 +163,7 @@
@Test
fun displayView_endItemNull_correctlyRendered() {
underTest.displayView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem = null,
@@ -179,7 +179,7 @@
@Test
fun displayView_endItemLoading_correctlyRendered() {
underTest.displayView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem = ChipbarEndItem.Loading,
@@ -195,7 +195,7 @@
@Test
fun displayView_endItemError_correctlyRendered() {
underTest.displayView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem = ChipbarEndItem.Error,
@@ -211,7 +211,7 @@
@Test
fun displayView_endItemButton_correctlyRendered() {
underTest.displayView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem =
@@ -237,7 +237,7 @@
val buttonClickListener = View.OnClickListener { isClicked = true }
underTest.displayView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem =
@@ -260,7 +260,7 @@
val buttonClickListener = View.OnClickListener { isClicked = true }
underTest.displayView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem =
@@ -279,7 +279,7 @@
@Test
fun displayView_vibrationEffect_doubleClickEffect() {
underTest.displayView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem = null,
@@ -296,7 +296,7 @@
val drawable = context.getDrawable(R.drawable.ic_celebration)!!
underTest.displayView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")),
Text.Loaded("title text"),
endItem = ChipbarEndItem.Loading,
@@ -314,7 +314,7 @@
// WHEN the view is updated
val newDrawable = context.getDrawable(R.drawable.ic_cake)!!
underTest.updateView(
- ChipbarInfo(
+ createChipbarInfo(
Icon.Loaded(newDrawable, ContentDescription.Loaded("new CD")),
Text.Loaded("new title text"),
endItem = ChipbarEndItem.Error,
@@ -331,6 +331,47 @@
assertThat(chipbarView.getEndButton().visibility).isEqualTo(View.GONE)
}
+ @Test
+ fun viewUpdates_logged() {
+ val drawable = context.getDrawable(R.drawable.ic_celebration)!!
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")),
+ Text.Loaded("title text"),
+ endItem = ChipbarEndItem.Loading,
+ )
+ )
+
+ verify(logger).logViewUpdate(eq(WINDOW_TITLE), eq("title text"), any())
+
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Loaded(drawable, ContentDescription.Loaded("new CD")),
+ Text.Loaded("new title text"),
+ endItem = ChipbarEndItem.Error,
+ )
+ )
+
+ verify(logger).logViewUpdate(eq(WINDOW_TITLE), eq("new title text"), any())
+ }
+
+ private fun createChipbarInfo(
+ startIcon: Icon,
+ text: Text,
+ endItem: ChipbarEndItem?,
+ vibrationEffect: VibrationEffect? = null,
+ ): ChipbarInfo {
+ return ChipbarInfo(
+ startIcon,
+ text,
+ endItem,
+ vibrationEffect,
+ windowTitle = WINDOW_TITLE,
+ wakeReason = WAKE_REASON,
+ timeoutMs = TIMEOUT,
+ )
+ }
+
private fun ViewGroup.getStartIconView() = this.requireViewById<ImageView>(R.id.start_icon)
private fun ViewGroup.getChipText(): String =
@@ -350,3 +391,5 @@
}
private const val TIMEOUT = 10000
+private const val WINDOW_TITLE = "Test Chipbar Window Title"
+private const val WAKE_REASON = "TEST_CHIPBAR_WAKE_REASON"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt
index 17d4023..574f70e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt
@@ -22,8 +22,6 @@
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
import com.android.systemui.classifier.FalsingCollector
-import com.android.systemui.media.taptotransfer.common.MediaTttLogger
-import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -33,7 +31,7 @@
/** A fake implementation of [ChipbarCoordinator] for testing. */
class FakeChipbarCoordinator(
context: Context,
- @MediaTttReceiverLogger logger: MediaTttLogger,
+ logger: ChipbarLogger,
windowManager: WindowManager,
mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 15c569e..4013ace 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -117,6 +117,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
/**
* Service to manage game related features.
@@ -333,7 +334,7 @@
removeMessages(POPULATE_GAME_MODE_SETTINGS, msg.obj);
final int userId = (int) msg.obj;
final String[] packageNames = getInstalledGamePackageNames(userId);
- updateConfigsForUser(userId, packageNames);
+ updateConfigsForUser(userId, false /*checkGamePackage*/, packageNames);
break;
}
case SET_GAME_STATE: {
@@ -402,7 +403,8 @@
@Override
public void onPropertiesChanged(Properties properties) {
final String[] packageNames = properties.getKeyset().toArray(new String[0]);
- updateConfigsForUser(ActivityManager.getCurrentUser(), packageNames);
+ updateConfigsForUser(ActivityManager.getCurrentUser(), true /*checkGamePackage*/,
+ packageNames);
}
@Override
@@ -553,16 +555,23 @@
private static final String GAME_MODE_CONFIG_NODE_NAME = "game-mode-config";
private final String mPackageName;
- private final ArrayMap<Integer, GameModeConfiguration> mModeConfigs;
+ private final Object mModeConfigLock = new Object();
+ @GuardedBy("mModeConfigLock")
+ private final ArrayMap<Integer, GameModeConfiguration> mModeConfigs = new ArrayMap<>();
+ // if adding new properties or make any of the below overridable, the method
+ // copyAndApplyOverride should be updated accordingly
private boolean mPerfModeOptedIn = false;
private boolean mBatteryModeOptedIn = false;
private boolean mAllowDownscale = true;
private boolean mAllowAngle = true;
private boolean mAllowFpsOverride = true;
+ GamePackageConfiguration(String packageName) {
+ mPackageName = packageName;
+ }
+
GamePackageConfiguration(String packageName, int userId) {
mPackageName = packageName;
- mModeConfigs = new ArrayMap<>();
try {
final ApplicationInfo ai = mPackageManager.getApplicationInfoAsUser(packageName,
@@ -646,6 +655,13 @@
return xmlFound;
}
+ GameModeConfiguration getOrAddDefaultGameModeConfiguration(int gameMode) {
+ synchronized (mModeConfigLock) {
+ mModeConfigs.putIfAbsent(gameMode, new GameModeConfiguration(gameMode));
+ return mModeConfigs.get(gameMode);
+ }
+ }
+
/**
* GameModeConfiguration contains all the values for all the interventions associated with
* a game mode.
@@ -658,15 +674,23 @@
public static final String FPS_KEY = "fps";
public static final String DEFAULT_SCALING = "1.0";
public static final String DEFAULT_FPS = "";
+ public static final boolean DEFAULT_USE_ANGLE = false;
+ public static final int DEFAULT_LOADING_BOOST_DURATION = -1;
public static final String ANGLE_KEY = "useAngle";
public static final String LOADING_BOOST_KEY = "loadingBoost";
private final @GameMode int mGameMode;
- private String mScaling;
- private String mFps;
+ private String mScaling = DEFAULT_SCALING;
+ private String mFps = DEFAULT_FPS;
private final boolean mUseAngle;
private final int mLoadingBoostDuration;
+ GameModeConfiguration(int gameMode) {
+ mGameMode = gameMode;
+ mUseAngle = DEFAULT_USE_ANGLE;
+ mLoadingBoostDuration = DEFAULT_LOADING_BOOST_DURATION;
+ }
+
GameModeConfiguration(KeyValueListParser parser) {
mGameMode = parser.getInt(MODE_KEY, GameManager.GAME_MODE_UNSUPPORTED);
// isGameModeOptedIn() returns if an app will handle all of the changes necessary
@@ -693,11 +717,11 @@
return mGameMode;
}
- public String getScaling() {
+ public synchronized String getScaling() {
return mScaling;
}
- public int getFps() {
+ public synchronized int getFps() {
return GameManagerService.getFpsInt(mFps);
}
@@ -709,15 +733,15 @@
return mLoadingBoostDuration;
}
- public void setScaling(String scaling) {
+ public synchronized void setScaling(String scaling) {
mScaling = scaling;
}
- public void setFpsStr(String fpsStr) {
+ public synchronized void setFpsStr(String fpsStr) {
mFps = fpsStr;
}
- public boolean isValid() {
+ public boolean isActive() {
return (mGameMode == GameManager.GAME_MODE_STANDARD
|| mGameMode == GameManager.GAME_MODE_PERFORMANCE
|| mGameMode == GameManager.GAME_MODE_BATTERY)
@@ -760,8 +784,10 @@
private int getAvailableGameModesBitfield() {
int field = 0;
- for (final int mode : mModeConfigs.keySet()) {
- field |= modeToBitmask(mode);
+ synchronized (mModeConfigLock) {
+ for (final int mode : mModeConfigs.keySet()) {
+ field |= modeToBitmask(mode);
+ }
}
if (mBatteryModeOptedIn) {
field |= modeToBitmask(GameManager.GAME_MODE_BATTERY);
@@ -802,27 +828,71 @@
* @return The package's GameModeConfiguration for the provided mode or null if absent
*/
public GameModeConfiguration getGameModeConfiguration(@GameMode int gameMode) {
- return mModeConfigs.get(gameMode);
+ synchronized (mModeConfigLock) {
+ return mModeConfigs.get(gameMode);
+ }
}
/**
* Insert a new GameModeConfiguration
*/
public void addModeConfig(GameModeConfiguration config) {
- if (config.isValid()) {
- mModeConfigs.put(config.getGameMode(), config);
+ if (config.isActive()) {
+ synchronized (mModeConfigLock) {
+ mModeConfigs.put(config.getGameMode(), config);
+ }
} else {
- Slog.w(TAG, "Invalid game mode config for "
+ Slog.w(TAG, "Attempt to add inactive game mode config for "
+ mPackageName + ":" + config.toString());
}
}
- public boolean isValid() {
- return mModeConfigs.size() > 0 || mBatteryModeOptedIn || mPerfModeOptedIn;
+ public boolean isActive() {
+ synchronized (mModeConfigLock) {
+ return mModeConfigs.size() > 0 || mBatteryModeOptedIn || mPerfModeOptedIn;
+ }
+ }
+
+ GamePackageConfiguration copyAndApplyOverride(GamePackageConfiguration overrideConfig) {
+ GamePackageConfiguration copy = new GamePackageConfiguration(mPackageName);
+ // if a game mode is overridden, we treat it with the highest priority and reset any
+ // opt-in game modes so that interventions are always executed.
+ copy.mPerfModeOptedIn = mPerfModeOptedIn && !(overrideConfig != null
+ && overrideConfig.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE)
+ != null);
+ copy.mBatteryModeOptedIn = mBatteryModeOptedIn && !(overrideConfig != null
+ && overrideConfig.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY)
+ != null);
+
+ // if any game mode is overridden, we will consider all interventions forced-active,
+ // this can be done more granular by checking if a specific intervention is
+ // overridden under each game mode override, but only if necessary.
+ copy.mAllowDownscale = mAllowDownscale || overrideConfig != null;
+ copy.mAllowAngle = mAllowAngle || overrideConfig != null;
+ copy.mAllowFpsOverride = mAllowFpsOverride || overrideConfig != null;
+ if (overrideConfig != null) {
+ synchronized (copy.mModeConfigLock) {
+ synchronized (mModeConfigLock) {
+ for (Map.Entry<Integer, GameModeConfiguration> entry :
+ mModeConfigs.entrySet()) {
+ copy.mModeConfigs.put(entry.getKey(), entry.getValue());
+ }
+ }
+ synchronized (overrideConfig.mModeConfigLock) {
+ for (Map.Entry<Integer, GameModeConfiguration> entry :
+ overrideConfig.mModeConfigs.entrySet()) {
+ copy.mModeConfigs.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+ }
+ return copy;
}
public String toString() {
- return "[Name:" + mPackageName + " Modes: " + mModeConfigs.toString() + "]";
+ synchronized (mModeConfigLock) {
+ return "[Name:" + mPackageName + " Modes: " + mModeConfigs.toString() + "]";
+ }
}
}
@@ -893,15 +963,7 @@
}
private @GameMode int[] getAvailableGameModesUnchecked(String packageName) {
- GamePackageConfiguration config = null;
- synchronized (mOverrideConfigLock) {
- config = mOverrideConfigs.get(packageName);
- }
- if (config == null) {
- synchronized (mDeviceConfigLock) {
- config = mConfigs.get(packageName);
- }
- }
+ final GamePackageConfiguration config = getConfig(packageName);
if (config == null) {
return new int[]{};
}
@@ -1054,19 +1116,19 @@
if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
return false;
}
-
+ final GamePackageConfiguration config;
synchronized (mDeviceConfigLock) {
- final GamePackageConfiguration config = mConfigs.get(packageName);
+ config = mConfigs.get(packageName);
if (config == null) {
return false;
}
- GamePackageConfiguration.GameModeConfiguration gameModeConfiguration =
- config.getGameModeConfiguration(gameMode);
- if (gameModeConfiguration == null) {
- return false;
- }
- return gameModeConfiguration.getUseAngle();
}
+ GamePackageConfiguration.GameModeConfiguration gameModeConfiguration =
+ config.getGameModeConfiguration(gameMode);
+ if (gameModeConfiguration == null) {
+ return false;
+ }
+ return gameModeConfiguration.getUseAngle();
}
/**
@@ -1081,19 +1143,19 @@
if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
return -1;
}
-
+ final GamePackageConfiguration config;
synchronized (mDeviceConfigLock) {
- final GamePackageConfiguration config = mConfigs.get(packageName);
- if (config == null) {
- return -1;
- }
- GamePackageConfiguration.GameModeConfiguration gameModeConfiguration =
- config.getGameModeConfiguration(gameMode);
- if (gameModeConfiguration == null) {
- return -1;
- }
- return gameModeConfiguration.getLoadingBoostDuration();
+ config = mConfigs.get(packageName);
}
+ if (config == null) {
+ return -1;
+ }
+ GamePackageConfiguration.GameModeConfiguration gameModeConfiguration =
+ config.getGameModeConfiguration(gameMode);
+ if (gameModeConfiguration == null) {
+ return -1;
+ }
+ return gameModeConfiguration.getLoadingBoostDuration();
}
/**
@@ -1262,7 +1324,7 @@
try {
final float fps = 0.0f;
final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
- nativeSetOverrideFrameRate(uid, fps);
+ setOverrideFrameRate(uid, fps);
} catch (PackageManager.NameNotFoundException e) {
return;
}
@@ -1348,7 +1410,7 @@
try {
final float fps = modeConfig.getFps();
final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
- nativeSetOverrideFrameRate(uid, fps);
+ setOverrideFrameRate(uid, fps);
} catch (PackageManager.NameNotFoundException e) {
return;
}
@@ -1357,32 +1419,17 @@
private void updateInterventions(String packageName,
@GameMode int gameMode, @UserIdInt int userId) {
+ final GamePackageConfiguration packageConfig = getConfig(packageName);
if (gameMode == GameManager.GAME_MODE_STANDARD
- || gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
+ || gameMode == GameManager.GAME_MODE_UNSUPPORTED || packageConfig == null
+ || packageConfig.willGamePerformOptimizations(gameMode)) {
disableCompatScale(packageName);
resetFps(packageName, userId);
- return;
- }
- GamePackageConfiguration packageConfig = null;
-
- synchronized (mOverrideConfigLock) {
- packageConfig = mOverrideConfigs.get(packageName);
- }
-
- if (packageConfig == null) {
- synchronized (mDeviceConfigLock) {
- packageConfig = mConfigs.get(packageName);
+ if (packageConfig == null) {
+ Slog.v(TAG, "Package configuration not found for " + packageName);
+ return;
}
}
-
- if (packageConfig == null) {
- disableCompatScale(packageName);
- Slog.v(TAG, "Package configuration not found for " + packageName);
- return;
- }
- if (packageConfig.willGamePerformOptimizations(gameMode)) {
- return;
- }
updateCompatModeDownscale(packageConfig, packageName, gameMode);
updateFps(packageConfig, packageName, gameMode, userId);
updateUseAngle(packageName, gameMode);
@@ -1403,34 +1450,34 @@
}
}
// Adding override game mode configuration of the given package name
+ GamePackageConfiguration overrideConfig;
synchronized (mOverrideConfigLock) {
// look for the existing override GamePackageConfiguration
- GamePackageConfiguration overrideConfig = mOverrideConfigs.get(packageName);
+ overrideConfig = mOverrideConfigs.get(packageName);
if (overrideConfig == null) {
- overrideConfig = new GamePackageConfiguration(packageName, userId);
+ overrideConfig = new GamePackageConfiguration(packageName);
mOverrideConfigs.put(packageName, overrideConfig);
}
-
- // modify GameModeConfiguration intervention settings
- GamePackageConfiguration.GameModeConfiguration overrideModeConfig =
- overrideConfig.getGameModeConfiguration(gameMode);
-
- if (fpsStr != null) {
- overrideModeConfig.setFpsStr(fpsStr);
- } else {
- overrideModeConfig.setFpsStr(
- GamePackageConfiguration.GameModeConfiguration.DEFAULT_FPS);
- }
- if (scaling != null) {
- overrideModeConfig.setScaling(scaling);
- } else {
- overrideModeConfig.setScaling(
- GamePackageConfiguration.GameModeConfiguration.DEFAULT_SCALING);
- }
- Slog.i(TAG, "Package Name: " + packageName
- + " FPS: " + String.valueOf(overrideModeConfig.getFps())
- + " Scaling: " + overrideModeConfig.getScaling());
}
+ // modify GameModeConfiguration intervention settings
+ GamePackageConfiguration.GameModeConfiguration overrideModeConfig =
+ overrideConfig.getOrAddDefaultGameModeConfiguration(gameMode);
+
+ if (fpsStr != null) {
+ overrideModeConfig.setFpsStr(fpsStr);
+ } else {
+ overrideModeConfig.setFpsStr(
+ GamePackageConfiguration.GameModeConfiguration.DEFAULT_FPS);
+ }
+ if (scaling != null) {
+ overrideModeConfig.setScaling(scaling);
+ } else {
+ overrideModeConfig.setScaling(
+ GamePackageConfiguration.GameModeConfiguration.DEFAULT_SCALING);
+ }
+ Slog.i(TAG, "Package Name: " + packageName
+ + " FPS: " + String.valueOf(overrideModeConfig.getFps())
+ + " Scaling: " + overrideModeConfig.getScaling());
setGameMode(packageName, gameMode, userId);
}
@@ -1496,15 +1543,7 @@
// If not, set the game mode to standard
int gameMode = getGameMode(packageName, userId);
- GamePackageConfiguration config = null;
- synchronized (mOverrideConfigLock) {
- config = mOverrideConfigs.get(packageName);
- }
- if (config == null) {
- synchronized (mDeviceConfigLock) {
- config = mConfigs.get(packageName);
- }
- }
+ final GamePackageConfiguration config = getConfig(packageName);
final int newGameMode = getNewGameMode(gameMode, config);
if (gameMode != newGameMode) {
setGameMode(packageName, GameManager.GAME_MODE_STANDARD, userId);
@@ -1543,18 +1582,8 @@
* Returns the string listing all the interventions currently set to a game.
*/
public String getInterventionList(String packageName) {
- GamePackageConfiguration packageConfig = null;
- synchronized (mOverrideConfigLock) {
- packageConfig = mOverrideConfigs.get(packageName);
- }
-
- if (packageConfig == null) {
- synchronized (mDeviceConfigLock) {
- packageConfig = mConfigs.get(packageName);
- }
- }
-
- StringBuilder listStrSb = new StringBuilder();
+ final GamePackageConfiguration packageConfig = getConfig(packageName);
+ final StringBuilder listStrSb = new StringBuilder();
if (packageConfig == null) {
listStrSb.append("\n No intervention found for package ")
.append(packageName);
@@ -1569,20 +1598,27 @@
* @hide
*/
@VisibleForTesting
- void updateConfigsForUser(@UserIdInt int userId, String... packageNames) {
+ void updateConfigsForUser(@UserIdInt int userId, boolean checkGamePackage,
+ String... packageNames) {
+ if (checkGamePackage) {
+ packageNames = Arrays.stream(packageNames).filter(
+ p -> isPackageGame(p, userId)).toArray(String[]::new);
+ }
try {
synchronized (mDeviceConfigLock) {
for (final String packageName : packageNames) {
final GamePackageConfiguration config =
new GamePackageConfiguration(packageName, userId);
- if (config.isValid()) {
+ if (config.isActive()) {
if (DEBUG) {
Slog.i(TAG, "Adding config: " + config.toString());
}
mConfigs.put(packageName, config);
} else {
- Slog.w(TAG, "Invalid package config for "
- + config.getPackageName() + ":" + config.toString());
+ if (DEBUG) {
+ Slog.w(TAG, "Inactive package config for "
+ + config.getPackageName() + ":" + config.toString());
+ }
mConfigs.remove(packageName);
}
}
@@ -1721,16 +1757,18 @@
*/
@VisibleForTesting
public GamePackageConfiguration getConfig(String packageName) {
- GamePackageConfiguration packageConfig = null;
+ GamePackageConfiguration overrideConfig = null;
+ GamePackageConfiguration config;
+ synchronized (mDeviceConfigLock) {
+ config = mConfigs.get(packageName);
+ }
synchronized (mOverrideConfigLock) {
- packageConfig = mOverrideConfigs.get(packageName);
+ overrideConfig = mOverrideConfigs.get(packageName);
}
- if (packageConfig == null) {
- synchronized (mDeviceConfigLock) {
- packageConfig = mConfigs.get(packageName);
- }
+ if (overrideConfig == null || config == null) {
+ return overrideConfig == null ? config : overrideConfig;
}
- return packageConfig;
+ return config.copyAndApplyOverride(overrideConfig);
}
private void registerPackageReceiver() {
@@ -1760,7 +1798,7 @@
}
switch (intent.getAction()) {
case ACTION_PACKAGE_ADDED:
- updateConfigsForUser(userId, packageName);
+ updateConfigsForUser(userId, true /*checkGamePackage*/, packageName);
break;
case ACTION_PACKAGE_REMOVED:
disableCompatScale(packageName);
@@ -1834,6 +1872,11 @@
return handlerThread;
}
+ @VisibleForTesting
+ void setOverrideFrameRate(int uid, float frameRate) {
+ nativeSetOverrideFrameRate(uid, frameRate);
+ }
+
/**
* load dynamic library for frame rate overriding JNI calls
*/
diff --git a/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in.xml b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in.xml
new file mode 100644
index 0000000..77fe786
--- /dev/null
+++ b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<game-mode-config
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:supportsPerformanceGameMode="true"
+ android:supportsBatteryGameMode="true"
+ android:allowGameAngleDriver="false"
+ android:allowGameDownscaling="false"
+ android:allowGameFpsOverride="false"
+/>
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_no_opt_in.xml
similarity index 100%
rename from services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml
rename to services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_disabled_no_opt_in.xml
diff --git a/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_all_opt_in.xml b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_all_opt_in.xml
new file mode 100644
index 0000000..96d2878
--- /dev/null
+++ b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_all_opt_in.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<game-mode-config
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:supportsPerformanceGameMode="true"
+ android:supportsBatteryGameMode="true"
+ android:allowGameAngleDriver="true"
+ android:allowGameDownscaling="true"
+ android:allowGameFpsOverride="true"
+/>
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml b/services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_no_opt_in.xml
similarity index 100%
rename from services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml
rename to services/tests/mockingservicestests/res/xml/game_manager_service_metadata_config_interventions_enabled_no_opt_in.xml
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index d675b0a..cfb8014 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -19,6 +19,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
@@ -67,7 +68,9 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
@@ -87,6 +90,7 @@
private static final String PACKAGE_NAME_INVALID = "com.android.app";
private static final int USER_ID_1 = 1001;
private static final int USER_ID_2 = 1002;
+ private static final int DEFAULT_PACKAGE_UID = 12345;
private MockitoSession mMockingSession;
private String mPackageName;
@@ -194,6 +198,8 @@
.thenReturn(packages);
when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
.thenReturn(applicationInfo);
+ when(mMockPackageManager.getPackageUidAsUser(mPackageName, USER_ID_1)).thenReturn(
+ DEFAULT_PACKAGE_UID);
LocalServices.addService(PowerManagerInternal.class, mMockPowerManager);
}
@@ -369,38 +375,41 @@
.thenReturn(applicationInfo);
}
- private void mockInterventionsEnabledFromXml() throws Exception {
- final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
- mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
- Bundle metaDataBundle = new Bundle();
- final int resId = 123;
- metaDataBundle.putInt(
- GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId);
- applicationInfo.metaData = metaDataBundle;
- when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
- .thenReturn(applicationInfo);
- seedGameManagerServiceMetaDataFromFile(mPackageName, resId,
- "res/xml/gama_manager_service_metadata_config_enabled.xml");
+ private void mockInterventionsEnabledNoOptInFromXml() throws Exception {
+ seedGameManagerServiceMetaDataFromFile(mPackageName, 123,
+ "res/xml/game_manager_service_metadata_config_interventions_enabled_no_opt_in.xml");
}
- private void mockInterventionsDisabledFromXml() throws Exception {
- final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
- mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
- Bundle metaDataBundle = new Bundle();
- final int resId = 123;
- metaDataBundle.putInt(
- GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId);
- applicationInfo.metaData = metaDataBundle;
- when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
- .thenReturn(applicationInfo);
- seedGameManagerServiceMetaDataFromFile(mPackageName, resId,
- "res/xml/gama_manager_service_metadata_config_disabled.xml");
+ private void mockInterventionsEnabledAllOptInFromXml() throws Exception {
+ seedGameManagerServiceMetaDataFromFile(mPackageName, 123,
+ "res/xml/game_manager_service_metadata_config_interventions_enabled_all_opt_in"
+ + ".xml");
+ }
+
+ private void mockInterventionsDisabledNoOptInFromXml() throws Exception {
+ seedGameManagerServiceMetaDataFromFile(mPackageName, 123,
+ "res/xml/game_manager_service_metadata_config_interventions_disabled_no_opt_in"
+ + ".xml");
+ }
+
+ private void mockInterventionsDisabledAllOptInFromXml() throws Exception {
+ seedGameManagerServiceMetaDataFromFile(mPackageName, 123,
+ "res/xml/game_manager_service_metadata_config_interventions_disabled_all_opt_in"
+ + ".xml");
}
private void seedGameManagerServiceMetaDataFromFile(String packageName, int resId,
String fileName)
throws Exception {
+ final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
+ mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
+ Bundle metaDataBundle = new Bundle();
+ metaDataBundle.putInt(
+ GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId);
+ applicationInfo.metaData = metaDataBundle;
+ when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+ .thenReturn(applicationInfo);
AssetManager assetManager =
InstrumentationRegistry.getInstrumentation().getContext().getAssets();
XmlResourceParser xmlResourceParser =
@@ -450,13 +459,13 @@
startUser(gameManagerService, USER_ID_1);
- gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
mockModifyGameModeGranted();
assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
// We need to make sure the mode is supported before setting it.
mockDeviceConfigAll();
- gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1);
assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
@@ -534,8 +543,8 @@
startUser(gameManagerService, USER_ID_1);
startUser(gameManagerService, USER_ID_2);
- gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
- gameManagerService.updateConfigsForUser(USER_ID_2, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_2, true, mPackageName);
// Set User 1 to Standard
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1);
@@ -563,7 +572,7 @@
if (gameManagerService == null) {
gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper());
startUser(gameManagerService, USER_ID_1);
- gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
}
ArraySet<Integer> reportedModes = new ArraySet<>();
int[] modes = gameManagerService.getAvailableGameModes(mPackageName);
@@ -582,7 +591,7 @@
if (gameManagerService == null) {
gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper());
startUser(gameManagerService, USER_ID_1);
- gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
}
GameManagerService.GamePackageConfiguration config =
gameManagerService.getConfig(mPackageName);
@@ -591,7 +600,7 @@
private void checkAngleEnabled(GameManagerService gameManagerService, int gameMode,
boolean angleEnabled) {
- gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
// Validate GamePackageConfiguration returns the correct value.
GameManagerService.GamePackageConfiguration config =
@@ -604,7 +613,7 @@
private void checkLoadingBoost(GameManagerService gameManagerService, int gameMode,
int loadingBoost) {
- gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
// Validate GamePackageConfiguration returns the correct value.
GameManagerService.GamePackageConfiguration config =
@@ -621,13 +630,19 @@
if (gameManagerService == null) {
gameManagerService = new GameManagerService(mMockContext, mTestLooper.getLooper());
startUser(gameManagerService, USER_ID_1);
- gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
}
GameManagerService.GamePackageConfiguration config =
gameManagerService.getConfig(mPackageName);
assertEquals(fps, config.getGameModeConfiguration(gameMode).getFps());
}
+ private boolean checkOptedIn(GameManagerService gameManagerService, int gameMode) {
+ GameManagerService.GamePackageConfiguration config =
+ gameManagerService.getConfig(mPackageName);
+ return config.willGamePerformOptimizations(gameMode);
+ }
+
/**
* Phenotype device config exists, but is only propagating the default value.
*/
@@ -743,7 +758,7 @@
* Override device configs for both battery and performance modes exists and are valid.
*/
@Test
- public void testSetDeviceOverrideConfigAll() {
+ public void testSetDeviceConfigOverrideAll() {
mockDeviceConfigAll();
mockModifyGameModeGranted();
@@ -763,6 +778,75 @@
checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 60);
}
+ @Test
+ public void testSetBatteryModeConfigOverride_thenUpdateAllDeviceConfig() throws Exception {
+ mockModifyGameModeGranted();
+ String configStringBefore =
+ "mode=2,downscaleFactor=1.0,fps=90:mode=3,downscaleFactor=0.1,fps=30";
+ when(DeviceConfig.getProperty(anyString(), anyString()))
+ .thenReturn(configStringBefore);
+ mockInterventionsEnabledNoOptInFromXml();
+ GameManagerService gameManagerService = new GameManagerService(mMockContext,
+ mTestLooper.getLooper());
+ startUser(gameManagerService, USER_ID_1);
+
+ checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, "1.0");
+ checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
+ checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.1");
+ checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 30);
+
+ gameManagerService.setGameModeConfigOverride(mPackageName, USER_ID_1, 3, "40",
+ "0.2");
+
+ checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 40);
+ checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.2");
+
+ String configStringAfter =
+ "mode=2,downscaleFactor=0.9,fps=60:mode=3,downscaleFactor=0.3,fps=50";
+ when(DeviceConfig.getProperty(anyString(), anyString()))
+ .thenReturn(configStringAfter);
+ gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);
+
+ // performance mode was not overridden thus it should be updated
+ checkDownscaling(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, "0.9");
+ checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 60);
+
+ // battery mode was overridden thus it should be the same as the override
+ checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.2");
+ checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 40);
+ }
+
+ @Test
+ public void testSetBatteryModeConfigOverride_thenOptInBatteryMode() throws Exception {
+ mockModifyGameModeGranted();
+ String configStringBefore =
+ "mode=2,downscaleFactor=1.0,fps=90:mode=3,downscaleFactor=0.1,fps=30";
+ when(DeviceConfig.getProperty(anyString(), anyString()))
+ .thenReturn(configStringBefore);
+ mockInterventionsDisabledNoOptInFromXml();
+ GameManagerService gameManagerService = new GameManagerService(mMockContext,
+ mTestLooper.getLooper());
+ startUser(gameManagerService, USER_ID_1);
+
+ assertFalse(checkOptedIn(gameManagerService, GameManager.GAME_MODE_PERFORMANCE));
+ assertFalse(checkOptedIn(gameManagerService, GameManager.GAME_MODE_BATTERY));
+ checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0);
+
+ gameManagerService.setGameModeConfigOverride(mPackageName, USER_ID_1, 3, "40",
+ "0.2");
+ checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0);
+ // override will enable the interventions
+ checkDownscaling(gameManagerService, GameManager.GAME_MODE_BATTERY, "0.2");
+ checkFps(gameManagerService, GameManager.GAME_MODE_BATTERY, 40);
+
+ mockInterventionsDisabledAllOptInFromXml();
+ gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);
+
+ assertTrue(checkOptedIn(gameManagerService, GameManager.GAME_MODE_PERFORMANCE));
+ // opt-in is still false for battery mode as override exists
+ assertFalse(checkOptedIn(gameManagerService, GameManager.GAME_MODE_BATTERY));
+ }
+
/**
* Override device config for performance mode exists and is valid.
*/
@@ -1037,7 +1121,7 @@
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
assertEquals(GameManager.GAME_MODE_PERFORMANCE,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
- mockInterventionsEnabledFromXml();
+ mockInterventionsEnabledNoOptInFromXml();
checkLoadingBoost(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0);
}
@@ -1045,7 +1129,7 @@
public void testGameModeConfigAllowFpsTrue() throws Exception {
mockDeviceConfigAll();
mockModifyGameModeGranted();
- mockInterventionsEnabledFromXml();
+ mockInterventionsEnabledNoOptInFromXml();
GameManagerService gameManagerService = new GameManagerService(mMockContext,
mTestLooper.getLooper());
startUser(gameManagerService, USER_ID_1);
@@ -1060,7 +1144,7 @@
public void testGameModeConfigAllowFpsFalse() throws Exception {
mockDeviceConfigAll();
mockModifyGameModeGranted();
- mockInterventionsDisabledFromXml();
+ mockInterventionsDisabledNoOptInFromXml();
GameManagerService gameManagerService = new GameManagerService(mMockContext,
mTestLooper.getLooper());
startUser(gameManagerService, USER_ID_1);
@@ -1091,7 +1175,7 @@
GameManagerService gameManagerService =
new GameManagerService(mMockContext, mTestLooper.getLooper());
startUser(gameManagerService, USER_ID_1);
- gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
GameManagerService.GamePackageConfiguration config =
gameManagerService.getConfig(mPackageName);
assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE));
@@ -1109,7 +1193,7 @@
new GameManagerService(mMockContext, mTestLooper.getLooper());
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
- gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
}
@@ -1126,7 +1210,7 @@
new GameManagerService(mMockContext, mTestLooper.getLooper());
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1);
- gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
}
@@ -1143,7 +1227,7 @@
new GameManagerService(mMockContext, mTestLooper.getLooper());
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_UNSUPPORTED, USER_ID_1);
- gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
+ gameManagerService.updateConfigsForUser(USER_ID_1, true, mPackageName);
assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
}
@@ -1404,4 +1488,80 @@
assertEquals(splitLine[6], "angle=0,scaling=0.7,fps=30");
}
+
+ @Test
+ public void testResetInterventions_onDeviceConfigReset() throws Exception {
+ mockModifyGameModeGranted();
+ String configStringBefore =
+ "mode=2,downscaleFactor=1.0,fps=90";
+ when(DeviceConfig.getProperty(anyString(), anyString()))
+ .thenReturn(configStringBefore);
+ mockInterventionsEnabledNoOptInFromXml();
+ GameManagerService gameManagerService = Mockito.spy(new GameManagerService(mMockContext,
+ mTestLooper.getLooper()));
+ startUser(gameManagerService, USER_ID_1);
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+ Mockito.verify(gameManagerService).setOverrideFrameRate(
+ ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
+ ArgumentMatchers.eq(90.0f));
+ checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
+
+ String configStringAfter = "";
+ when(DeviceConfig.getProperty(anyString(), anyString()))
+ .thenReturn(configStringAfter);
+ gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);
+ Mockito.verify(gameManagerService).setOverrideFrameRate(
+ ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
+ ArgumentMatchers.eq(0.0f));
+ }
+
+ @Test
+ public void testResetInterventions_onInterventionsDisabled() throws Exception {
+ mockModifyGameModeGranted();
+ String configStringBefore =
+ "mode=2,downscaleFactor=1.0,fps=90";
+ when(DeviceConfig.getProperty(anyString(), anyString()))
+ .thenReturn(configStringBefore);
+ mockInterventionsEnabledNoOptInFromXml();
+ GameManagerService gameManagerService = Mockito.spy(new GameManagerService(mMockContext,
+ mTestLooper.getLooper()));
+ startUser(gameManagerService, USER_ID_1);
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+ Mockito.verify(gameManagerService).setOverrideFrameRate(
+ ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
+ ArgumentMatchers.eq(90.0f));
+ checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
+
+ mockInterventionsDisabledNoOptInFromXml();
+ gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);
+ Mockito.verify(gameManagerService).setOverrideFrameRate(
+ ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
+ ArgumentMatchers.eq(0.0f));
+ checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0);
+ }
+
+ @Test
+ public void testResetInterventions_onGameModeOptedIn() throws Exception {
+ mockModifyGameModeGranted();
+ String configStringBefore =
+ "mode=2,downscaleFactor=1.0,fps=90";
+ when(DeviceConfig.getProperty(anyString(), anyString()))
+ .thenReturn(configStringBefore);
+ mockInterventionsEnabledNoOptInFromXml();
+ GameManagerService gameManagerService = Mockito.spy(new GameManagerService(mMockContext,
+ mTestLooper.getLooper()));
+ startUser(gameManagerService, USER_ID_1);
+
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+ Mockito.verify(gameManagerService).setOverrideFrameRate(
+ ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
+ ArgumentMatchers.eq(90.0f));
+ checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
+
+ mockInterventionsEnabledAllOptInFromXml();
+ gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);
+ Mockito.verify(gameManagerService).setOverrideFrameRate(
+ ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
+ ArgumentMatchers.eq(0.0f));
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
index dd0c162..f494f72 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
@@ -51,6 +51,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -87,6 +88,7 @@
LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
}
+ @Ignore("b/253871109")
@Test
public void testAddPinCreatesPinned() throws RemoteException {
grantSlicePermission();
@@ -97,6 +99,7 @@
verify(mService, times(1)).createPinnedSlice(eq(maybeAddUserId(TEST_URI, 0)), anyString());
}
+ @Ignore("b/253871109")
@Test
public void testRemovePinDestroysPinned() throws RemoteException {
grantSlicePermission();
@@ -109,6 +112,7 @@
verify(mCreatedSliceState, never()).destroy();
}
+ @Ignore("b/253871109")
@Test
public void testCheckAutoGrantPermissions() throws RemoteException {
String[] testPerms = new String[] {
@@ -129,12 +133,14 @@
verify(mContextSpy).checkPermission(eq("perm2"), eq(Process.myPid()), eq(Process.myUid()));
}
+ @Ignore("b/253871109")
@Test(expected = IllegalStateException.class)
public void testNoPinThrow() throws Exception {
grantSlicePermission();
mService.getPinnedSpecs(TEST_URI, "pkg");
}
+ @Ignore("b/253871109")
@Test
public void testGetPinnedSpecs() throws Exception {
grantSlicePermission();