Merge "DOZING->LOCKSCREEN alpha should just be 1f" into main
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index de39847..ff737a4 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -58,8 +58,6 @@
import static android.view.inputmethod.Flags.ctrlShiftShortcut;
import static android.view.inputmethod.Flags.predictiveBackIme;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
import android.annotation.AnyThread;
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
@@ -500,36 +498,53 @@
public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3;
/**
- * Enum flag to be used for {@link #setBackDisposition(int)}.
+ * The disposition mode that indicates the expected affordance for the back button.
*
* @hide
*/
- @Retention(SOURCE)
- @IntDef(value = {BACK_DISPOSITION_DEFAULT, BACK_DISPOSITION_WILL_NOT_DISMISS,
- BACK_DISPOSITION_WILL_DISMISS, BACK_DISPOSITION_ADJUST_NOTHING},
- prefix = "BACK_DISPOSITION_")
+ @IntDef(prefix = { "BACK_DISPOSITION_" }, value = {
+ BACK_DISPOSITION_DEFAULT,
+ BACK_DISPOSITION_WILL_NOT_DISMISS,
+ BACK_DISPOSITION_WILL_DISMISS,
+ BACK_DISPOSITION_ADJUST_NOTHING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
public @interface BackDispositionMode {}
/**
+ * The IME is active, and ready to accept touch/key events. It may or may not be visible.
+ *
* @hide
- * The IME is active. It may or may not be visible.
*/
- public static final int IME_ACTIVE = 0x1;
+ public static final int IME_ACTIVE = 1 << 0;
/**
- * @hide
* The IME is perceptibly visible to the user.
+ *
+ * @hide
*/
- public static final int IME_VISIBLE = 0x2;
+ public static final int IME_VISIBLE = 1 << 1;
/**
- * @hide
* The IME is visible, but not yet perceptible to the user (e.g. fading in)
* by {@link android.view.WindowInsetsController}.
*
* @see InputMethodManager#reportPerceptible
+ * @hide
*/
- public static final int IME_VISIBLE_IMPERCEPTIBLE = 0x4;
+ public static final int IME_VISIBLE_IMPERCEPTIBLE = 1 << 2;
+
+ /**
+ * The IME window visibility state.
+ *
+ * @hide
+ */
+ @IntDef(flag = true, prefix = { "IME_" }, value = {
+ IME_ACTIVE,
+ IME_VISIBLE,
+ IME_VISIBLE_IMPERCEPTIBLE,
+ })
+ public @interface ImeWindowVisibility {}
// Min and max values for back disposition.
private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
@@ -1342,7 +1357,8 @@
mImeSurfaceRemoverRunnable = null;
}
- private void setImeWindowStatus(int visibilityFlags, int backDisposition) {
+ private void setImeWindowStatus(@ImeWindowVisibility int visibilityFlags,
+ @BackDispositionMode int backDisposition) {
mPrivOps.setImeWindowStatusAsync(visibilityFlags, backDisposition);
}
@@ -3301,7 +3317,7 @@
ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_HIDE_WINDOW);
ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper,
null /* icProto */);
- setImeWindowStatus(0, mBackDisposition);
+ setImeWindowStatus(0 /* visibilityFlags */, mBackDisposition);
if (android.view.inputmethod.Flags.refactorInsetsController()) {
// The ImeInsetsSourceProvider need the statsToken when dispatching the control. We
// send the token here, so that another request in the provider can be cancelled.
@@ -4476,6 +4492,7 @@
};
}
+ @ImeWindowVisibility
private int mapToImeWindowStatus() {
return IME_ACTIVE
| (isInputViewShown() ? IME_VISIBLE : 0);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 921363c..b009c99 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -20,6 +20,8 @@
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
@@ -106,13 +108,10 @@
*
* @param vis visibility flags
* @param backDisposition disposition flags
- * @see android.inputmethodservice.InputMethodService#IME_ACTIVE
- * @see android.inputmethodservice.InputMethodService#IME_VISIBLE
- * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_DEFAULT
- * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_ADJUST_NOTHING
*/
@AnyThread
- public void setImeWindowStatusAsync(int vis, int backDisposition) {
+ public void setImeWindowStatusAsync(@ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition) {
final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
if (ops == null) {
return;
diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
index 7240aff..3adc6b2 100644
--- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
+++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
@@ -16,6 +16,8 @@
package com.android.internal.statusbar;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
@@ -30,7 +32,9 @@
public final int mDisabledFlags1; // switch[0]
public final int mAppearance; // switch[1]
public final AppearanceRegion[] mAppearanceRegions; // switch[2]
+ @ImeWindowVisibility
public final int mImeWindowVis; // switch[3]
+ @BackDispositionMode
public final int mImeBackDisposition; // switch[4]
public final boolean mShowImeSwitcher; // switch[5]
public final int mDisabledFlags2; // switch[6]
@@ -42,10 +46,11 @@
public final LetterboxDetails[] mLetterboxDetails;
public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1,
- int appearance, AppearanceRegion[] appearanceRegions, int imeWindowVis,
- int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2,
- boolean navbarColorManagedByIme, int behavior, int requestedVisibleTypes,
- String packageName, int transientBarTypes, LetterboxDetails[] letterboxDetails) {
+ int appearance, AppearanceRegion[] appearanceRegions,
+ @ImeWindowVisibility int imeWindowVis, @BackDispositionMode int imeBackDisposition,
+ boolean showImeSwitcher, int disabledFlags2, boolean navbarColorManagedByIme,
+ int behavior, int requestedVisibleTypes, String packageName, int transientBarTypes,
+ LetterboxDetails[] letterboxDetails) {
mIcons = new ArrayMap<>(icons);
mDisabledFlags1 = disabledFlags1;
mAppearance = appearance;
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt
index dad5db9..a9dba4a 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt
@@ -17,11 +17,13 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.Presubmit
+import android.tools.NavBar
import android.tools.Rotation
+import android.tools.ScenarioBuilder
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
-import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.SERVICE_TRACE_CONFIG
import android.tools.traces.component.ComponentNameMatcher
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitscreen.benchmark.MultipleShowImeRequestsInSplitScreenBenchmark
@@ -35,7 +37,7 @@
/**
* Test quick switch between two split pairs.
*
- * To run this test: `atest WMShellFlickerTestsSplitScreenGroup2:MultipleShowImeRequestsInSplitScreen`
+ * To run this test: `atest WMShellFlickerTestsSplitScreenGroupOther:MultipleShowImeRequestsInSplitScreen`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@@ -58,10 +60,22 @@
}
companion object {
+ private fun createFlickerTest(
+ navBarMode: NavBar
+ ) = LegacyFlickerTest(ScenarioBuilder()
+ .withStartRotation(Rotation.ROTATION_0)
+ .withEndRotation(Rotation.ROTATION_0)
+ .withNavBarMode(navBarMode), resultReaderProvider = { scenario ->
+ android.tools.flicker.datastore.CachedResultReader(
+ scenario, SERVICE_TRACE_CONFIG
+ )
+ })
+
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
+ fun getParams() = listOf(
+ createFlickerTest(NavBar.MODE_GESTURAL),
+ createFlickerTest(NavBar.MODE_3BUTTON)
)
}
-}
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 7e7c76e..8cc9974 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -35,6 +35,7 @@
import android.os.ParcelUuid;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -545,6 +546,7 @@
* Test to verify OnDeviceUnpaired() for csip device unpair.
*/
@Test
+ @Ignore("b/359066481")
public void onDeviceUnpaired_unpairCsipSubDevice() {
when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
index 194a0e2..4e54d8f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
@@ -40,6 +40,7 @@
import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -58,6 +59,7 @@
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowInteractionJankMonitor.class, SettingsJankMonitorTest.ShadowBuilder.class})
+@Ignore("b/359066481")
public class SettingsJankMonitorTest {
private static final String TEST_KEY = "key";
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java
index 0d318c3..325bb2c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java
@@ -36,6 +36,7 @@
import com.android.settingslib.testutils.shadow.ShadowSmsApplication;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -86,6 +87,7 @@
mPowerAllowlistBackend = new PowerAllowlistBackend(mContext, mDeviceIdleService);
}
+ @Ignore("b/359066481")
@Test
public void testIsAllowlisted() throws Exception {
doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getFullPowerWhitelist();
@@ -160,6 +162,7 @@
assertThat(mPowerAllowlistBackend.isDefaultActiveApp(PACKAGE_ONE, UID)).isTrue();
}
+ @Ignore("b/359066481")
@Test
public void testIsSystemAllowlisted() throws Exception {
doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getSystemPowerWhitelist();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
index f0f53d6..7f4bdae 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
@@ -44,6 +44,7 @@
import com.android.settingslib.widget.preference.banner.R;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
@@ -53,6 +54,7 @@
import org.robolectric.shadows.ShadowTouchDelegate;
import org.robolectric.util.ReflectionHelpers;
+@Ignore("b/359066481")
@RunWith(RobolectricTestRunner.class)
public class BannerMessagePreferenceTest {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 30c4ee5..9ab853f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -690,7 +690,7 @@
Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null,
null, null);
try {
- return extractRelevantValues(cursor, GlobalSettings.SETTINGS_TO_BACKUP);
+ return extractRelevantValues(cursor, getGlobalSettingsToBackup());
} finally {
cursor.close();
}
@@ -1011,7 +1011,7 @@
Settings.System.LEGACY_RESTORE_SETTINGS);
validators = SystemSettingsValidators.VALIDATORS;
} else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
- whitelist = ArrayUtils.concat(String.class, GlobalSettings.SETTINGS_TO_BACKUP,
+ whitelist = ArrayUtils.concat(String.class, getGlobalSettingsToBackup(),
Settings.Global.LEGACY_RESTORE_SETTINGS);
validators = GlobalSettingsValidators.VALIDATORS;
} else {
@@ -1021,6 +1021,17 @@
return new SettingsBackupWhitelist(whitelist, validators);
}
+ private String[] getGlobalSettingsToBackup() {
+ // On watches, we don't want to backup or restore 'bluetooth_on' setting, as setting it to
+ // false during restore would cause watch OOBE to fail due to bluetooth connection loss.
+ if (isWatch()) {
+ return ArrayUtils.removeElement(
+ String.class, GlobalSettings.SETTINGS_TO_BACKUP, Settings.Global.BLUETOOTH_ON);
+ }
+
+ return GlobalSettings.SETTINGS_TO_BACKUP;
+ }
+
private boolean isBlockedByDynamicList(Set<String> dynamicBlockList, Uri areaUri, String key) {
String contentKey = Uri.withAppendedPath(areaUri, key).toString();
return dynamicBlockList.contains(contentKey);
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
index d4ca4a3..3a391505 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
@@ -26,6 +26,7 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
@@ -221,6 +222,21 @@
}
@Test
+ public void testOnRestore_bluetoothOnRestoredOnNonWearablesOnly() {
+ TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext);
+ mAgentUnderTest.mSettingsHelper = settingsHelper;
+
+ restoreGlobalSettings(generateBackupData(Map.of(Settings.Global.BLUETOOTH_ON, "0")));
+
+ var isWatch = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ if (isWatch) {
+ assertFalse(settingsHelper.mWrittenValues.containsKey(Settings.Global.BLUETOOTH_ON));
+ } else {
+ assertEquals("0", settingsHelper.mWrittenValues.get(Settings.Global.BLUETOOTH_ON));
+ }
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_CONFIGURABLE_FONT_SCALE_DEFAULT)
public void testFindClosestAllowedFontScale() {
final String[] availableFontScales = new String[]{"0.5", "0.9", "1.0", "1.1", "1.5"};
@@ -266,6 +282,20 @@
return buffer.array();
}
+ private void restoreGlobalSettings(byte[] backupData) {
+ mAgentUnderTest.restoreSettings(
+ backupData,
+ /* pos= */ 0,
+ backupData.length,
+ Settings.Global.CONTENT_URI,
+ null,
+ null,
+ null,
+ R.array.restore_blocked_global_settings,
+ /* dynamicBlockList= */ Collections.emptySet(),
+ /* settingsToPreserve= */ Collections.emptySet());
+ }
+
private byte[] generateUncorruptedHeader() throws IOException {
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
mAgentUnderTest.writeHeader(os);
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
index 26ab10b..85d5d6a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
@@ -24,9 +24,11 @@
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.approachLayout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.viewinterop.AndroidView
import com.android.compose.animation.scene.MovableElementKey
import com.android.compose.animation.scene.SceneScope
@@ -51,6 +53,7 @@
mediaHost: MediaHost,
modifier: Modifier = Modifier,
carouselController: MediaCarouselController,
+ offsetProvider: (() -> IntOffset)? = null,
) {
if (!isVisible) {
return
@@ -68,21 +71,38 @@
MovableElement(
key = MediaCarousel.Elements.Content,
- modifier = modifier.height(mediaHeight).fillMaxWidth()
+ modifier = modifier.height(mediaHeight).fillMaxWidth(),
) {
content {
AndroidView(
modifier =
- Modifier.fillMaxSize().layout { measurable, constraints ->
- val placeable = measurable.measure(constraints)
+ Modifier.fillMaxSize()
+ .approachLayout(
+ isMeasurementApproachInProgress = { offsetProvider != null },
+ approachMeasure = { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ placeable.placeRelative(
+ offsetProvider?.invoke() ?: IntOffset.Zero
+ )
+ }
+ }
+ )
+ .layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
- // Notify controller to size the carousel for the current space
- mediaHost.measurementInput =
- MeasurementInput(placeable.width, placeable.height)
- carouselController.setSceneContainerSize(placeable.width, placeable.height)
+ // Notify controller to size the carousel for the current space
+ mediaHost.measurementInput =
+ MeasurementInput(placeable.width, placeable.height)
+ carouselController.setSceneContainerSize(
+ placeable.width,
+ placeable.height
+ )
- layout(placeable.width, placeable.height) { placeable.placeRelative(0, 0) }
- },
+ layout(placeable.width, placeable.height) {
+ placeable.placeRelative(0, 0)
+ }
+ },
factory = { context ->
FrameLayout(context).apply {
layoutParams =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt
index 3f04f37..70c0db1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt
@@ -27,7 +27,6 @@
/** [ElementContentPicker] implementation for the media carousel object. */
object MediaContentPicker : StaticElementContentPicker {
- const val SHADE_FRACTION = 0.66f
override val contents =
setOf(
Scenes.Lockscreen,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
index a9da733..71fa6c9 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
@@ -25,7 +25,6 @@
import com.android.compose.animation.scene.UserActionDistance
import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.media.controls.ui.composable.MediaCarousel
-import com.android.systemui.media.controls.ui.composable.MediaContentPicker
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.shade.ui.composable.Shade
@@ -54,13 +53,7 @@
fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) }
fractionRange(start = .33f) {
- val qsTranslation =
- ShadeHeader.Dimensions.CollapsedHeight * MediaContentPicker.SHADE_FRACTION
- val qsExpansionDiff =
- ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight
- translate(MediaCarousel.Elements.Content, y = -(qsExpansionDiff + qsTranslation))
fade(MediaCarousel.Elements.Content)
-
fade(ShadeHeader.Elements.Clock)
fade(ShadeHeader.Elements.CollapsedContentStart)
fade(ShadeHeader.Elements.CollapsedContentEnd)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
index 21dfc49..b677dff 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
@@ -26,7 +26,6 @@
import com.android.compose.animation.scene.UserActionDistance
import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.media.controls.ui.composable.MediaCarousel
-import com.android.systemui.media.controls.ui.composable.MediaContentPicker
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.scene.shared.model.Scenes
@@ -62,12 +61,9 @@
fade(QuickSettings.Elements.FooterActions)
}
- val qsTranslation = ShadeHeader.Dimensions.CollapsedHeight * MediaContentPicker.SHADE_FRACTION
- val qsExpansionDiff =
- ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight
-
- translate(QuickSettings.Elements.QuickQuickSettings, y = -qsTranslation)
- translate(MediaCarousel.Elements.Content, y = -(qsExpansionDiff + qsTranslation))
+ val qsTranslation = -ShadeHeader.Dimensions.CollapsedHeight * 0.66f
+ translate(QuickSettings.Elements.QuickQuickSettings, y = qsTranslation)
+ translate(MediaCarousel.Elements.Content, y = qsTranslation)
translate(Notifications.Elements.NotificationScrim, Edge.Top, false)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeMediaOffsetProvider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeMediaOffsetProvider.kt
new file mode 100644
index 0000000..e0b7909
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeMediaOffsetProvider.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 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.shade.ui.composable
+
+import androidx.compose.ui.unit.IntOffset
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter
+
+/**
+ * Provider for the extra offset for the Media section in the shade to accommodate for the squishing
+ * qs or qqs tiles.
+ */
+interface ShadeMediaOffsetProvider {
+
+ /** Returns current offset to be applied to the Media Carousel */
+ val offset: IntOffset
+
+ /**
+ * [ShadeMediaOffsetProvider] implementation for Quick Settings.
+ *
+ * [updateLayout] should represent an access to some state to trigger Compose to relayout to
+ * track [QSSceneAdapter] internal state changes during the transition.
+ */
+ class Qs(private val updateLayout: () -> Unit, private val qsSceneAdapter: QSSceneAdapter) :
+ ShadeMediaOffsetProvider {
+
+ override val offset: IntOffset
+ get() =
+ calculateQsOffset(
+ updateLayout,
+ qsSceneAdapter.qsHeight,
+ qsSceneAdapter.squishedQsHeight
+ )
+ }
+
+ /**
+ * [ShadeMediaOffsetProvider] implementation for Quick Quick Settings.
+ *
+ * [updateLayout] should represent an access to some state to trigger Compose to relayout to
+ * track [QSSceneAdapter] internal state changes during the transition.
+ */
+ class Qqs(private val updateLayout: () -> Unit, private val qsSceneAdapter: QSSceneAdapter) :
+ ShadeMediaOffsetProvider {
+
+ override val offset: IntOffset
+ get() =
+ calculateQsOffset(
+ updateLayout,
+ qsSceneAdapter.qqsHeight,
+ qsSceneAdapter.squishedQqsHeight
+ )
+ }
+
+ companion object {
+
+ protected fun calculateQsOffset(
+ updateLayout: () -> Unit,
+ qsHeight: Int,
+ qsSquishedHeight: Int
+ ): IntOffset {
+ updateLayout()
+ val distanceFromBottomToActualBottom = qsHeight - qsSquishedHeight
+ return IntOffset(0, -distanceFromBottomToActualBottom)
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 0e3fcf4..16972bc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -118,7 +118,6 @@
object Shade {
object Elements {
- val MediaCarousel = ElementKey("ShadeMediaCarousel")
val BackgroundScrim =
ElementKey("ShadeBackgroundScrim", contentPicker = LowestZIndexContentPicker)
val SplitShadeStartColumn = ElementKey("SplitShadeStartColumn")
@@ -283,6 +282,13 @@
val navBarHeight = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
+ val mediaOffsetProvider = remember {
+ ShadeMediaOffsetProvider.Qqs(
+ { @Suppress("UNUSED_EXPRESSION") tileSquishiness },
+ viewModel.qsSceneAdapter,
+ )
+ }
+
Box(
modifier =
modifier.thenIf(shouldPunchHoleBehindScrim) {
@@ -335,12 +341,12 @@
)
}
- MediaCarousel(
+ ShadeMediaCarousel(
isVisible = isMediaVisible,
mediaHost = mediaHost,
+ mediaOffsetProvider = mediaOffsetProvider,
modifier =
- Modifier.fillMaxWidth()
- .layoutId(QSMediaMeasurePolicy.LayoutId.Media),
+ Modifier.layoutId(QSMediaMeasurePolicy.LayoutId.Media),
carouselController = mediaCarouselController,
)
}
@@ -497,6 +503,13 @@
val brightnessMirrorShowingModifier = Modifier.graphicsLayer { alpha = contentAlpha }
+ val mediaOffsetProvider = remember {
+ ShadeMediaOffsetProvider.Qs(
+ { @Suppress("UNUSED_EXPRESSION") tileSquishiness },
+ viewModel.qsSceneAdapter,
+ )
+ }
+
Box {
Box(
modifier =
@@ -570,11 +583,13 @@
squishiness = { tileSquishiness },
)
}
- MediaCarousel(
+
+ ShadeMediaCarousel(
isVisible = isMediaVisible,
mediaHost = mediaHost,
+ mediaOffsetProvider = mediaOffsetProvider,
modifier =
- Modifier.fillMaxWidth().thenIf(
+ Modifier.thenIf(
MediaContentPicker.shouldElevateMedia(layoutState)
) {
Modifier.zIndex(1f)
@@ -620,3 +635,25 @@
)
}
}
+
+@Composable
+private fun SceneScope.ShadeMediaCarousel(
+ isVisible: Boolean,
+ mediaHost: MediaHost,
+ carouselController: MediaCarouselController,
+ mediaOffsetProvider: ShadeMediaOffsetProvider,
+ modifier: Modifier = Modifier,
+) {
+ MediaCarousel(
+ modifier = modifier.fillMaxWidth(),
+ isVisible = isVisible,
+ mediaHost = mediaHost,
+ carouselController = carouselController,
+ offsetProvider =
+ if (MediaContentPicker.shouldElevateMedia(layoutState)) {
+ null
+ } else {
+ { mediaOffsetProvider.offset }
+ }
+ )
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
index e13ca391..ae5a84b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
@@ -120,7 +120,7 @@
}
@Deprecated(
- "Use animateSceneFloatAsState() instead",
+ "Use animateContentFloatAsState() instead",
replaceWith = ReplaceWith("animateContentFloatAsState(value, key, canOverflow)")
)
@Composable
@@ -171,7 +171,7 @@
}
@Deprecated(
- "Use animateSceneDpAsState() instead",
+ "Use animateContentDpAsState() instead",
replaceWith = ReplaceWith("animateContentDpAsState(value, key, canOverflow)")
)
@Composable
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index a43028a..712fe6b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -459,38 +459,11 @@
animateTo(targetScene = targetScene, targetOffset = targetOffset)
} else {
- // We are doing an overscroll animation between scenes. In this case, we can also start
- // from the idle position.
-
- val startFromIdlePosition = swipeTransition.dragOffset == 0f
-
- if (startFromIdlePosition) {
- // If there is a target scene, we start the overscroll animation.
- val result = swipes.findUserActionResultStrict(velocity)
- if (result == null) {
- // We will not animate
- swipeTransition.snapToScene(fromScene.key)
- return 0f
- }
-
- val newSwipeTransition =
- SwipeTransition(
- layoutState = layoutState,
- coroutineScope = draggableHandler.coroutineScope,
- fromScene = fromScene,
- result = result,
- swipes = swipes,
- layoutImpl = draggableHandler.layoutImpl,
- orientation = draggableHandler.orientation,
- )
- .apply { _currentScene = swipeTransition._currentScene }
-
- updateTransition(newSwipeTransition)
- animateTo(targetScene = fromScene, targetOffset = 0f)
- } else {
- // We were between two scenes: animate to the initial scene.
- animateTo(targetScene = fromScene, targetOffset = 0f)
+ // We are doing an overscroll preview animation between scenes.
+ check(fromScene == swipeTransition._currentScene) {
+ "canChangeScene is false but currentScene != fromScene"
}
+ animateTo(targetScene = fromScene, targetOffset = 0f)
}
// The onStop animation consumes any remaining velocity.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index a30b780..79b3856 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -17,6 +17,8 @@
package com.android.compose.animation.scene
import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.Easing
+import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.SpringSpec
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.ui.geometry.Offset
@@ -140,6 +142,7 @@
fun fractionRange(
start: Float? = null,
end: Float? = null,
+ easing: Easing = LinearEasing,
builder: PropertyTransformationBuilder.() -> Unit,
)
}
@@ -182,6 +185,7 @@
fun timestampRange(
startMillis: Int? = null,
endMillis: Int? = null,
+ easing: Easing = LinearEasing,
builder: PropertyTransformationBuilder.() -> Unit,
)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index 6515cb8..a63b19a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -18,6 +18,7 @@
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.DurationBasedAnimationSpec
+import androidx.compose.animation.core.Easing
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.SpringSpec
import androidx.compose.animation.core.VectorConverter
@@ -163,9 +164,10 @@
override fun fractionRange(
start: Float?,
end: Float?,
+ easing: Easing,
builder: PropertyTransformationBuilder.() -> Unit
) {
- range = TransformationRange(start, end)
+ range = TransformationRange(start, end, easing)
builder()
range = null
}
@@ -251,6 +253,7 @@
override fun timestampRange(
startMillis: Int?,
endMillis: Int?,
+ easing: Easing,
builder: PropertyTransformationBuilder.() -> Unit
) {
if (startMillis != null && (startMillis < 0 || startMillis > durationMillis)) {
@@ -263,7 +266,7 @@
val start = startMillis?.let { it.toFloat() / durationMillis }
val end = endMillis?.let { it.toFloat() / durationMillis }
- fractionRange(start, end, builder)
+ fractionRange(start, end, easing, builder)
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
index 77ec891..eda8ede 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
@@ -16,6 +16,8 @@
package com.android.compose.animation.scene.transformation
+import androidx.compose.animation.core.Easing
+import androidx.compose.animation.core.LinearEasing
import androidx.compose.ui.util.fastCoerceAtLeast
import androidx.compose.ui.util.fastCoerceAtMost
import androidx.compose.ui.util.fastCoerceIn
@@ -90,11 +92,13 @@
data class TransformationRange(
val start: Float,
val end: Float,
+ val easing: Easing,
) {
constructor(
start: Float? = null,
- end: Float? = null
- ) : this(start ?: BoundUnspecified, end ?: BoundUnspecified)
+ end: Float? = null,
+ easing: Easing = LinearEasing,
+ ) : this(start ?: BoundUnspecified, end ?: BoundUnspecified, easing)
init {
require(!start.isSpecified() || (start in 0f..1f))
@@ -103,17 +107,20 @@
}
/** Reverse this range. */
- fun reversed() = TransformationRange(start = reverseBound(end), end = reverseBound(start))
+ fun reversed() =
+ TransformationRange(start = reverseBound(end), end = reverseBound(start), easing = easing)
/** Get the progress of this range given the global [transitionProgress]. */
fun progress(transitionProgress: Float): Float {
- return when {
- start.isSpecified() && end.isSpecified() ->
- ((transitionProgress - start) / (end - start)).fastCoerceIn(0f, 1f)
- !start.isSpecified() && !end.isSpecified() -> transitionProgress
- end.isSpecified() -> (transitionProgress / end).fastCoerceAtMost(1f)
- else -> ((transitionProgress - start) / (1f - start)).fastCoerceAtLeast(0f)
- }
+ val progress =
+ when {
+ start.isSpecified() && end.isSpecified() ->
+ ((transitionProgress - start) / (end - start)).fastCoerceIn(0f, 1f)
+ !start.isSpecified() && !end.isSpecified() -> transitionProgress
+ end.isSpecified() -> (transitionProgress / end).fastCoerceAtMost(1f)
+ else -> ((transitionProgress - start) / (1f - start)).fastCoerceAtLeast(0f)
+ }
+ return easing.transform(progress)
}
private fun Float.isSpecified() = this != BoundUnspecified
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
index 68240b5..bed6cef 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -16,6 +16,7 @@
package com.android.compose.animation.scene
+import androidx.compose.animation.core.CubicBezierEasing
import androidx.compose.animation.core.SpringSpec
import androidx.compose.animation.core.TweenSpec
import androidx.compose.animation.core.spring
@@ -107,6 +108,13 @@
fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) }
fractionRange(start = 0.2f) { fade(TestElements.Foo) }
fractionRange(end = 0.9f) { fade(TestElements.Foo) }
+ fractionRange(
+ start = 0.1f,
+ end = 0.8f,
+ easing = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+ ) {
+ fade(TestElements.Foo)
+ }
}
}
@@ -118,6 +126,11 @@
TransformationRange(start = 0.1f, end = 0.8f),
TransformationRange(start = 0.2f, end = TransformationRange.BoundUnspecified),
TransformationRange(start = TransformationRange.BoundUnspecified, end = 0.9f),
+ TransformationRange(
+ start = 0.1f,
+ end = 0.8f,
+ CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+ ),
)
}
@@ -130,6 +143,13 @@
timestampRange(startMillis = 100, endMillis = 300) { fade(TestElements.Foo) }
timestampRange(startMillis = 200) { fade(TestElements.Foo) }
timestampRange(endMillis = 400) { fade(TestElements.Foo) }
+ timestampRange(
+ startMillis = 100,
+ endMillis = 300,
+ easing = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+ ) {
+ fade(TestElements.Foo)
+ }
}
}
@@ -141,6 +161,11 @@
TransformationRange(start = 100 / 500f, end = 300 / 500f),
TransformationRange(start = 200 / 500f, end = TransformationRange.BoundUnspecified),
TransformationRange(start = TransformationRange.BoundUnspecified, end = 400 / 500f),
+ TransformationRange(
+ start = 100 / 500f,
+ end = 300 / 500f,
+ easing = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+ ),
)
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/EasingTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/EasingTest.kt
new file mode 100644
index 0000000..07901f2
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/EasingTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 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.compose.animation.scene.transformation
+
+import androidx.compose.animation.core.CubicBezierEasing
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.TestElements
+import com.android.compose.animation.scene.testTransition
+import com.android.compose.test.assertSizeIsEqualTo
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class EasingTest {
+ @get:Rule val rule = createComposeRule()
+
+ @Test
+ fun testFractionRangeEasing() {
+ val easing = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+ rule.testTransition(
+ fromSceneContent = { Box(Modifier.size(100.dp).element(TestElements.Foo)) },
+ toSceneContent = { Box(Modifier.size(100.dp).element(TestElements.Bar)) },
+ transition = {
+ // Scale during 4 frames.
+ spec = tween(16 * 4, easing = LinearEasing)
+ fractionRange(easing = easing) {
+ scaleSize(TestElements.Foo, width = 0f, height = 0f)
+ scaleSize(TestElements.Bar, width = 0f, height = 0f)
+ }
+ },
+ ) {
+ // Foo is entering, is 100dp x 100dp at rest and is scaled by (2, 0.5) during the
+ // transition so it starts at 200dp x 50dp.
+ before { onElement(TestElements.Bar).assertDoesNotExist() }
+ at(0) {
+ onElement(TestElements.Foo).assertSizeIsEqualTo(100.dp, 100.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(0.dp, 0.dp)
+ }
+ at(16) {
+ // 25% linear progress is mapped to 68.5% eased progress
+ onElement(TestElements.Foo).assertSizeIsEqualTo(31.5.dp, 31.5.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(68.5.dp, 68.5.dp)
+ }
+ at(32) {
+ // 50% linear progress is mapped to 89.5% eased progress
+ onElement(TestElements.Foo).assertSizeIsEqualTo(10.5.dp, 10.5.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(89.5.dp, 89.5.dp)
+ }
+ at(48) {
+ // 75% linear progress is mapped to 97.8% eased progress
+ onElement(TestElements.Foo).assertSizeIsEqualTo(2.2.dp, 2.2.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(97.8.dp, 97.8.dp)
+ }
+ after {
+ onElement(TestElements.Foo).assertDoesNotExist()
+ onElement(TestElements.Bar).assertSizeIsEqualTo(100.dp, 100.dp)
+ }
+ }
+ }
+
+ @Test
+ fun testTimestampRangeEasing() {
+ val easing = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+ rule.testTransition(
+ fromSceneContent = { Box(Modifier.size(100.dp).element(TestElements.Foo)) },
+ toSceneContent = { Box(Modifier.size(100.dp).element(TestElements.Bar)) },
+ transition = {
+ // Scale during 4 frames.
+ spec = tween(16 * 4, easing = LinearEasing)
+ timestampRange(easing = easing) {
+ scaleSize(TestElements.Foo, width = 0f, height = 0f)
+ scaleSize(TestElements.Bar, width = 0f, height = 0f)
+ }
+ },
+ ) {
+ // Foo is entering, is 100dp x 100dp at rest and is scaled by (2, 0.5) during the
+ // transition so it starts at 200dp x 50dp.
+ before { onElement(TestElements.Bar).assertDoesNotExist() }
+ at(0) {
+ onElement(TestElements.Foo).assertSizeIsEqualTo(100.dp, 100.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(0.dp, 0.dp)
+ }
+ at(16) {
+ // 25% linear progress is mapped to 68.5% eased progress
+ onElement(TestElements.Foo).assertSizeIsEqualTo(31.5.dp, 31.5.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(68.5.dp, 68.5.dp)
+ }
+ at(32) {
+ // 50% linear progress is mapped to 89.5% eased progress
+ onElement(TestElements.Foo).assertSizeIsEqualTo(10.5.dp, 10.5.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(89.5.dp, 89.5.dp)
+ }
+ at(48) {
+ // 75% linear progress is mapped to 97.8% eased progress
+ onElement(TestElements.Foo).assertSizeIsEqualTo(2.2.dp, 2.2.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(97.8.dp, 97.8.dp)
+ }
+ after {
+ onElement(TestElements.Foo).assertDoesNotExist()
+ onElement(TestElements.Bar).assertSizeIsEqualTo(100.dp, 100.dp)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 0242c2d..e57a4cb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -1039,6 +1039,22 @@
assertThat(showCommunalFromOccluded).isTrue()
}
+ @Test
+ fun showCommunalFromOccluded_enteredOccludedFromDreaming() =
+ testScope.runTest {
+ kosmos.setCommunalAvailable(true)
+ val showCommunalFromOccluded by collectLastValue(underTest.showCommunalFromOccluded)
+ assertThat(showCommunalFromOccluded).isFalse()
+
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.DREAMING,
+ to = KeyguardState.OCCLUDED,
+ testScope
+ )
+
+ assertThat(showCommunalFromOccluded).isTrue()
+ }
+
private fun smartspaceTimer(id: String, timestamp: Long = 0L): CommunalSmartspaceTimer {
return CommunalSmartspaceTimer(
smartspaceTargetId = id,
diff --git a/packages/SystemUI/res/layout/media_projection_app_selector.xml b/packages/SystemUI/res/layout/media_projection_app_selector.xml
index b77f78d..3b6a64f 100644
--- a/packages/SystemUI/res/layout/media_projection_app_selector.xml
+++ b/packages/SystemUI/res/layout/media_projection_app_selector.xml
@@ -37,6 +37,7 @@
android:background="@*android:drawable/bottomsheet_background">
<ImageView
+ android:id="@+id/media_projection_app_selector_icon"
android:layout_width="@dimen/media_projection_app_selector_icon_size"
android:layout_height="@dimen/media_projection_app_selector_icon_size"
android:layout_marginTop="@*android:dimen/chooser_edge_margin_normal"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 2ad6b6a..f8303ea 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -291,6 +291,8 @@
<string name="screenrecord_permission_dialog_warning_single_app">When you’re recording an app, anything shown or played in that app is recorded. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
<!-- Button to start a screen recording of the entire screen in the updated screen record dialog that allows to select an app to record [CHAR LIMIT=50]-->
<string name="screenrecord_permission_dialog_continue_entire_screen">Record screen</string>
+ <!-- Title of the activity that allows to select an app to screen record [CHAR LIMIT=70] -->
+ <string name="screenrecord_app_selector_title">Choose app to record</string>
<!-- Label for a switch to enable recording audio [CHAR LIMIT=NONE]-->
<string name="screenrecord_audio_label">Record audio</string>
@@ -1362,8 +1364,8 @@
<!-- Media projection permission dialog warning text for system services. [CHAR LIMIT=NONE] -->
<string name="media_projection_sys_service_dialog_warning">The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string>
- <!-- Title of the dialog that allows to select an app to share or record [CHAR LIMIT=NONE] -->
- <string name="screen_share_permission_app_selector_title">Share or record an app</string>
+ <!-- Title of the activity that allows users to select an app to share or record [CHAR LIMIT=NONE] -->
+ <string name="screen_share_generic_app_selector_title">Share or record an app</string>
<!-- Media projection that launched from 1P/3P apps -->
<!-- 1P/3P app media projection permission dialog title. [CHAR LIMIT=NONE] -->
@@ -1381,6 +1383,8 @@
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen">Share screen</string>
<!-- 1P/3P apps disabled the single app projection option. [CHAR LIMIT=NONE] -->
<string name="media_projection_entry_app_permission_dialog_single_app_disabled"><xliff:g id="app_name" example="Meet">%1$s</xliff:g> has disabled this option</string>
+ <!-- Title of the activity that allows users to select an app to share to a 1P/3P app [CHAR LIMIT=70] -->
+ <string name="media_projection_entry_share_app_selector_title">Choose app to share</string>
<!-- Casting that launched by SysUI (i.e. when there is no app name) -->
<!-- System casting media projection permission dialog title. [CHAR LIMIT=100] -->
@@ -1395,6 +1399,8 @@
<string name="media_projection_entry_cast_permission_dialog_warning_single_app">When you’re casting an app, anything shown or played in that app is visible. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
<!-- System casting media projection permission button to continue for SysUI casting. [CHAR LIMIT=60] -->
<string name="media_projection_entry_cast_permission_dialog_continue_entire_screen">Cast screen</string>
+ <!-- Title of the activity that allows users to select an app to cast [CHAR LIMIT=70] -->
+ <string name="media_projection_entry_cast_app_selector_title">Choose app to cast</string>
<!-- Other sharing (not recording nor casting) that launched by SysUI (currently not in use) -->
<!-- System sharing media projection permission dialog title. [CHAR LIMIT=100] -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
index 68d2eb3..41ad437 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -26,6 +26,7 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
@@ -105,8 +106,8 @@
* @return updated set of flags from InputMethodService based off {@param oldHints}
* Leaves original hints unmodified
*/
- public static int calculateBackDispositionHints(int oldHints, int backDisposition,
- boolean imeShown, boolean showImeSwitcher) {
+ public static int calculateBackDispositionHints(int oldHints,
+ @BackDispositionMode int backDisposition, boolean imeShown, boolean showImeSwitcher) {
int hints = oldHints;
switch (backDisposition) {
case InputMethodService.BACK_DISPOSITION_DEFAULT:
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 6aaaf3d..fbeb715 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -184,7 +184,11 @@
keyguardTransitionInteractor.startedKeyguardTransitionStep
.filter { step -> step.to == KeyguardState.OCCLUDED }
.combine(isCommunalAvailable, ::Pair)
- .map { (step, available) -> available && step.from == KeyguardState.GLANCEABLE_HUB }
+ .map { (step, available) ->
+ available &&
+ (step.from == KeyguardState.GLANCEABLE_HUB ||
+ step.from == KeyguardState.DREAMING)
+ }
.flowOn(bgDispatcher)
.stateIn(
scope = applicationScope,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/OWNERS b/packages/SystemUI/src/com/android/systemui/keyguard/OWNERS
new file mode 100644
index 0000000..443e9876
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/OWNERS
@@ -0,0 +1,11 @@
+set noparent
+
+# Bug component: 78010
+
+amiko@google.com
+beverlyt@google.com
+bhinegardner@google.com
+chandruis@google.com
+jglazier@google.com
+mpietal@google.com
+tsuji@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
index d6affd2..228b576 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
@@ -32,6 +32,10 @@
import android.view.View
import android.view.ViewGroup
import android.view.accessibility.AccessibilityEvent
+import android.widget.ImageView
+import androidx.annotation.ColorRes
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
@@ -52,6 +56,7 @@
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.AsyncActivityLauncher
+import java.lang.IllegalArgumentException
import javax.inject.Inject
class MediaProjectionAppSelectorActivity(
@@ -116,6 +121,7 @@
super.onCreate(savedInstanceState)
controller.init()
+ setIcon()
// we override AppList's AccessibilityDelegate set in ResolverActivity.onCreate because in
// our case this delegate must extend RecyclerViewAccessibilityDelegate, otherwise
// RecyclerView scrolling is broken
@@ -298,6 +304,29 @@
override fun createContentPreviewView(parent: ViewGroup): ViewGroup =
recentsViewController.createView(parent)
+ /** Set up intent for the [ChooserActivity] */
+ private fun Intent.configureChooserIntent(
+ resources: Resources,
+ hostUserHandle: UserHandle,
+ personalProfileUserHandle: UserHandle,
+ ) {
+ // Specify the query intent to show icons for all apps on the chooser screen
+ val queryIntent = Intent(Intent.ACTION_MAIN).apply { addCategory(Intent.CATEGORY_LAUNCHER) }
+ putExtra(Intent.EXTRA_INTENT, queryIntent)
+
+ // Update the title of the chooser
+ putExtra(Intent.EXTRA_TITLE, resources.getString(titleResId))
+
+ // Select host app's profile tab by default
+ val selectedProfile =
+ if (hostUserHandle == personalProfileUserHandle) {
+ PROFILE_PERSONAL
+ } else {
+ PROFILE_WORK
+ }
+ putExtra(EXTRA_SELECTED_PROFILE, selectedProfile)
+ }
+
private val hostUserHandle: UserHandle
get() {
val extras =
@@ -321,6 +350,54 @@
return intent.getIntExtra(EXTRA_HOST_APP_UID, /* defaultValue= */ -1)
}
+ /**
+ * The type of screen sharing being performed. Used to show the right text and icon in the
+ * activity.
+ */
+ private val screenShareType: ScreenShareType?
+ get() {
+ if (!intent.hasExtra(EXTRA_SCREEN_SHARE_TYPE)) {
+ return null
+ } else {
+ val type = intent.getStringExtra(EXTRA_SCREEN_SHARE_TYPE) ?: return null
+ return try {
+ enumValueOf<ScreenShareType>(type)
+ } catch (e: IllegalArgumentException) {
+ null
+ }
+ }
+ }
+
+ @get:StringRes
+ private val titleResId: Int
+ get() =
+ when (screenShareType) {
+ ScreenShareType.ShareToApp ->
+ R.string.media_projection_entry_share_app_selector_title
+ ScreenShareType.SystemCast ->
+ R.string.media_projection_entry_cast_app_selector_title
+ ScreenShareType.ScreenRecord -> R.string.screenrecord_app_selector_title
+ null -> R.string.screen_share_generic_app_selector_title
+ }
+
+ @get:DrawableRes
+ private val iconResId: Int
+ get() =
+ when (screenShareType) {
+ ScreenShareType.ShareToApp -> R.drawable.ic_present_to_all
+ ScreenShareType.SystemCast -> R.drawable.ic_cast_connected
+ ScreenShareType.ScreenRecord -> R.drawable.ic_screenrecord
+ null -> R.drawable.ic_present_to_all
+ }
+
+ @get:ColorRes
+ private val iconTintResId: Int?
+ get() =
+ when (screenShareType) {
+ ScreenShareType.ScreenRecord -> R.color.screenrecord_icon_color
+ else -> null
+ }
+
companion object {
const val TAG = "MediaProjectionAppSelectorActivity"
@@ -343,30 +420,18 @@
const val EXTRA_HOST_APP_UID = "launched_from_host_uid"
const val KEY_CAPTURE_TARGET = "capture_region"
- /** Set up intent for the [ChooserActivity] */
- private fun Intent.configureChooserIntent(
- resources: Resources,
- hostUserHandle: UserHandle,
- personalProfileUserHandle: UserHandle
- ) {
- // Specify the query intent to show icons for all apps on the chooser screen
- val queryIntent =
- Intent(Intent.ACTION_MAIN).apply { addCategory(Intent.CATEGORY_LAUNCHER) }
- putExtra(Intent.EXTRA_INTENT, queryIntent)
+ /**
+ * The type of screen sharing being performed.
+ *
+ * The value set for this extra should match the name of a [ScreenShareType].
+ */
+ const val EXTRA_SCREEN_SHARE_TYPE = "screen_share_type"
+ }
- // Update the title of the chooser
- val title = resources.getString(R.string.screen_share_permission_app_selector_title)
- putExtra(Intent.EXTRA_TITLE, title)
-
- // Select host app's profile tab by default
- val selectedProfile =
- if (hostUserHandle == personalProfileUserHandle) {
- PROFILE_PERSONAL
- } else {
- PROFILE_WORK
- }
- putExtra(EXTRA_SELECTED_PROFILE, selectedProfile)
- }
+ private fun setIcon() {
+ val iconView = findViewById<ImageView>(R.id.media_projection_app_selector_icon) ?: return
+ iconView.setImageResource(iconResId)
+ iconTintResId?.let { iconView.setColorFilter(this.resources.getColor(it, this.theme)) }
}
private fun setAppListAccessibilityDelegate() {
@@ -406,4 +471,14 @@
return delegate.onRequestSendAccessibilityEvent(host, child, event)
}
}
+
+ /** Enum describing what type of app screen sharing is being performed. */
+ enum class ScreenShareType {
+ /** The selected app will be cast to another device. */
+ SystemCast,
+ /** The selected app will be shared to another app on the device. */
+ ShareToApp,
+ /** The selected app will be recorded. */
+ ScreenRecord,
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 3c83db3..18c6f53 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -73,8 +73,7 @@
import dagger.Lazy;
-public class MediaProjectionPermissionActivity extends Activity
- implements DialogInterface.OnClickListener {
+public class MediaProjectionPermissionActivity extends Activity {
private static final String TAG = "MediaProjectionPermissionActivity";
private static final float MAX_APP_NAME_SIZE_PX = 500f;
private static final String ELLIPSIS = "\u2026";
@@ -269,7 +268,8 @@
Consumer<BaseMediaProjectionPermissionDialogDelegate<AlertDialog>> onStartRecordingClicked =
dialog -> {
ScreenShareOption selectedOption = dialog.getSelectedScreenShareOption();
- grantMediaProjectionPermission(selectedOption.getMode());
+ grantMediaProjectionPermission(
+ selectedOption.getMode(), hasCastingCapabilities);
};
Runnable onCancelClicked = () -> finish(RECORD_CANCEL, /* projection= */ null);
if (hasCastingCapabilities) {
@@ -305,19 +305,6 @@
}
}
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (which == AlertDialog.BUTTON_POSITIVE) {
- grantMediaProjectionPermission(ENTIRE_SCREEN);
- } else {
- if (mDialog != null) {
- mDialog.dismiss();
- }
- setResult(RESULT_CANCELED);
- finish(RECORD_CANCEL, /* projection= */ null);
- }
- }
-
private void setUpDialog(AlertDialog dialog) {
SystemUIDialog.registerDismissListener(dialog);
SystemUIDialog.applyFlags(dialog);
@@ -345,25 +332,21 @@
return false;
}
- private void grantMediaProjectionPermission(int screenShareMode) {
+ private void grantMediaProjectionPermission(
+ int screenShareMode, boolean hasCastingCapabilities) {
try {
+ IMediaProjection projection = MediaProjectionServiceHelper.createOrReuseProjection(
+ mUid, mPackageName, mReviewGrantedConsentRequired);
if (screenShareMode == ENTIRE_SCREEN) {
- final IMediaProjection projection =
- MediaProjectionServiceHelper.createOrReuseProjection(mUid, mPackageName,
- mReviewGrantedConsentRequired);
final Intent intent = new Intent();
- intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
- projection.asBinder());
+ setCommonIntentExtras(intent, hasCastingCapabilities, projection);
setResult(RESULT_OK, intent);
finish(RECORD_CONTENT_DISPLAY, projection);
}
if (screenShareMode == SINGLE_APP) {
- IMediaProjection projection = MediaProjectionServiceHelper.createOrReuseProjection(
- mUid, mPackageName, mReviewGrantedConsentRequired);
final Intent intent = new Intent(this,
MediaProjectionAppSelectorActivity.class);
- intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
- projection.asBinder());
+ setCommonIntentExtras(intent, hasCastingCapabilities, projection);
intent.putExtra(MediaProjectionAppSelectorActivity.EXTRA_HOST_APP_USER_HANDLE,
getHostUserHandle());
intent.putExtra(
@@ -391,6 +374,19 @@
}
}
+ private void setCommonIntentExtras(
+ Intent intent,
+ boolean hasCastingCapabilities,
+ IMediaProjection projection) throws RemoteException {
+ intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
+ projection.asBinder());
+ intent.putExtra(
+ MediaProjectionAppSelectorActivity.EXTRA_SCREEN_SHARE_TYPE,
+ hasCastingCapabilities
+ ? MediaProjectionAppSelectorActivity.ScreenShareType.SystemCast.name()
+ : MediaProjectionAppSelectorActivity.ScreenShareType.ShareToApp.name());
+ }
+
private UserHandle getHostUserHandle() {
return UserHandle.getUserHandleForUid(getLaunchedFromUid());
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index 13a786a..ac878c2 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -38,6 +38,7 @@
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -516,7 +517,7 @@
* @return Whether the IME is shown on top of the screen given the {@code vis} flag of
* {@link InputMethodService} and the keyguard states.
*/
- public boolean isImeShown(int vis) {
+ public boolean isImeShown(@ImeWindowVisibility int vis) {
View shadeWindowView = mNotificationShadeWindowController.getWindowRootView();
boolean isKeyguardShowing = mKeyguardStateController.isShowing();
boolean imeVisibleOnShade = shadeWindowView != null && shadeWindowView.isAttachedToWindow()
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 15b1e4d..cb0bb4a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -42,6 +42,8 @@
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
@@ -424,8 +426,8 @@
}
@Override
- public void setImeWindowStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
boolean imeShown = mNavBarHelper.isImeShown(vis);
if (!imeShown) {
// Count imperceptible changes as visible so we transition taskbar out quickly.
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
index e895d83..c706c3e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
@@ -68,6 +68,8 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -1098,8 +1100,8 @@
// ----- CommandQueue Callbacks -----
@Override
- public void setImeWindowStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
if (displayId != mDisplayId) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 9939075..1511f31 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -259,6 +259,13 @@
}
/**
+ * @return height with the squishiness fraction applied.
+ */
+ int getSquishedQqsHeight() {
+ return mHeader.getSquishedHeight();
+ }
+
+ /**
* Returns the size of QS (or the QSCustomizer), regardless of the measured size of this view
* @return size in pixels of QS (or QSCustomizer)
*/
@@ -267,6 +274,13 @@
: mQSPanel.getMeasuredHeight();
}
+ /**
+ * @return height with the squishiness fraction applied.
+ */
+ int getSquishedQsHeight() {
+ return mQSPanel.getSquishedHeight();
+ }
+
public void setExpansion(float expansion) {
mQsExpansion = expansion;
if (mQSPanelContainer != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
index a6fd35a..0b37b5b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
@@ -992,11 +992,25 @@
return mContainer.getQqsHeight();
}
+ /**
+ * @return height with the squishiness fraction applied.
+ */
+ public int getSquishedQqsHeight() {
+ return mContainer.getSquishedQqsHeight();
+ }
+
public int getQSHeight() {
return mContainer.getQsHeight();
}
/**
+ * @return height with the squishiness fraction applied.
+ */
+ public int getSquishedQsHeight() {
+ return mContainer.getSquishedQsHeight();
+ }
+
+ /**
* Pass the size of the navbar when it's at the bottom of the device so it can be used as
* padding
* @param padding size of the bottom nav bar in px
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 032891f..d3bed27 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -733,6 +733,30 @@
mCanCollapse = canCollapse;
}
+ /**
+ * @return height with the {@link QSPanel#setSquishinessFraction(float)} applied.
+ */
+ public int getSquishedHeight() {
+ if (mFooter != null) {
+ final ViewGroup.LayoutParams footerLayoutParams = mFooter.getLayoutParams();
+ final int footerBottomMargin;
+ if (footerLayoutParams instanceof MarginLayoutParams) {
+ footerBottomMargin = ((MarginLayoutParams) footerLayoutParams).bottomMargin;
+ } else {
+ footerBottomMargin = 0;
+ }
+ // This is the distance between the top of the QSPanel and the last view in the
+ // layout (which is the effective the bottom)
+ return mFooter.getBottom() + footerBottomMargin - getTop();
+ }
+ if (mTileLayout != null) {
+ // Footer absence means that the panel is in the QQS. In this case it's just height
+ // of the tiles + paddings.
+ return mTileLayout.getTilesHeight() + getPaddingBottom() + getPaddingTop();
+ }
+ return getHeight();
+ }
+
@Nullable
@VisibleForTesting
View getMediaPlaceholder() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 5a3f1c0..8fde52c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -123,4 +123,11 @@
lp.setMarginEnd(marginEnd);
view.setLayoutParams(lp);
}
+
+ /**
+ * @return height with the squishiness fraction applied.
+ */
+ public int getSquishedHeight() {
+ return mHeaderQsPanel.getSquishedHeight();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
index ae2f32a..dfcf216 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
@@ -34,7 +34,6 @@
import com.android.systemui.qs.QSContainerImpl
import com.android.systemui.qs.QSImpl
import com.android.systemui.qs.dagger.QSSceneComponent
-import com.android.systemui.qs.tiles.viewmodel.StubQSTileViewModel.state
import com.android.systemui.res.R
import com.android.systemui.settings.brightness.MirrorController
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -126,12 +125,18 @@
/** The current height of QQS in the current [qsView], or 0 if there's no view. */
val qqsHeight: Int
+ /** @return height with the squishiness fraction applied. */
+ val squishedQqsHeight: Int
+
/**
* The current height of QS in the current [qsView], or 0 if there's no view. If customizing, it
* will return the height allocated to the customizer.
*/
val qsHeight: Int
+ /** @return height with the squishiness fraction applied. */
+ val squishedQsHeight: Int
+
/** Compatibility for use by LockscreenShadeTransitionController. Matches default from [QS] */
val isQsFullyCollapsed: Boolean
get() = true
@@ -273,9 +278,15 @@
override val qqsHeight: Int
get() = qsImpl.value?.qqsHeight ?: 0
+ override val squishedQqsHeight: Int
+ get() = qsImpl.value?.squishedQqsHeight ?: 0
+
override val qsHeight: Int
get() = qsImpl.value?.qsHeight ?: 0
+ override val squishedQsHeight: Int
+ get() = qsImpl.value?.squishedQsHeight ?: 0
+
// If value is null, there's no QS and therefore it's fully collapsed.
override val isQsFullyCollapsed: Boolean
get() = qsImpl.value?.isFullyCollapsed ?: true
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
index 46ac54f..f3357ee 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
@@ -146,6 +146,10 @@
hostUserHandle
)
intent.putExtra(MediaProjectionAppSelectorActivity.EXTRA_HOST_APP_UID, hostUid)
+ intent.putExtra(
+ MediaProjectionAppSelectorActivity.EXTRA_SCREEN_SHARE_TYPE,
+ MediaProjectionAppSelectorActivity.ScreenShareType.ScreenRecord.name,
+ )
activityStarter.startActivity(intent, /* dismissShade= */ true)
}
dialog.dismiss()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 50be6dc..a1477b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -37,6 +37,7 @@
import android.hardware.biometrics.PromptInfo;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.media.INearbyMediaDevicesProvider;
import android.media.MediaRoute2Info;
import android.os.Binder;
@@ -257,10 +258,10 @@
*
* @param displayId The id of the display to notify.
* @param vis IME visibility.
- * @param backDisposition Disposition mode of back button. It should be one of below flags:
+ * @param backDisposition Disposition mode of back button.
* @param showImeSwitcher {@code true} to show IME switch button.
*/
- default void setImeWindowStatus(int displayId, int vis,
+ default void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
@BackDispositionMode int backDisposition, boolean showImeSwitcher) { }
default void showRecentApps(boolean triggeredFromAltTab) { }
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
@@ -743,8 +744,8 @@
}
@Override
- public void setImeWindowStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
synchronized (mLock) {
mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
SomeArgs args = SomeArgs.obtain();
@@ -1205,8 +1206,8 @@
}
}
- private void handleShowImeButton(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ private void handleShowImeButton(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
if (displayId == INVALID_DISPLAY) return;
boolean isConcurrentMultiUserModeEnabled = UserManager.isVisibleBackgroundUsersEnabled()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
index 69ebb76..c4f539a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
@@ -5,3 +5,12 @@
caitlinshk@google.com
evanlaird@google.com
pixel@google.com
+
+per-file *Biometrics* = set noparent
+per-file *Biometrics* = file:../keyguard/OWNERS
+per-file *Doze* = set noparent
+per-file *Doze* = file:../keyguard/OWNERS
+per-file *Keyboard* = set noparent
+per-file *Keyboard* = file:../keyguard/OWNERS
+per-file *Keyguard* = set noparent
+per-file *Keyguard* = file:../keyguard/OWNERS
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 9ca0591..50efc21 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -34,6 +34,8 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
@@ -378,8 +380,8 @@
}
@Override
- public void setImeWindowStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
if (displayId == mDisplayTracker.getDefaultDisplayId()
&& (vis & InputMethodService.IME_VISIBLE) != 0) {
oneHanded.stopOneHanded(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 6916bbd..d10ea1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -15,7 +15,9 @@
package com.android.systemui.statusbar;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
+import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
+import static android.inputmethodservice.InputMethodService.IME_ACTIVE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
@@ -194,9 +196,11 @@
@Test
public void testShowImeButton() {
- mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, 1, 2, true);
+ mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, IME_ACTIVE,
+ BACK_DISPOSITION_ADJUST_NOTHING, true);
waitForIdleSync();
- verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(1), eq(2), eq(true));
+ verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(IME_ACTIVE),
+ eq(BACK_DISPOSITION_ADJUST_NOTHING), eq(true));
}
@Test
@@ -204,11 +208,13 @@
// First show in default display to update the "last updated ime display"
testShowImeButton();
- mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, 1, 2, true);
+ mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, IME_ACTIVE,
+ BACK_DISPOSITION_ADJUST_NOTHING, true);
waitForIdleSync();
- verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(0),
+ verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(0) /* vis */,
eq(BACK_DISPOSITION_DEFAULT), eq(false));
- verify(mCallbacks).setImeWindowStatus(eq(SECONDARY_DISPLAY), eq(1), eq(2), eq(true));
+ verify(mCallbacks).setImeWindowStatus(eq(SECONDARY_DISPLAY), eq(IME_ACTIVE),
+ eq(BACK_DISPOSITION_ADJUST_NOTHING), eq(true));
}
@Test
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt
index b6194e3..bbe753e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt
@@ -27,7 +27,9 @@
class FakeQSSceneAdapter(
private val inflateDelegate: suspend (Context) -> View,
override val qqsHeight: Int = 0,
+ override val squishedQqsHeight: Int = 0,
override val qsHeight: Int = 0,
+ override val squishedQsHeight: Int = 0,
) : QSSceneAdapter {
private val _customizerState = MutableStateFlow<CustomizerState>(CustomizerState.Hidden)
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 079b724..ec1993a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -18,6 +18,7 @@
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
import static android.content.Context.DEVICE_ID_DEFAULT;
+import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.INVALID_DISPLAY;
@@ -32,6 +33,8 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManagerInternal;
import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
@@ -99,24 +102,16 @@
/**
* A set of status bits regarding the active IME.
*
- * <p>This value is a combination of following two bits:</p>
- * <dl>
- * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
- * <dd>
- * If this bit is ON, connected IME is ready to accept touch/key events.
- * </dd>
- * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
- * <dd>
- * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
- * </dd>
- * </dl>
- * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
- * {@link InputMethodBindingController#unbindCurrentMethod()}.</em>
+ * <em>Do not update this value outside of {@link #setImeWindowVis} and
+ * {@link InputMethodBindingController#unbindCurrentMethod}.</em>
*/
- @GuardedBy("ImfLock.class") private int mImeWindowVis;
-
+ @ImeWindowVisibility
@GuardedBy("ImfLock.class")
- private int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
+ private int mImeWindowVis;
+
+ @BackDispositionMode
+ @GuardedBy("ImfLock.class")
+ private int mBackDisposition = BACK_DISPOSITION_DEFAULT;
@Nullable private CountDownLatch mLatchForTesting;
@@ -718,22 +713,24 @@
}
@GuardedBy("ImfLock.class")
- void setImeWindowVis(int imeWindowVis) {
+ void setImeWindowVis(@ImeWindowVisibility int imeWindowVis) {
mImeWindowVis = imeWindowVis;
}
+ @ImeWindowVisibility
@GuardedBy("ImfLock.class")
int getImeWindowVis() {
return mImeWindowVis;
}
+ @BackDispositionMode
@GuardedBy("ImfLock.class")
int getBackDisposition() {
return mBackDisposition;
}
@GuardedBy("ImfLock.class")
- void setBackDisposition(int backDisposition) {
+ void setBackDisposition(@BackDispositionMode int backDisposition) {
mBackDisposition = backDisposition;
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 8afbd56..3654283 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -86,6 +86,8 @@
import android.content.res.Resources;
import android.hardware.input.InputManager;
import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.media.AudioManagerInternal;
import android.net.Uri;
import android.os.Binder;
@@ -2618,7 +2620,8 @@
}
@GuardedBy("ImfLock.class")
- private boolean shouldShowImeSwitcherLocked(int visibility, @UserIdInt int userId) {
+ private boolean shouldShowImeSwitcherLocked(@ImeWindowVisibility int visibility,
+ @UserIdInt int userId) {
if (!mShowOngoingImeSwitcherForPhones) return false;
// When the IME switcher dialog is shown, the IME switcher button should be hidden.
// TODO(b/305849394): Make mMenuController multi-user aware.
@@ -2722,8 +2725,8 @@
@BinderThread
@GuardedBy("ImfLock.class")
@SuppressWarnings("deprecation")
- private void setImeWindowStatusLocked(int vis, int backDisposition,
- @NonNull UserData userData) {
+ private void setImeWindowStatusLocked(@ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, @NonNull UserData userData) {
final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
final int userId = userData.mUserId;
@@ -2772,7 +2775,7 @@
final int userId = resolveImeUserIdFromDisplayIdLocked(displayId);
if (disableImeIcon) {
final var bindingController = getInputMethodBindingController(userId);
- updateSystemUiLocked(0, bindingController.getBackDisposition(), userId);
+ updateSystemUiLocked(0 /* vis */, bindingController.getBackDisposition(), userId);
} else {
updateSystemUiLocked(userId);
}
@@ -2787,7 +2790,8 @@
}
@GuardedBy("ImfLock.class")
- private void updateSystemUiLocked(int vis, int backDisposition, @UserIdInt int userId) {
+ private void updateSystemUiLocked(@ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, @UserIdInt int userId) {
// To minimize app compat risk, ignore background users' request for single-user mode.
// TODO(b/357178609): generalize the logic and remove this special rule.
if (!mConcurrentMultiUserModeEnabled && userId != mCurrentImeUserId) {
@@ -6812,7 +6816,8 @@
@BinderThread
@Override
- public void setImeWindowStatusAsync(int vis, int backDisposition) {
+ public void setImeWindowStatusAsync(@ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition) {
synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(mToken, mUserData)) {
return;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
index c77b768..202543c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -614,242 +614,61 @@
}
}
- @VisibleForTesting
- public static class ControllerImpl {
-
- @NonNull
- private final DynamicRotationList mSwitchingAwareRotationList;
- @NonNull
- private final StaticRotationList mSwitchingUnawareRotationList;
- /** List of input methods and subtypes. */
- @Nullable
- private final RotationList mRotationList;
- /** List of input methods and subtypes suitable for hardware keyboards. */
- @Nullable
- private final RotationList mHardwareRotationList;
-
- /**
- * Whether there was a user action since the last input method and subtype switch.
- * Used to determine the switching behaviour for {@link #MODE_AUTO}.
- */
- private boolean mUserActionSinceSwitch;
-
- @NonNull
- public static ControllerImpl createFrom(@Nullable ControllerImpl currentInstance,
- @NonNull List<ImeSubtypeListItem> sortedEnabledItems,
- @NonNull List<ImeSubtypeListItem> hardwareKeyboardItems) {
- final var switchingAwareImeSubtypes = filterImeSubtypeList(sortedEnabledItems,
- true /* supportsSwitchingToNextInputMethod */);
- final var switchingUnawareImeSubtypes = filterImeSubtypeList(sortedEnabledItems,
- false /* supportsSwitchingToNextInputMethod */);
-
- final DynamicRotationList switchingAwareRotationList;
- if (currentInstance != null && Objects.equals(
- currentInstance.mSwitchingAwareRotationList.mImeSubtypeList,
- switchingAwareImeSubtypes)) {
- // Can reuse the current instance.
- switchingAwareRotationList = currentInstance.mSwitchingAwareRotationList;
- } else {
- switchingAwareRotationList = new DynamicRotationList(switchingAwareImeSubtypes);
- }
-
- final StaticRotationList switchingUnawareRotationList;
- if (currentInstance != null && Objects.equals(
- currentInstance.mSwitchingUnawareRotationList.mImeSubtypeList,
- switchingUnawareImeSubtypes)) {
- // Can reuse the current instance.
- switchingUnawareRotationList = currentInstance.mSwitchingUnawareRotationList;
- } else {
- switchingUnawareRotationList = new StaticRotationList(switchingUnawareImeSubtypes);
- }
-
- final RotationList rotationList;
- if (!Flags.imeSwitcherRevamp()) {
- rotationList = null;
- } else if (currentInstance != null && currentInstance.mRotationList != null
- && Objects.equals(
- currentInstance.mRotationList.mItems, sortedEnabledItems)) {
- // Can reuse the current instance.
- rotationList = currentInstance.mRotationList;
- } else {
- rotationList = new RotationList(sortedEnabledItems);
- }
-
- final RotationList hardwareRotationList;
- if (!Flags.imeSwitcherRevamp()) {
- hardwareRotationList = null;
- } else if (currentInstance != null && currentInstance.mHardwareRotationList != null
- && Objects.equals(
- currentInstance.mHardwareRotationList.mItems, hardwareKeyboardItems)) {
- // Can reuse the current instance.
- hardwareRotationList = currentInstance.mHardwareRotationList;
- } else {
- hardwareRotationList = new RotationList(hardwareKeyboardItems);
- }
-
- return new ControllerImpl(switchingAwareRotationList, switchingUnawareRotationList,
- rotationList, hardwareRotationList);
- }
-
- private ControllerImpl(@NonNull DynamicRotationList switchingAwareRotationList,
- @NonNull StaticRotationList switchingUnawareRotationList,
- @Nullable RotationList rotationList,
- @Nullable RotationList hardwareRotationList) {
- mSwitchingAwareRotationList = switchingAwareRotationList;
- mSwitchingUnawareRotationList = switchingUnawareRotationList;
- mRotationList = rotationList;
- mHardwareRotationList = hardwareRotationList;
- }
-
- @Nullable
- public ImeSubtypeListItem getNextInputMethod(boolean onlyCurrentIme,
- @Nullable InputMethodInfo imi, @Nullable InputMethodSubtype subtype,
- @SwitchMode int mode, boolean forward) {
- if (imi == null) {
- return null;
- }
- if (Flags.imeSwitcherRevamp() && mRotationList != null) {
- return mRotationList.next(imi, subtype, onlyCurrentIme,
- isRecency(mode, forward), forward);
- } else if (imi.supportsSwitchingToNextInputMethod()) {
- return mSwitchingAwareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi,
- subtype);
- } else {
- return mSwitchingUnawareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi,
- subtype);
- }
- }
-
- @Nullable
- public ImeSubtypeListItem getNextInputMethodForHardware(boolean onlyCurrentIme,
- @NonNull InputMethodInfo imi, @Nullable InputMethodSubtype subtype,
- @SwitchMode int mode, boolean forward) {
- if (Flags.imeSwitcherRevamp() && mHardwareRotationList != null) {
- return mHardwareRotationList.next(imi, subtype, onlyCurrentIme,
- isRecency(mode, forward), forward);
- }
- return null;
- }
-
- /**
- * Called when the user took an action that should update the recency of the current
- * input method and subtype in the switching list.
- *
- * @param imi the currently selected input method.
- * @param subtype the currently selected input method subtype, if any.
- * @return {@code true} if the recency was updated, otherwise {@code false}.
- * @see android.inputmethodservice.InputMethodServiceInternal#notifyUserActionIfNecessary()
- */
- public boolean onUserActionLocked(@NonNull InputMethodInfo imi,
- @Nullable InputMethodSubtype subtype) {
- boolean recencyUpdated = false;
- if (Flags.imeSwitcherRevamp()) {
- if (mRotationList != null) {
- recencyUpdated |= mRotationList.setMostRecent(imi, subtype);
- }
- if (mHardwareRotationList != null) {
- recencyUpdated |= mHardwareRotationList.setMostRecent(imi, subtype);
- }
- if (recencyUpdated) {
- mUserActionSinceSwitch = true;
- }
- } else if (imi.supportsSwitchingToNextInputMethod()) {
- mSwitchingAwareRotationList.onUserAction(imi, subtype);
- }
- return recencyUpdated;
- }
-
- /** Called when the input method and subtype was changed. */
- public void onInputMethodSubtypeChanged() {
- mUserActionSinceSwitch = false;
- }
-
- /**
- * Whether the given mode and direction result in recency or static order.
- *
- * <p>{@link #MODE_AUTO} resolves to the recency order for the first forwards switch
- * after an {@link #onUserActionLocked user action}, and otherwise to the static order.</p>
- *
- * @param mode the switching mode.
- * @param forward the switching direction.
- * @return {@code true} for the recency order, otherwise {@code false}.
- */
- private boolean isRecency(@SwitchMode int mode, boolean forward) {
- if (mode == MODE_AUTO && mUserActionSinceSwitch && forward) {
- return true;
- } else {
- return mode == MODE_RECENT;
- }
- }
-
- @NonNull
- private static List<ImeSubtypeListItem> filterImeSubtypeList(
- @NonNull List<ImeSubtypeListItem> items,
- boolean supportsSwitchingToNextInputMethod) {
- final ArrayList<ImeSubtypeListItem> result = new ArrayList<>();
- final int numItems = items.size();
- for (int i = 0; i < numItems; i++) {
- final ImeSubtypeListItem item = items.get(i);
- if (item.mImi.supportsSwitchingToNextInputMethod()
- == supportsSwitchingToNextInputMethod) {
- result.add(item);
- }
- }
- return result;
- }
-
- protected void dump(@NonNull Printer pw, @NonNull String prefix) {
- pw.println(prefix + "mSwitchingAwareRotationList:");
- mSwitchingAwareRotationList.dump(pw, prefix + " ");
- pw.println(prefix + "mSwitchingUnawareRotationList:");
- mSwitchingUnawareRotationList.dump(pw, prefix + " ");
- if (Flags.imeSwitcherRevamp()) {
- if (mRotationList != null) {
- pw.println(prefix + "mRotationList:");
- mRotationList.dump(pw, prefix + " ");
- }
- if (mHardwareRotationList != null) {
- pw.println(prefix + "mHardwareRotationList:");
- mHardwareRotationList.dump(pw, prefix + " ");
- }
- pw.println(prefix + "User action since last switch: " + mUserActionSinceSwitch);
- }
- }
- }
-
@NonNull
- private ControllerImpl mController;
-
- InputMethodSubtypeSwitchingController() {
- mController = ControllerImpl.createFrom(null, Collections.emptyList(),
- Collections.emptyList());
- }
+ private DynamicRotationList mSwitchingAwareRotationList =
+ new DynamicRotationList(Collections.emptyList());
+ @NonNull
+ private StaticRotationList mSwitchingUnawareRotationList =
+ new StaticRotationList(Collections.emptyList());
+ /** List of input methods and subtypes. */
+ @NonNull
+ private RotationList mRotationList = new RotationList(Collections.emptyList());
+ /** List of input methods and subtypes suitable for hardware keyboards. */
+ @NonNull
+ private RotationList mHardwareRotationList = new RotationList(Collections.emptyList());
/**
- * Called when the user took an action that should update the recency of the current
- * input method and subtype in the switching list.
- *
- * @param imi the currently selected input method.
- * @param subtype the currently selected input method subtype, if any.
- * @see android.inputmethodservice.InputMethodServiceInternal#notifyUserActionIfNecessary()
+ * Whether there was a user action since the last input method and subtype switch.
+ * Used to determine the switching behaviour for {@link #MODE_AUTO}.
*/
- public void onUserActionLocked(@NonNull InputMethodInfo imi,
- @Nullable InputMethodSubtype subtype) {
- mController.onUserActionLocked(imi, subtype);
- }
+ private boolean mUserActionSinceSwitch;
- /** Called when the input method and subtype was changed. */
- public void onInputMethodSubtypeChanged() {
- mController.onInputMethodSubtypeChanged();
- }
+ /**
+ * Updates the list of input methods and subtypes used for switching. If the given items are
+ * equal to the existing ones (regardless of recency order), the update is skipped and the
+ * current recency order is kept. Otherwise, the recency order is reset.
+ *
+ * @param sortedEnabledItems the sorted list of enabled input methods and subtypes.
+ * @param hardwareKeyboardItems the unsorted list of enabled input method and subtypes
+ * suitable for hardware keyboards.
+ */
+ @VisibleForTesting
+ void update(@NonNull List<ImeSubtypeListItem> sortedEnabledItems,
+ @NonNull List<ImeSubtypeListItem> hardwareKeyboardItems) {
+ final var switchingAwareImeSubtypes = filterImeSubtypeList(sortedEnabledItems,
+ true /* supportsSwitchingToNextInputMethod */);
+ final var switchingUnawareImeSubtypes = filterImeSubtypeList(sortedEnabledItems,
+ false /* supportsSwitchingToNextInputMethod */);
- public void resetCircularListLocked(@NonNull Context context,
- @NonNull InputMethodSettings settings) {
- mController = ControllerImpl.createFrom(mController,
- getSortedInputMethodAndSubtypeList(
- false /* includeAuxiliarySubtypes */, false /* isScreenLocked */,
- false /* forImeMenu */, context, settings),
- getInputMethodAndSubtypeListForHardwareKeyboard(context, settings));
+ if (!Objects.equals(mSwitchingAwareRotationList.mImeSubtypeList,
+ switchingAwareImeSubtypes)) {
+ mSwitchingAwareRotationList = new DynamicRotationList(switchingAwareImeSubtypes);
+ }
+
+ if (!Objects.equals(mSwitchingUnawareRotationList.mImeSubtypeList,
+ switchingUnawareImeSubtypes)) {
+ mSwitchingUnawareRotationList = new StaticRotationList(switchingUnawareImeSubtypes);
+ }
+
+ if (Flags.imeSwitcherRevamp()
+ && !Objects.equals(mRotationList.mItems, sortedEnabledItems)) {
+ mRotationList = new RotationList(sortedEnabledItems);
+ }
+
+ if (Flags.imeSwitcherRevamp()
+ && !Objects.equals(mHardwareRotationList.mItems, hardwareKeyboardItems)) {
+ mHardwareRotationList = new RotationList(hardwareKeyboardItems);
+ }
}
/**
@@ -869,7 +688,19 @@
public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme,
@Nullable InputMethodInfo imi, @Nullable InputMethodSubtype subtype,
@SwitchMode int mode, boolean forward) {
- return mController.getNextInputMethod(onlyCurrentIme, imi, subtype, mode, forward);
+ if (imi == null) {
+ return null;
+ }
+ if (Flags.imeSwitcherRevamp()) {
+ return mRotationList.next(imi, subtype, onlyCurrentIme,
+ isRecency(mode, forward), forward);
+ } else if (imi.supportsSwitchingToNextInputMethod()) {
+ return mSwitchingAwareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi,
+ subtype);
+ } else {
+ return mSwitchingUnawareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi,
+ subtype);
+ }
}
/**
@@ -890,11 +721,98 @@
public ImeSubtypeListItem getNextInputMethodForHardware(boolean onlyCurrentIme,
@NonNull InputMethodInfo imi, @Nullable InputMethodSubtype subtype,
@SwitchMode int mode, boolean forward) {
- return mController.getNextInputMethodForHardware(onlyCurrentIme, imi, subtype, mode,
- forward);
+ if (Flags.imeSwitcherRevamp()) {
+ return mHardwareRotationList.next(imi, subtype, onlyCurrentIme,
+ isRecency(mode, forward), forward);
+ }
+ return null;
}
- public void dump(@NonNull Printer pw, @NonNull String prefix) {
- mController.dump(pw, prefix);
+ /**
+ * Called when the user took an action that should update the recency of the current
+ * input method and subtype in the switching list.
+ *
+ * @param imi the currently selected input method.
+ * @param subtype the currently selected input method subtype, if any.
+ * @return {@code true} if the recency was updated, otherwise {@code false}.
+ * @see android.inputmethodservice.InputMethodServiceInternal#notifyUserActionIfNecessary()
+ */
+ public boolean onUserActionLocked(@NonNull InputMethodInfo imi,
+ @Nullable InputMethodSubtype subtype) {
+ boolean recencyUpdated = false;
+ if (Flags.imeSwitcherRevamp()) {
+ recencyUpdated |= mRotationList.setMostRecent(imi, subtype);
+ recencyUpdated |= mHardwareRotationList.setMostRecent(imi, subtype);
+ if (recencyUpdated) {
+ mUserActionSinceSwitch = true;
+ }
+ } else if (imi.supportsSwitchingToNextInputMethod()) {
+ mSwitchingAwareRotationList.onUserAction(imi, subtype);
+ }
+ return recencyUpdated;
+ }
+
+ /** Called when the input method and subtype was changed. */
+ public void onInputMethodSubtypeChanged() {
+ mUserActionSinceSwitch = false;
+ }
+
+ /**
+ * Whether the given mode and direction result in recency or static order.
+ *
+ * <p>{@link #MODE_AUTO} resolves to the recency order for the first forwards switch
+ * after an {@link #onUserActionLocked user action}, and otherwise to the static order.</p>
+ *
+ * @param mode the switching mode.
+ * @param forward the switching direction.
+ * @return {@code true} for the recency order, otherwise {@code false}.
+ */
+ private boolean isRecency(@SwitchMode int mode, boolean forward) {
+ if (mode == MODE_AUTO && mUserActionSinceSwitch && forward) {
+ return true;
+ } else {
+ return mode == MODE_RECENT;
+ }
+ }
+
+ @NonNull
+ private static List<ImeSubtypeListItem> filterImeSubtypeList(
+ @NonNull List<ImeSubtypeListItem> items,
+ boolean supportsSwitchingToNextInputMethod) {
+ final ArrayList<ImeSubtypeListItem> result = new ArrayList<>();
+ final int numItems = items.size();
+ for (int i = 0; i < numItems; i++) {
+ final ImeSubtypeListItem item = items.get(i);
+ if (item.mImi.supportsSwitchingToNextInputMethod()
+ == supportsSwitchingToNextInputMethod) {
+ result.add(item);
+ }
+ }
+ return result;
+ }
+
+ void dump(@NonNull Printer pw, @NonNull String prefix) {
+ pw.println(prefix + "mSwitchingAwareRotationList:");
+ mSwitchingAwareRotationList.dump(pw, prefix + " ");
+ pw.println(prefix + "mSwitchingUnawareRotationList:");
+ mSwitchingUnawareRotationList.dump(pw, prefix + " ");
+ if (Flags.imeSwitcherRevamp()) {
+ pw.println(prefix + "mRotationList:");
+ mRotationList.dump(pw, prefix + " ");
+ pw.println(prefix + "mHardwareRotationList:");
+ mHardwareRotationList.dump(pw, prefix + " ");
+ pw.println(prefix + "User action since last switch: " + mUserActionSinceSwitch);
+ }
+ }
+
+ InputMethodSubtypeSwitchingController() {
+ }
+
+ public void resetCircularListLocked(@NonNull Context context,
+ @NonNull InputMethodSettings settings) {
+ update(getSortedInputMethodAndSubtypeList(
+ false /* includeAuxiliarySubtypes */, false /* isScreenLocked */,
+ false /* forImeMenu */, context, settings),
+ getInputMethodAndSubtypeListForHardwareKeyboard(context, settings));
}
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index b28da55b..1a2a196 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -360,7 +360,13 @@
IWakeLockCallback callback, int newFlags, String newTag, String newPackageName,
int newOwnerUid, int newOwnerPid, WorkSource newWorkSource, String newHistoryTag,
IWakeLockCallback newCallback) {
-
+ // Todo(b/359154665): We do this because the newWorkSource can potentially be updated
+ // before the request is processed on the notifier thread. This would generally happen is
+ // the Worksource's set method is called, which as of this comment happens only in
+ // PowerManager#setWorksource and WifiManager#WifiLock#setWorksource. Both these places
+ // need to be updated and the WorkSource#set should be deprecated to avoid falling into
+ // such traps
+ newWorkSource = (newWorkSource == null) ? null : new WorkSource(newWorkSource);
final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags);
if (workSource != null && newWorkSource != null
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index a4a29a0..2faa68a 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -20,6 +20,8 @@
import android.app.ITransientNotificationCallback;
import android.content.ComponentName;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.os.Bundle;
import android.os.IBinder;
import android.os.UserHandle;
@@ -54,13 +56,12 @@
* Used by InputMethodManagerService to notify the IME status.
*
* @param displayId The display to which the IME is bound to.
- * @param vis Bit flags about the IME visibility.
- * (e.g. {@link android.inputmethodservice.InputMethodService#IME_ACTIVE})
- * @param backDisposition Bit flags about the IME back disposition.
- * (e.g. {@link android.inputmethodservice.InputMethodService#BACK_DISPOSITION_DEFAULT})
+ * @param vis The IME visibility.
+ * @param backDisposition The IME back disposition.
* @param showImeSwitcher {@code true} when the IME switcher button should be shown.
*/
- void setImeWindowStatus(int displayId, int vis, int backDisposition, boolean showImeSwitcher);
+ void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher);
/**
* See {@link android.app.StatusBarManager#setIcon(String, int, int, String)}.
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index c3601b3c..e71f9ea 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -26,6 +26,7 @@
import static android.app.StatusBarManager.NavBarMode;
import static android.app.StatusBarManager.SessionFlags;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewRootImpl.CLIENT_TRANSIENT;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
@@ -60,6 +61,8 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.media.INearbyMediaDevicesProvider;
import android.media.MediaRoute2Info;
import android.net.Uri;
@@ -534,8 +537,8 @@
}
@Override
- public void setImeWindowStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
StatusBarManagerService.this.setImeWindowStatus(displayId, vis, backDisposition,
showImeSwitcher);
}
@@ -1351,8 +1354,8 @@
}
@Override
- public void setImeWindowStatus(int displayId, final int vis, final int backDisposition,
- final boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, @ImeWindowVisibility final int vis,
+ @BackDispositionMode final int backDisposition, final boolean showImeSwitcher) {
enforceStatusBar();
if (SPEW) {
@@ -1418,8 +1421,10 @@
private String mPackageName = "none";
private int mDisabled1 = 0;
private int mDisabled2 = 0;
+ @ImeWindowVisibility
private int mImeWindowVis = 0;
- private int mImeBackDisposition = 0;
+ @BackDispositionMode
+ private int mImeBackDisposition = BACK_DISPOSITION_DEFAULT;
private boolean mShowImeSwitcher = false;
private LetterboxDetails[] mLetterboxDetails = new LetterboxDetails[0];
@@ -1462,7 +1467,8 @@
return mDisabled1 == disabled1 && mDisabled2 == disabled2;
}
- private void setImeWindowState(final int vis, final int backDisposition,
+ private void setImeWindowState(@ImeWindowVisibility final int vis,
+ @BackDispositionMode final int backDisposition,
final boolean showImeSwitcher) {
mImeWindowVis = vis;
mImeBackDisposition = backDisposition;
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
index a27ad9a..770451c 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -44,7 +44,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl;
import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
import org.junit.Rule;
@@ -178,19 +177,20 @@
return items;
}
- private void assertNextInputMethod(@NonNull ControllerImpl controller, boolean onlyCurrentIme,
- @NonNull ImeSubtypeListItem currentItem, @Nullable ImeSubtypeListItem nextItem) {
+ private void assertNextInputMethod(@NonNull InputMethodSubtypeSwitchingController controller,
+ boolean onlyCurrentIme, @NonNull ImeSubtypeListItem currentItem,
+ @Nullable ImeSubtypeListItem nextItem) {
InputMethodSubtype subtype = null;
if (currentItem.mSubtypeName != null) {
subtype = createTestSubtype(currentItem.mSubtypeName.toString());
}
- final ImeSubtypeListItem nextIme = controller.getNextInputMethod(onlyCurrentIme,
+ final ImeSubtypeListItem nextIme = controller.getNextInputMethodLocked(onlyCurrentIme,
currentItem.mImi, subtype, MODE_STATIC, true /* forward */);
assertEquals(nextItem, nextIme);
}
- private void assertRotationOrder(@NonNull ControllerImpl controller, boolean onlyCurrentIme,
- ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) {
+ private void assertRotationOrder(@NonNull InputMethodSubtypeSwitchingController controller,
+ boolean onlyCurrentIme, ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) {
final int numItems = expectedRotationOrderOfImeSubtypeList.length;
for (int i = 0; i < numItems; i++) {
final int nextIndex = (i + 1) % numItems;
@@ -200,7 +200,7 @@
}
}
- private boolean onUserAction(@NonNull ControllerImpl controller,
+ private boolean onUserAction(@NonNull InputMethodSubtypeSwitchingController controller,
@NonNull ImeSubtypeListItem subtypeListItem) {
InputMethodSubtype subtype = null;
if (subtypeListItem.mSubtypeName != null) {
@@ -228,8 +228,8 @@
final ImeSubtypeListItem japaneseIme_ja_jp = enabledItems.get(6);
final ImeSubtypeListItem switchUnawareJapaneseIme_ja_jp = enabledItems.get(7);
- final ControllerImpl controller = ControllerImpl.createFrom(
- null /* currentInstance */, enabledItems, new ArrayList<>());
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(enabledItems, new ArrayList<>());
// switching-aware loop
assertRotationOrder(controller, false /* onlyCurrentIme */,
@@ -286,8 +286,8 @@
final ImeSubtypeListItem japaneseIme_ja_jp = enabledItems.get(6);
final ImeSubtypeListItem switchUnawareJapaneseIme_ja_jp = enabledItems.get(7);
- final ControllerImpl controller = ControllerImpl.createFrom(
- null /* currentInstance */, enabledItems, new ArrayList<>());
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(enabledItems, new ArrayList<>());
// === switching-aware loop ===
assertRotationOrder(controller, false /* onlyCurrentIme */,
@@ -336,11 +336,10 @@
// Rotation order should be preserved when created with the same subtype list.
final List<ImeSubtypeListItem> sameEnabledItems = createEnabledImeSubtypes();
- final ControllerImpl newController = ControllerImpl.createFrom(controller,
- sameEnabledItems, new ArrayList<>());
- assertRotationOrder(newController, false /* onlyCurrentIme */,
+ controller.update(sameEnabledItems, new ArrayList<>());
+ assertRotationOrder(controller, false /* onlyCurrentIme */,
subtypeAwareIme, latinIme_fr, latinIme_en_us, japaneseIme_ja_jp);
- assertRotationOrder(newController, false /* onlyCurrentIme */,
+ assertRotationOrder(controller, false /* onlyCurrentIme */,
switchingUnawareLatinIme_en_uk, switchingUnawareLatinIme_hi, subtypeUnawareIme,
switchUnawareJapaneseIme_ja_jp);
@@ -348,11 +347,10 @@
final List<ImeSubtypeListItem> differentEnabledItems = List.of(
latinIme_en_us, latinIme_fr, subtypeAwareIme, switchingUnawareLatinIme_en_uk,
switchUnawareJapaneseIme_ja_jp, subtypeUnawareIme);
- final ControllerImpl anotherController = ControllerImpl.createFrom(controller,
- differentEnabledItems, new ArrayList<>());
- assertRotationOrder(anotherController, false /* onlyCurrentIme */,
+ controller.update(differentEnabledItems, new ArrayList<>());
+ assertRotationOrder(controller, false /* onlyCurrentIme */,
latinIme_en_us, latinIme_fr, subtypeAwareIme);
- assertRotationOrder(anotherController, false /* onlyCurrentIme */,
+ assertRotationOrder(controller, false /* onlyCurrentIme */,
switchingUnawareLatinIme_en_uk, switchUnawareJapaneseIme_ja_jp, subtypeUnawareIme);
}
@@ -520,8 +518,8 @@
final var hardwareLatinIme = List.of(hardwareEnglish, hardwareFrench, hardwareItalian);
final var hardwareSimpleIme = List.of(hardwareSimple);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
- hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
final int mode = MODE_STATIC;
@@ -583,8 +581,8 @@
final var hardwareLatinIme = List.of(hardwareEnglish, hardwareFrench, hardwareItalian);
final var hardwareSimpleIme = List.of(hardwareSimple);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
- hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
final int mode = MODE_RECENT;
@@ -666,8 +664,8 @@
final var hardwareLatinIme = List.of(hardwareEnglish, hardwareFrench, hardwareItalian);
final var hardwareSimpleIme = List.of(hardwareSimple);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
- hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
final int mode = MODE_AUTO;
@@ -777,92 +775,73 @@
final var hardwareLatinIme = List.of(hardwareEnglish, hardwareFrench, hardwareItalian);
final var hardwareSimpleIme = List.of(hardwareSimple);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
- hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
final int mode = MODE_RECENT;
// Recency order is initialized to static order.
assertNextOrder(controller, false /* forHardware */, mode,
items, List.of(latinIme, simpleIme));
-
assertNextOrder(controller, true /* forHardware */, mode,
hardwareItems, List.of(hardwareLatinIme, hardwareSimpleIme));
// User action on french IME.
assertTrue("Recency updated for french IME", onUserAction(controller, french));
- final var equalItems = new ArrayList<>(items);
- final var otherItems = new ArrayList<>(items);
- otherItems.remove(simple);
-
- final var equalController = ControllerImpl.createFrom(controller, equalItems,
- hardwareItems);
- final var otherController = ControllerImpl.createFrom(controller, otherItems,
- hardwareItems);
-
final var recencyItems = List.of(french, english, italian, simple);
final var recencyLatinIme = List.of(french, english, italian);
final var recencySimpleIme = List.of(simple);
+ final var equalItems = new ArrayList<>(items);
+ controller.update(equalItems, hardwareItems);
+
+ // The order of non-hardware items remains unchanged when updated with equal items.
assertNextOrder(controller, false /* forHardware */, mode,
recencyItems, List.of(recencyLatinIme, recencySimpleIme));
-
- // The order of equal non-hardware items is unchanged.
- assertNextOrder(equalController, false /* forHardware */, mode,
- recencyItems, List.of(recencyLatinIme, recencySimpleIme));
-
- // The order of other hardware items is reset.
- assertNextOrder(otherController, false /* forHardware */, mode,
- latinIme, List.of(latinIme));
-
- // The order of hardware remains unchanged.
+ // The order of hardware items remains unchanged when only non-hardware items are updated.
assertNextOrder(controller, true /* forHardware */, mode,
hardwareItems, List.of(hardwareLatinIme, hardwareSimpleIme));
- assertNextOrder(equalController, true /* forHardware */, mode,
- hardwareItems, List.of(hardwareLatinIme, hardwareSimpleIme));
+ final var otherItems = new ArrayList<>(items);
+ otherItems.remove(simple);
+ controller.update(otherItems, hardwareItems);
- assertNextOrder(otherController, true /* forHardware */, mode,
+ // The order of non-hardware items is reset when updated with other items.
+ assertNextOrder(controller, false /* forHardware */, mode,
+ latinIme, List.of(latinIme));
+ // The order of hardware items remains unchanged when only non-hardware items are updated.
+ assertNextOrder(controller, true /* forHardware */, mode,
hardwareItems, List.of(hardwareLatinIme, hardwareSimpleIme));
assertTrue("Recency updated for french hardware IME",
onUserAction(controller, hardwareFrench));
- final var equalHardwareItems = new ArrayList<>(hardwareItems);
- final var otherHardwareItems = new ArrayList<>(hardwareItems);
- otherHardwareItems.remove(hardwareSimple);
-
- final var equalHardwareController = ControllerImpl.createFrom(controller, items,
- equalHardwareItems);
- final var otherHardwareController = ControllerImpl.createFrom(controller, items,
- otherHardwareItems);
-
final var recencyHardwareItems =
List.of(hardwareFrench, hardwareEnglish, hardwareItalian, hardwareSimple);
final var recencyHardwareLatinIme =
List.of(hardwareFrench, hardwareEnglish, hardwareItalian);
final var recencyHardwareSimpleIme = List.of(hardwareSimple);
- // The order of non-hardware items remains unchanged.
+ final var equalHardwareItems = new ArrayList<>(hardwareItems);
+ controller.update(otherItems, equalHardwareItems);
+
+ // The order of non-hardware items remains unchanged when only hardware items are updated.
assertNextOrder(controller, false /* forHardware */, mode,
- recencyItems, List.of(recencyLatinIme, recencySimpleIme));
-
- assertNextOrder(equalHardwareController, false /* forHardware */, mode,
- recencyItems, List.of(recencyLatinIme, recencySimpleIme));
-
- assertNextOrder(otherHardwareController, false /* forHardware */, mode,
- recencyItems, List.of(recencyLatinIme, recencySimpleIme));
-
+ latinIme, List.of(latinIme));
+ // The order of hardware items remains unchanged when updated with equal items.
assertNextOrder(controller, true /* forHardware */, mode,
recencyHardwareItems, List.of(recencyHardwareLatinIme, recencyHardwareSimpleIme));
- // The order of equal hardware items is unchanged.
- assertNextOrder(equalHardwareController, true /* forHardware */, mode,
- recencyHardwareItems, List.of(recencyHardwareLatinIme, recencyHardwareSimpleIme));
+ final var otherHardwareItems = new ArrayList<>(hardwareItems);
+ otherHardwareItems.remove(hardwareSimple);
+ controller.update(otherItems, otherHardwareItems);
- // The order of other hardware items is reset.
- assertNextOrder(otherHardwareController, true /* forHardware */, mode,
+ // The order of non-hardware items remains unchanged when only hardware items are updated.
+ assertNextOrder(controller, false /* forHardware */, mode,
+ latinIme, List.of(latinIme));
+ // The order of hardware items is reset when updated with other items.
+ assertNextOrder(controller, true /* forHardware */, mode,
hardwareLatinIme, List.of(hardwareLatinIme));
}
@@ -882,8 +861,8 @@
addTestImeSubtypeListItems(hardwareItems, "hardwareSwitchUnaware", "hardwareSwitchUnaware",
null, false /* supportsSwitchingToNextInputMethod*/);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
- hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
for (int mode = MODE_STATIC; mode <= MODE_AUTO; mode++) {
assertNextOrder(controller, false /* forHardware */, false /* onlyCurrentIme */,
@@ -910,8 +889,7 @@
addTestImeSubtypeListItems(hardwareItems, "HardwareIme", "HardwareIme",
List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, List.of(),
- List.of());
+ final var controller = new InputMethodSubtypeSwitchingController();
assertNextItemNoAction(controller, false /* forHardware */, items,
null /* expectedNext */);
@@ -940,8 +918,8 @@
addTestImeSubtypeListItems(unknownHardwareItems, "HardwareUnknownIme", "HardwareUnknownIme",
List.of("en", "fr", "it"), true /* supportsSwitchingToNextInputMethod */);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */,
- items, hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
assertNextItemNoAction(controller, false /* forHardware */, items,
null /* expectedNext */);
@@ -979,8 +957,8 @@
addTestImeSubtypeListItems(unknownHardwareItems, "HardwareUnknownIme", "HardwareUnknownIme",
List.of("en", "fr", "it"), true /* supportsSwitchingToNextInputMethod */);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
- hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
assertTrue("Recency updated for french IME", onUserAction(controller, french));
@@ -1118,8 +1096,9 @@
* @param allItems the list of items across all IMEs.
* @param perImeItems the list of lists of items per IME.
*/
- private static void assertNextOrder(@NonNull ControllerImpl controller, boolean forHardware,
- @SwitchMode int mode, boolean forward, @NonNull List<ImeSubtypeListItem> allItems,
+ private static void assertNextOrder(@NonNull InputMethodSubtypeSwitchingController controller,
+ boolean forHardware, @SwitchMode int mode, boolean forward,
+ @NonNull List<ImeSubtypeListItem> allItems,
@NonNull List<List<ImeSubtypeListItem>> perImeItems) {
assertNextOrder(controller, forHardware, false /* onlyCurrentIme */, mode,
forward, allItems);
@@ -1142,8 +1121,8 @@
* @param allItems the list of items across all IMEs.
* @param perImeItems the list of lists of items per IME.
*/
- private static void assertNextOrder(@NonNull ControllerImpl controller, boolean forHardware,
- @SwitchMode int mode, @NonNull List<ImeSubtypeListItem> allItems,
+ private static void assertNextOrder(@NonNull InputMethodSubtypeSwitchingController controller,
+ boolean forHardware, @SwitchMode int mode, @NonNull List<ImeSubtypeListItem> allItems,
@NonNull List<List<ImeSubtypeListItem>> perImeItems) {
assertNextOrder(controller, forHardware, false /* onlyCurrentIme */, mode,
true /* forward */, allItems);
@@ -1170,7 +1149,7 @@
* @param forward whether to search forwards or backwards in the list.
* @param items the list of items to verify, in the expected order.
*/
- private static void assertNextOrder(@NonNull ControllerImpl controller,
+ private static void assertNextOrder(@NonNull InputMethodSubtypeSwitchingController controller,
boolean forHardware, boolean onlyCurrentIme, @SwitchMode int mode, boolean forward,
@NonNull List<ImeSubtypeListItem> items) {
final int numItems = items.size();
@@ -1214,7 +1193,7 @@
* @param item the item to find the next value from.
* @param expectedNext the expected next value.
*/
- private static void assertNextItem(@NonNull ControllerImpl controller,
+ private static void assertNextItem(@NonNull InputMethodSubtypeSwitchingController controller,
boolean forHardware, boolean onlyCurrentIme, @SwitchMode int mode, boolean forward,
@NonNull ImeSubtypeListItem item, @Nullable ImeSubtypeListItem expectedNext) {
final var nextItem = getNextItem(controller, forHardware, onlyCurrentIme, mode, forward,
@@ -1234,15 +1213,16 @@
* @return the next item found, otherwise {@code null}.
*/
@Nullable
- private static ImeSubtypeListItem getNextItem(@NonNull ControllerImpl controller,
- boolean forHardware, boolean onlyCurrentIme, @SwitchMode int mode, boolean forward,
+ private static ImeSubtypeListItem getNextItem(
+ @NonNull InputMethodSubtypeSwitchingController controller, boolean forHardware,
+ boolean onlyCurrentIme, @SwitchMode int mode, boolean forward,
@NonNull ImeSubtypeListItem item) {
final var subtype = item.mSubtypeName != null
? createTestSubtype(item.mSubtypeName.toString()) : null;
return forHardware
? controller.getNextInputMethodForHardware(
onlyCurrentIme, item.mImi, subtype, mode, forward)
- : controller.getNextInputMethod(
+ : controller.getNextInputMethodLocked(
onlyCurrentIme, item.mImi, subtype, mode, forward);
}
@@ -1255,8 +1235,9 @@
* @param items the list of items to verify.
* @param expectedNext the expected next item.
*/
- private void assertNextItemNoAction(@NonNull ControllerImpl controller, boolean forHardware,
- @NonNull List<ImeSubtypeListItem> items, @Nullable ImeSubtypeListItem expectedNext) {
+ private void assertNextItemNoAction(@NonNull InputMethodSubtypeSwitchingController controller,
+ boolean forHardware, @NonNull List<ImeSubtypeListItem> items,
+ @Nullable ImeSubtypeListItem expectedNext) {
for (var item : items) {
for (int mode = MODE_STATIC; mode <= MODE_AUTO; mode++) {
assertNextItem(controller, forHardware, false /* onlyCurrentIme */, mode,
diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
index d45e312..fc4d8d8 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -61,7 +61,6 @@
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.concurrent.Executor;
@@ -264,8 +263,8 @@
BatteryStats.WAKE_TYPE_PARTIAL, false);
verifyNoMoreInteractions(mWakeLockLog, mBatteryStats);
- WorkSource worksourceOld = Mockito.mock(WorkSource.class);
- WorkSource worksourceNew = Mockito.mock(WorkSource.class);
+ WorkSource worksourceOld = new WorkSource(/*uid=*/ 1);
+ WorkSource worksourceNew = new WorkSource(/*uid=*/ 2);
mNotifier.onWakeLockChanging(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
"my.package.name", uid, pid, worksourceOld, /* historyTag= */ null,
@@ -309,6 +308,40 @@
verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
}
+ @Test
+ public void
+ test_notifierProcessesWorkSourceDeepCopy_OnWakelockChanging() throws RemoteException {
+ when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);
+ createNotifier();
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+ IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
+ @Override public void onStateChanged(boolean enabled) throws RemoteException {
+ throw new RemoteException("Just testing");
+ }
+ };
+
+ final int uid = 1234;
+ final int pid = 5678;
+ mTestLooper.dispatchAll();
+ WorkSource worksourceOld = new WorkSource(/*uid=*/ 1);
+ WorkSource worksourceNew = new WorkSource(/*uid=*/ 2);
+
+ mNotifier.onWakeLockChanging(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, worksourceOld, /* historyTag= */ null,
+ exceptingCallback,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, worksourceNew, /* newHistoryTag= */ null,
+ exceptingCallback);
+ // The newWorksource is modified before notifier could process it.
+ worksourceNew.set(/*uid=*/ 3);
+
+ mTestLooper.dispatchAll();
+ verify(mBatteryStats).noteChangeWakelockFromSource(worksourceOld, pid,
+ "wakelockTag", null, BatteryStats.WAKE_TYPE_PARTIAL,
+ new WorkSource(/*uid=*/ 2), pid, "wakelockTag", null,
+ BatteryStats.WAKE_TYPE_FULL, false);
+ }
+
@Test
public void testOnWakeLockListener_FullWakeLock_ProcessesOnHandler() throws RemoteException {
diff --git a/tests/FlickerTests/AppLaunch/Android.bp b/tests/FlickerTests/AppLaunch/Android.bp
index 72a9065..b61739f 100644
--- a/tests/FlickerTests/AppLaunch/Android.bp
+++ b/tests/FlickerTests/AppLaunch/Android.bp
@@ -15,6 +15,7 @@
//
package {
+ default_team: "trendy_team_windowing_animations_transitions",
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
@@ -23,6 +24,9 @@
default_applicable_licenses: ["frameworks_base_license"],
}
+////////////////////////////////////////////////////////////////////////////////
+// Begin to cleanup after CL merges
+
filegroup {
name: "FlickerTestsAppLaunchCommon-src",
srcs: ["src/**/common/*"],
@@ -69,3 +73,122 @@
],
data: ["trace_config/*"],
}
+
+// End to cleanup after CL merges
+////////////////////////////////////////////////////////////////////////////////
+
+android_test {
+ name: "FlickerTestsAppLaunch",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: [
+ "FlickerTestsBase",
+ "FlickerTestsAppLaunchCommon",
+ ],
+ data: ["trace_config/*"],
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Begin breakdowns for FlickerTestsAppLaunch module
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-CatchAll",
+ base: "FlickerTestsAppLaunch",
+ exclude_filters: [
+ "com.android.server.wm.flicker.launch.TaskTransitionTest",
+ "com.android.server.wm.flicker.launch.ActivityTransitionTest",
+ "com.android.server.wm.flicker.launch.OpenAppFromIconColdTest",
+ "com.android.server.wm.flicker.launch.OpenAppFromIntentColdAfterCameraTest",
+ "com.android.server.wm.flicker.launch.OpenAppFromIntentColdTest",
+ "com.android.server.wm.flicker.launch.OpenAppFromIntentWarmTest",
+ "com.android.server.wm.flicker.launch.OpenAppFromLockscreenViaIntentTest",
+ "com.android.server.wm.flicker.launch.OpenAppFromOverviewTest",
+ "com.android.server.wm.flicker.launch.OpenCameraFromHomeOnDoubleClickPowerButtonTest",
+ "com.android.server.wm.flicker.launch.OpenTransferSplashscreenAppFromLauncherTransition",
+ "com.android.server.wm.flicker.launch.OverrideTaskTransitionTest",
+ "com.android.server.wm.flicker.launch.TaskTransitionTest",
+ ],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-ActivityTransitionTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.ActivityTransitionTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenAppFromIconColdTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromIconColdTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenAppFromIntentColdAfterCameraTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromIntentColdAfterCameraTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenAppFromIntentColdTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromIntentColdTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenAppFromIntentWarmTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromIntentWarmTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenAppFromLockscreenViaIntentTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromLockscreenViaIntentTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenAppFromOverviewTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromOverviewTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenCameraFromHomeOnDoubleClickPowerButtonTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenCameraFromHomeOnDoubleClickPowerButtonTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenTransferSplashscreenAppFromLauncherTransition",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenTransferSplashscreenAppFromLauncherTransition"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OverrideTaskTransitionTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OverrideTaskTransitionTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-TaskTransitionTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.TaskTransitionTest"],
+ test_suites: ["device-tests"],
+}
+
+// End breakdowns for FlickerTestsAppLaunch module
+////////////////////////////////////////////////////////////////////////////////