Merge "Fix typo in @throw tag" into main
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 03e230c..69b91fd 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -144,6 +144,13 @@
}
flag {
+ name: "universal_resizable_by_default"
+ namespace: "windowing_frontend"
+ description: "The orientation, aspect ratio, resizability of activity will follow system behavior by default"
+ bug: "357141415"
+}
+
+flag {
name: "respect_non_top_visible_fixed_orientation"
namespace: "windowing_frontend"
description: "If top activity is not opaque, respect the fixed orientation of activity behind it"
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItem.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItem.kt
index a0fe5d2..38183d5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItem.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItem.kt
@@ -36,6 +36,7 @@
val className: String,
val intentAction: String,
val preferenceKey: String? = null,
+ val highlighted: Boolean = false,
val extras: Bundle = Bundle.EMPTY,
) : Parcelable {
@@ -47,6 +48,7 @@
writeString(packageName)
writeString(className)
writeString(intentAction)
+ writeBoolean(highlighted)
writeString(preferenceKey)
writeBundle(extras)
}
@@ -63,6 +65,7 @@
packageName = readString() ?: "",
className = readString() ?: "",
intentAction = readString() ?: "",
+ highlighted = readBoolean(),
preferenceKey = readString() ?: "",
extras = readBundle((Bundle::class.java.classLoader)) ?: Bundle.EMPTY,
)
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPreference.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPreference.java
index 4b67ef7..c8c7562 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPreference.java
@@ -42,6 +42,8 @@
return MultiTogglePreference.readFromParcel(in);
case DeviceSettingType.DEVICE_SETTING_TYPE_FOOTER:
return DeviceSettingFooterPreference.readFromParcel(in);
+ case DeviceSettingType.DEVICE_SETTING_TYPE_HELP:
+ return DeviceSettingHelpPreference.readFromParcel(in);
default:
return UNKNOWN;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
index 769b6e6..29664f6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
@@ -110,15 +110,16 @@
if (settingId == DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES) {
BluetoothProfilesItem(
settingId,
+ highlighted,
preferenceKey!!,
extras.getStringArrayList(DeviceSettingContract.INVISIBLE_PROFILES)
?: emptyList()
)
} else {
- CommonBuiltinItem(settingId, preferenceKey!!)
+ CommonBuiltinItem(settingId, highlighted, preferenceKey!!)
}
} else {
- AppProvidedItem(settingId)
+ AppProvidedItem(settingId, highlighted)
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt
index 08fb3fb..5958c30 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt
@@ -34,6 +34,7 @@
/** Models a device setting item in config. */
sealed interface DeviceSettingConfigItemModel {
@DeviceSettingId val settingId: Int
+ val highlighted: Boolean
/** A built-in item in Settings. */
sealed interface BuiltinItem : DeviceSettingConfigItemModel {
@@ -43,18 +44,22 @@
/** A general built-in item in Settings. */
data class CommonBuiltinItem(
@DeviceSettingId override val settingId: Int,
+ override val highlighted: Boolean,
override val preferenceKey: String,
) : BuiltinItem
/** A bluetooth profiles in Settings. */
data class BluetoothProfilesItem(
@DeviceSettingId override val settingId: Int,
+ override val highlighted: Boolean,
override val preferenceKey: String,
val invisibleProfiles: List<String>,
) : BuiltinItem
}
/** A remote item provided by other apps. */
- data class AppProvidedItem(@DeviceSettingId override val settingId: Int) :
- DeviceSettingConfigItemModel
+ data class AppProvidedItem(
+ @DeviceSettingId override val settingId: Int,
+ override val highlighted: Boolean,
+ ) : DeviceSettingConfigItemModel
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItemTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItemTest.kt
index 56e9b6c..86071bb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItemTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItemTest.kt
@@ -34,6 +34,8 @@
packageName = "package_name",
className = "class_name",
intentAction = "intent_action",
+ preferenceKey = "key1",
+ highlighted = true,
extras = Bundle().apply { putString("key1", "value1") },
)
@@ -43,6 +45,7 @@
assertThat(fromParcel.packageName).isEqualTo(item.packageName)
assertThat(fromParcel.className).isEqualTo(item.className)
assertThat(fromParcel.intentAction).isEqualTo(item.intentAction)
+ assertThat(fromParcel.preferenceKey).isEqualTo(item.preferenceKey)
assertThat(fromParcel.extras.getString("key1")).isEqualTo(item.extras.getString("key1"))
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsConfigTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsConfigTest.kt
index a0a2658..7f17293 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsConfigTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsConfigTest.kt
@@ -33,30 +33,33 @@
mainContentItems =
listOf(
DeviceSettingItem(
- 1,
- "package_name_1",
- "class_name_1",
- "intent_action_1",
- null,
- Bundle(),
+ settingId = 1,
+ packageName = "package_name_1",
+ className = "class_name_1",
+ intentAction = "intent_action_1",
+ preferenceKey = null,
+ highlighted = false,
+ extras = Bundle(),
)),
moreSettingsItems =
listOf(
DeviceSettingItem(
- 2,
- "package_name_2",
- "class_name_2",
- "intent_action_2",
- null,
- Bundle(),
+ settingId = 2,
+ packageName = "package_name_2",
+ className = "class_name_2",
+ intentAction = "intent_action_2",
+ preferenceKey = null,
+ highlighted = false,
+ extras = Bundle(),
)),
moreSettingsHelpItem = DeviceSettingItem(
- 3,
- "package_name_2",
- "class_name_2",
- "intent_action_2",
- null,
- Bundle(),
+ settingId = 3,
+ packageName = "package_name_2",
+ className = "class_name_2",
+ intentAction = "intent_action_2",
+ preferenceKey = null,
+ highlighted = false,
+ extras = Bundle(),
),
extras = Bundle().apply { putString("key1", "value1") },
)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 5a084db..ebe1df4 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -813,6 +813,10 @@
element: Element,
elementState: TransitionState,
): Boolean {
+ if (element.key.placeAllCopies) {
+ return true
+ }
+
val transition =
when (elementState) {
is TransitionState.Idle -> {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
index f9a9eeb..2e7488b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
@@ -79,6 +79,16 @@
* or compose MovableElements.
*/
open val contentPicker: ElementContentPicker = DefaultElementContentPicker,
+
+ /**
+ * Whether we should place all copies of this element when it is shared.
+ *
+ * This should usually be false, but it can be useful when sharing a container that has a
+ * different content in different scenes/overlays. That way the container will have the same
+ * size and position in all scenes/overlays but all different contents will be placed and
+ * visible on screen.
+ */
+ val placeAllCopies: Boolean = false,
) : Key(debugName, identity), ElementMatcher {
@VisibleForTesting
// TODO(b/240432457): Make internal once PlatformComposeSceneTransitionLayoutTestsUtils can
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index dbff8a4..2e8fc14 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -176,6 +176,35 @@
animationScope: CoroutineScope,
transitionKey: TransitionKey? = null,
)
+
+ /**
+ * Instantly start a [transition], running it in [animationScope].
+ *
+ * This call returns immediately and [transition] will be the [currentTransition] of this
+ * [MutableSceneTransitionLayoutState].
+ *
+ * @see startTransition
+ */
+ fun startTransitionImmediately(
+ animationScope: CoroutineScope,
+ transition: TransitionState.Transition,
+ chain: Boolean = true,
+ ): Job
+
+ /**
+ * Start a new [transition].
+ *
+ * If [chain] is `true`, then the transitions will simply be added to [currentTransitions] and
+ * will run in parallel to the current transitions. If [chain] is `false`, then the list of
+ * [currentTransitions] will be cleared and [transition] will be the only running transition.
+ *
+ * If any transition is currently ongoing, it will be interrupted and forced to animate to its
+ * current state by calling [TransitionState.Transition.freezeAndAnimateToCurrentState].
+ *
+ * This method returns when [transition] is done running, i.e. when the call to
+ * [run][TransitionState.Transition.run] returns.
+ */
+ suspend fun startTransition(transition: TransitionState.Transition, chain: Boolean = true)
}
/**
@@ -313,18 +342,10 @@
)
}
- /**
- * Instantly start a [transition], running it in [animationScope].
- *
- * This call returns immediately and [transition] will be the [currentTransition] of this
- * [MutableSceneTransitionLayoutState].
- *
- * @see startTransition
- */
- internal fun startTransitionImmediately(
+ override fun startTransitionImmediately(
animationScope: CoroutineScope,
transition: TransitionState.Transition,
- chain: Boolean = true,
+ chain: Boolean,
): Job {
// Note that we start with UNDISPATCHED so that startTransition() is called directly and
// transition becomes the current [transitionState] right after this call.
@@ -333,23 +354,7 @@
}
}
- /**
- * Start a new [transition].
- *
- * If [chain] is `true`, then the transitions will simply be added to [currentTransitions] and
- * will run in parallel to the current transitions. If [chain] is `false`, then the list of
- * [currentTransitions] will be cleared and [transition] will be the only running transition.
- *
- * If any transition is currently ongoing, it will be interrupted and forced to animate to its
- * current state.
- *
- * This method returns when [transition] is done running, i.e. when the call to
- * [run][TransitionState.Transition.run] returns.
- */
- internal suspend fun startTransition(
- transition: TransitionState.Transition,
- chain: Boolean = true,
- ) {
+ override suspend fun startTransition(transition: TransitionState.Transition, chain: Boolean) {
checkThread()
try {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
index 364c203..d6751ae 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
@@ -300,7 +300,7 @@
}
/** Run this transition and return once it is finished. */
- internal abstract suspend fun run()
+ abstract suspend fun run()
/**
* Freeze this transition state so that neither [currentScene] nor [currentOverlays] will
@@ -311,7 +311,7 @@
*
* This is called when this transition is interrupted (replaced) by another transition.
*/
- internal abstract fun freezeAndAnimateToCurrentState()
+ abstract fun freezeAndAnimateToCurrentState()
internal fun updateOverscrollSpecs(
fromSpec: OverscrollSpecImpl?,
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 43fc131..1eed54e 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -2519,4 +2519,65 @@
.onNode(hasTestTag(contentTestTag) and hasParent(isElement(movable)))
.assertSizeIsEqualTo(40.dp)
}
+
+ @Test
+ fun placeAllCopies() {
+ val foo = ElementKey("Foo", placeAllCopies = true)
+
+ @Composable
+ fun SceneScope.Foo(size: Dp, modifier: Modifier = Modifier) {
+ Box(modifier.element(foo).size(size))
+ }
+
+ rule.testTransition(
+ fromSceneContent = { Box(Modifier.size(100.dp)) { Foo(size = 10.dp) } },
+ toSceneContent = {
+ Box(Modifier.size(100.dp)) {
+ Foo(size = 50.dp, Modifier.align(Alignment.BottomEnd))
+ }
+ },
+ transition = { spec = tween(4 * 16, easing = LinearEasing) },
+ ) {
+ before {
+ onElement(foo, SceneA)
+ .assertSizeIsEqualTo(10.dp)
+ .assertPositionInRootIsEqualTo(0.dp, 0.dp)
+ onElement(foo, SceneB).assertDoesNotExist()
+ }
+
+ at(16) {
+ onElement(foo, SceneA)
+ .assertSizeIsEqualTo(20.dp)
+ .assertPositionInRootIsEqualTo(12.5.dp, 12.5.dp)
+ onElement(foo, SceneB)
+ .assertSizeIsEqualTo(20.dp)
+ .assertPositionInRootIsEqualTo(12.5.dp, 12.5.dp)
+ }
+
+ at(32) {
+ onElement(foo, SceneA)
+ .assertSizeIsEqualTo(30.dp)
+ .assertPositionInRootIsEqualTo(25.dp, 25.dp)
+ onElement(foo, SceneB)
+ .assertSizeIsEqualTo(30.dp)
+ .assertPositionInRootIsEqualTo(25.dp, 25.dp)
+ }
+
+ at(48) {
+ onElement(foo, SceneA)
+ .assertSizeIsEqualTo(40.dp)
+ .assertPositionInRootIsEqualTo(37.5.dp, 37.5.dp)
+ onElement(foo, SceneB)
+ .assertSizeIsEqualTo(40.dp)
+ .assertPositionInRootIsEqualTo(37.5.dp, 37.5.dp)
+ }
+
+ after {
+ onElement(foo, SceneA).assertDoesNotExist()
+ onElement(foo, SceneB)
+ .assertSizeIsEqualTo(50.dp)
+ .assertPositionInRootIsEqualTo(50.dp, 50.dp)
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
index 886b32b..717f82d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
@@ -31,12 +31,10 @@
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -74,7 +72,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -98,6 +95,10 @@
private static final String BACKLINKS_TASK_APP_NAME = "Ultimate question app";
private static final String BACKLINKS_TASK_PACKAGE_NAME = "backlinksTaskPackageName";
private static final AssistContent EMPTY_ASSIST_CONTENT = new AssistContent();
+ private static final ResolveInfo BACKLINKS_TASK_RESOLVE_INFO =
+ createBacklinksTaskResolveInfo();
+ private static final RunningTaskInfo BACKLINKS_TASK_RUNNING_TASK_INFO =
+ createTaskInfoForBacklinksTask();
@Mock
private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
@@ -111,26 +112,11 @@
Context mMockedContext;
@Mock
private PackageManager mPackageManager;
- private ArgumentCaptor<Intent> mPackageManagerLauncherIntentCaptor;
- private ArgumentCaptor<Intent> mPackageManagerBacklinkIntentCaptor;
private AppClipsViewModel mViewModel;
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
- mPackageManagerLauncherIntentCaptor = ArgumentCaptor.forClass(Intent.class);
- mPackageManagerBacklinkIntentCaptor = ArgumentCaptor.forClass(Intent.class);
-
- // Set up mocking for backlinks.
- when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
- .thenReturn(List.of(createTaskInfoForBacklinksTask()));
- ResolveInfo expectedResolveInfo = createBacklinksTaskResolveInfo();
- when(mPackageManager.resolveActivity(mPackageManagerLauncherIntentCaptor.capture(),
- anyInt())).thenReturn(expectedResolveInfo);
- when(mPackageManager.queryIntentActivities(mPackageManagerBacklinkIntentCaptor.capture(),
- eq(MATCH_DEFAULT_ONLY))).thenReturn(List.of(expectedResolveInfo));
- when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
- when(mMockedContext.getPackageManager()).thenReturn(mPackageManager);
mViewModel = new AppClipsViewModel.Factory(mAppClipsCrossProcessHelper, mImageExporter,
mAtmService, mAssistContentRequester, mMockedContext,
@@ -208,19 +194,18 @@
}
@Test
- public void triggerBacklinks_shouldUpdateBacklinks_withUri() {
+ public void triggerBacklinks_shouldUpdateBacklinks_withUri() throws RemoteException {
Uri expectedUri = Uri.parse("https://developers.android.com");
AssistContent contentWithUri = new AssistContent();
contentWithUri.setWebUri(expectedUri);
mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
+ mockPackageManagerToResolveUri(expectedUri, BACKLINKS_TASK_RESOLVE_INFO);
+ mockBacklinksTaskForMainLauncherIntent();
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
- Intent queriedIntent = mPackageManagerBacklinkIntentCaptor.getValue();
- assertThat(queriedIntent.getData()).isEqualTo(expectedUri);
- assertThat(queriedIntent.getAction()).isEqualTo(ACTION_VIEW);
-
BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
ClipData clipData = result.getClipData();
@@ -234,14 +219,17 @@
}
@Test
- public void triggerBacklinks_shouldUpdateBacklinks_withUriForDifferentApp() {
+ public void triggerBacklinks_shouldUpdateBacklinks_withUriForDifferentApp()
+ throws RemoteException {
+ // Mock for the screenshotted app so that it can be used for fallback backlink.
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
+ mockBacklinksTaskForMainLauncherIntent();
+
Uri expectedUri = Uri.parse("https://android.com");
AssistContent contentWithUri = new AssistContent();
contentWithUri.setWebUri(expectedUri);
mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
- // Reset PackageManager mocking done in setup.
- reset(mPackageManager);
String package2 = BACKLINKS_TASK_PACKAGE_NAME + 2;
String appName2 = BACKLINKS_TASK_APP_NAME + 2;
ResolveInfo resolveInfo2 = createBacklinksTaskResolveInfo();
@@ -250,14 +238,9 @@
activityInfo2.packageName = package2;
activityInfo2.applicationInfo.packageName = package2;
- Intent app2LauncherIntent = new Intent(ACTION_MAIN).addCategory(
- CATEGORY_LAUNCHER).setPackage(package2);
- when(mPackageManager.resolveActivity(intentEquals(app2LauncherIntent), eq(/* flags= */ 0)))
- .thenReturn(resolveInfo2);
- Intent uriIntent = new Intent(ACTION_VIEW).setData(expectedUri);
- when(mPackageManager.queryIntentActivities(intentEquals(uriIntent), eq(MATCH_DEFAULT_ONLY)))
- .thenReturn(List.of(resolveInfo2));
- when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
+ // Mock the different app resolve info so that backlinks resolves to this different app.
+ mockPackageManagerToResolveUri(expectedUri, resolveInfo2);
+ mockPmToResolveForMainLauncherIntent(resolveInfo2);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -273,30 +256,15 @@
assertThat(mViewModel.getBacklinksLiveData().getValue().size()).isEqualTo(1);
}
- private static class IntentMatcher implements ArgumentMatcher<Intent> {
- private final Intent mExpectedIntent;
-
- IntentMatcher(Intent expectedIntent) {
- mExpectedIntent = expectedIntent;
- }
-
- @Override
- public boolean matches(Intent actualIntent) {
- return actualIntent != null && mExpectedIntent.filterEquals(actualIntent);
- }
- }
-
- private static Intent intentEquals(Intent intent) {
- return argThat(new IntentMatcher(intent));
- }
-
@Test
- public void triggerBacklinks_withNonResolvableUri_usesMainLauncherIntent() {
+ public void triggerBacklinks_withNonResolvableUri_usesMainLauncherIntent()
+ throws RemoteException {
Uri expectedUri = Uri.parse("https://developers.android.com");
AssistContent contentWithUri = new AssistContent();
contentWithUri.setWebUri(expectedUri);
mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
- resetPackageManagerMockingForUsingFallbackBacklinks();
+ mockBacklinksTaskForMainLauncherIntent();
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -305,18 +273,19 @@
}
@Test
- public void triggerBacklinks_shouldUpdateBacklinks_withAppProvidedIntent() {
+ public void triggerBacklinks_shouldUpdateBacklinks_withAppProvidedIntent()
+ throws RemoteException {
Intent expectedIntent = new Intent().setPackage(BACKLINKS_TASK_PACKAGE_NAME);
AssistContent contentWithAppProvidedIntent = new AssistContent();
contentWithAppProvidedIntent.setIntent(expectedIntent);
mockForAssistContent(contentWithAppProvidedIntent, BACKLINKS_TASK_ID);
+ mockQueryIntentActivities(expectedIntent, BACKLINKS_TASK_RESOLVE_INFO);
+ mockBacklinksTaskForMainLauncherIntent();
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
- Intent queriedIntent = mPackageManagerBacklinkIntentCaptor.getValue();
- assertThat(queriedIntent.getPackage()).isEqualTo(expectedIntent.getPackage());
-
BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
ClipData clipData = result.getClipData();
@@ -328,12 +297,14 @@
}
@Test
- public void triggerBacklinks_withNonResolvableAppProvidedIntent_usesMainLauncherIntent() {
+ public void triggerBacklinks_withNonResolvableAppProvidedIntent_usesMainLauncherIntent()
+ throws RemoteException {
Intent expectedIntent = new Intent().setPackage(BACKLINKS_TASK_PACKAGE_NAME);
AssistContent contentWithAppProvidedIntent = new AssistContent();
contentWithAppProvidedIntent.setIntent(expectedIntent);
mockForAssistContent(contentWithAppProvidedIntent, BACKLINKS_TASK_ID);
- resetPackageManagerMockingForUsingFallbackBacklinks();
+ mockBacklinksTaskForMainLauncherIntent();
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -342,25 +313,28 @@
}
@Test
- public void triggerBacklinks_shouldUpdateBacklinks_withMainLauncherIntent() {
+ public void triggerBacklinks_shouldUpdateBacklinks_withMainLauncherIntent()
+ throws RemoteException {
mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
+ mockBacklinksTaskForMainLauncherIntent();
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
- Intent queriedIntent = mPackageManagerLauncherIntentCaptor.getValue();
- assertThat(queriedIntent.getPackage()).isEqualTo(BACKLINKS_TASK_PACKAGE_NAME);
- assertThat(queriedIntent.getAction()).isEqualTo(ACTION_MAIN);
- assertThat(queriedIntent.getCategories()).containsExactly(CATEGORY_LAUNCHER);
-
verifyMainLauncherBacklinksIntent();
}
@Test
- public void triggerBacklinks_withNonResolvableMainLauncherIntent_noBacklinksAvailable() {
- reset(mPackageManager);
+ public void triggerBacklinks_withNonResolvableMainLauncherIntent_noBacklinksAvailable()
+ throws RemoteException {
mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
+ // Mock ATM service so we return task info but don't mock PM to resolve the task intent.
+ when(mAtmService.getTasks(Integer.MAX_VALUE, /* filterOnlyVisibleRecents= */
+ false, /* keepIntentExtras= */ false, DEFAULT_DISPLAY)).thenReturn(
+ List.of(BACKLINKS_TASK_RUNNING_TASK_INFO));
+
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -371,11 +345,9 @@
@Test
public void triggerBacklinks_nonStandardActivityIgnored_noBacklinkAvailable()
throws RemoteException {
- reset(mAtmService);
RunningTaskInfo taskInfo = createTaskInfoForBacklinksTask();
taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME);
- when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
- .thenReturn(List.of(taskInfo));
+ mockAtmToReturnRunningTaskInfo(taskInfo);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -399,9 +371,9 @@
public void triggerBacklinks_multipleAppsOnScreen_multipleBacklinksAvailable()
throws RemoteException {
// Set up mocking for multiple backlinks.
- reset(mAtmService, mPackageManager);
- RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
ResolveInfo resolveInfo1 = createBacklinksTaskResolveInfo();
+ RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
+ runningTaskInfo1.topActivityInfo = resolveInfo1.activityInfo;
int taskId2 = BACKLINKS_TASK_ID + 2;
String package2 = BACKLINKS_TASK_PACKAGE_NAME + 2;
@@ -418,27 +390,23 @@
runningTaskInfo2.topActivityInfo = resolveInfo2.activityInfo;
runningTaskInfo2.baseIntent = new Intent().setComponent(runningTaskInfo2.topActivity);
- // For each task, the logic queries PM 3 times, twice for verifying if an app can be
- // launched via launcher and once with the data provided in backlink intent.
- when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo1,
- resolveInfo1, resolveInfo2, resolveInfo2);
- when(mPackageManager.queryIntentActivities(any(Intent.class), eq(MATCH_DEFAULT_ONLY)))
- .thenReturn(List.of(resolveInfo1)).thenReturn(List.of(resolveInfo2));
- when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
- when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
- .thenReturn(List.of(runningTaskInfo1, runningTaskInfo2));
+ mockAtmToReturnRunningTaskInfo(runningTaskInfo1, runningTaskInfo2);
+ mockPmToResolveForMainLauncherIntent(resolveInfo1);
+ mockPmToResolveForMainLauncherIntent(resolveInfo2);
// Using app provided web uri for the first backlink.
Uri expectedUri = Uri.parse("https://developers.android.com");
AssistContent contentWithUri = new AssistContent();
contentWithUri.setWebUri(expectedUri);
mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
+ mockPackageManagerToResolveUri(expectedUri, resolveInfo1);
// Using app provided intent for the second backlink.
Intent expectedIntent = new Intent().setPackage(package2);
AssistContent contentWithAppProvidedIntent = new AssistContent();
contentWithAppProvidedIntent.setIntent(expectedIntent);
mockForAssistContent(contentWithAppProvidedIntent, taskId2);
+ mockQueryIntentActivities(expectedIntent, resolveInfo2);
// Set up complete, trigger the backlinks action.
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
@@ -460,11 +428,12 @@
@Test
public void triggerBacklinks_singleCrossProfileApp_shouldIndicateError()
throws RemoteException {
- reset(mAtmService);
RunningTaskInfo taskInfo = createTaskInfoForBacklinksTask();
taskInfo.userId = UserHandle.myUserId() + 1;
- when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
- .thenReturn(List.of(taskInfo));
+ when(mAtmService.getTasks(Integer.MAX_VALUE, /* filterOnlyVisibleRecents= */
+ false, /* keepIntentExtra */ false, DEFAULT_DISPLAY)).thenReturn(List.of(taskInfo));
+ when(mPackageManager.loadItemIcon(taskInfo.topActivityInfo,
+ taskInfo.topActivityInfo.applicationInfo)).thenReturn(FAKE_DRAWABLE);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -478,13 +447,13 @@
throws RemoteException {
// Set up mocking for multiple backlinks.
mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
- reset(mAtmService);
- RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
RunningTaskInfo runningTaskInfo2 = createTaskInfoForBacklinksTask();
runningTaskInfo2.userId = UserHandle.myUserId() + 1;
- when(mAtmService.getTasks(anyInt(), anyBoolean(), anyBoolean(), anyInt()))
- .thenReturn(List.of(runningTaskInfo1, runningTaskInfo2));
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO, runningTaskInfo2);
+ when(mPackageManager.loadItemIcon(runningTaskInfo2.topActivityInfo,
+ runningTaskInfo2.topActivityInfo.applicationInfo)).thenReturn(FAKE_DRAWABLE);
+ mockBacklinksTaskForMainLauncherIntent();
// Set up complete, trigger the backlinks action.
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
@@ -497,22 +466,6 @@
assertThat(actualBacklinks.get(1)).isInstanceOf(CrossProfileError.class);
}
- private void resetPackageManagerMockingForUsingFallbackBacklinks() {
- ResolveInfo backlinksTaskResolveInfo = createBacklinksTaskResolveInfo();
- reset(mPackageManager);
- when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
- when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
- // Firstly, the logic queries whether a package has a launcher activity, this should
- // resolve otherwise the logic filters out the task.
- .thenReturn(backlinksTaskResolveInfo)
- // Secondly, the logic builds a fallback main launcher intent, this should also
- // resolve for the fallback intent to build correctly.
- .thenReturn(backlinksTaskResolveInfo)
- // Lastly, logic queries with the backlinks intent, this should not resolve for the
- // logic to use the fallback intent.
- .thenReturn(null);
- }
-
private void verifyMainLauncherBacklinksIntent() {
BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
@@ -540,6 +493,59 @@
}).when(mAssistContentRequester).requestAssistContent(eq(taskId), any());
}
+ private void mockPackageManagerToResolveUri(Uri uriToResolve, ResolveInfo resolveInfoToReturn) {
+ Intent uriIntent = new Intent(ACTION_VIEW).setData(uriToResolve);
+ mockQueryIntentActivities(uriIntent, resolveInfoToReturn);
+ mockPmToLoadAppIcon(resolveInfoToReturn);
+ }
+
+ private void mockQueryIntentActivities(Intent expectedIntent, ResolveInfo resolveInfoToReturn) {
+ when(mPackageManager.queryIntentActivities(intentEquals(expectedIntent),
+ eq(MATCH_DEFAULT_ONLY)))
+ .thenReturn(List.of(resolveInfoToReturn));
+ }
+
+ private void mockBacklinksTaskForMainLauncherIntent() {
+ mockPmToResolveForMainLauncherIntent(BACKLINKS_TASK_RESOLVE_INFO);
+ }
+
+ private void mockPmToResolveForMainLauncherIntent(ResolveInfo resolveInfo) {
+ Intent intent = new Intent(ACTION_MAIN).addCategory(CATEGORY_LAUNCHER).setPackage(
+ resolveInfo.activityInfo.packageName);
+ when(mPackageManager.resolveActivity(intentEquals(intent), eq(/* flags= */ 0))).thenReturn(
+ resolveInfo);
+ mockPmToLoadAppIcon(resolveInfo);
+ }
+
+ private void mockPmToLoadAppIcon(ResolveInfo resolveInfo) {
+ when(mPackageManager.loadItemIcon(resolveInfo.activityInfo,
+ resolveInfo.activityInfo.applicationInfo)).thenReturn(FAKE_DRAWABLE);
+ }
+
+ private void mockAtmToReturnRunningTaskInfo(RunningTaskInfo... taskInfos)
+ throws RemoteException {
+ when(mAtmService.getTasks(Integer.MAX_VALUE, /* filterOnlyVisibleRecents= */
+ false, /* keepIntentExtras= */ false, DEFAULT_DISPLAY)).thenReturn(
+ List.of(taskInfos));
+ }
+
+ private static Intent intentEquals(Intent intent) {
+ return argThat(new IntentMatcher(intent));
+ }
+
+ private static class IntentMatcher implements ArgumentMatcher<Intent> {
+ private final Intent mExpectedIntent;
+
+ IntentMatcher(Intent expectedIntent) {
+ mExpectedIntent = expectedIntent;
+ }
+
+ @Override
+ public boolean matches(Intent actualIntent) {
+ return actualIntent != null && mExpectedIntent.filterEquals(actualIntent);
+ }
+ }
+
private static ResolveInfo createBacklinksTaskResolveInfo() {
ActivityInfo activityInfo = new ActivityInfo();
activityInfo.applicationInfo = new ApplicationInfo();
@@ -558,7 +564,7 @@
taskInfo.isRunning = true;
taskInfo.numActivities = 1;
taskInfo.topActivity = new ComponentName(BACKLINKS_TASK_PACKAGE_NAME, "backlinksClass");
- taskInfo.topActivityInfo = createBacklinksTaskResolveInfo().activityInfo;
+ taskInfo.topActivityInfo = BACKLINKS_TASK_RESOLVE_INFO.activityInfo;
taskInfo.baseIntent = new Intent().setComponent(taskInfo.topActivity);
taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
taskInfo.userId = UserHandle.myUserId();
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6daf0d0..c3d09bb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -9211,7 +9211,7 @@
index = 1;
}
- if (replaceStreamBtSco()) {
+ if (replaceStreamBtSco() && index != 0) {
index = (int) (mIndexMin + (index * 10 - mIndexMin) / getIndexStepFactor() + 5)
/ 10;
}
diff --git a/services/core/java/com/android/server/input/debug/TouchpadDebugView.java b/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
index 486d4af..cc13e8e 100644
--- a/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
+++ b/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
@@ -16,6 +16,8 @@
package com.android.server.input.debug;
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Configuration;
@@ -24,6 +26,7 @@
import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.util.Slog;
+import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -38,6 +41,13 @@
import java.util.Objects;
public class TouchpadDebugView extends LinearLayout {
+ private static final float MAX_SCREEN_WIDTH_PROPORTION = 0.4f;
+ private static final float MAX_SCREEN_HEIGHT_PROPORTION = 0.4f;
+ private static final float MIN_SCALE_FACTOR = 10f;
+ private static final float TEXT_SIZE_SP = 16.0f;
+ private static final float DEFAULT_RES_X = 47f;
+ private static final float DEFAULT_RES_Y = 45f;
+
/**
* Input device ID for the touchpad that this debug view is displaying.
*/
@@ -62,6 +72,7 @@
new TouchpadHardwareState(0, 0 /* buttonsDown */, 0, 0,
new TouchpadFingerState[0]);
private TouchpadVisualizationView mTouchpadVisualizationView;
+ private final TouchpadHardwareProperties mTouchpadHardwareProperties;
public TouchpadDebugView(Context context, int touchpadId,
TouchpadHardwareProperties touchpadHardwareProperties) {
@@ -69,10 +80,10 @@
mTouchpadId = touchpadId;
mWindowManager =
Objects.requireNonNull(getContext().getSystemService(WindowManager.class));
- init(context, touchpadHardwareProperties, touchpadId);
+ mTouchpadHardwareProperties = touchpadHardwareProperties;
+ init(context, touchpadId);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- // TODO(b/360137366): Use the hardware properties to initialise layout parameters.
mWindowLayoutParams = new WindowManager.LayoutParams();
mWindowLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -92,8 +103,8 @@
mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
}
- private void init(Context context, TouchpadHardwareProperties touchpadHardwareProperties,
- int touchpadId) {
+ private void init(Context context, int touchpadId) {
+ updateScreenDimensions();
setOrientation(VERTICAL);
setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT,
@@ -102,35 +113,34 @@
TextView nameView = new TextView(context);
nameView.setBackgroundColor(Color.RED);
- nameView.setTextSize(20);
+ nameView.setTextSize(TEXT_SIZE_SP);
nameView.setText(Objects.requireNonNull(Objects.requireNonNull(
mContext.getSystemService(InputManager.class))
.getInputDevice(touchpadId)).getName());
nameView.setGravity(Gravity.CENTER);
nameView.setTextColor(Color.WHITE);
- nameView.setLayoutParams(new LayoutParams(1000, 200));
+ nameView.setLayoutParams(
+ new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
mTouchpadVisualizationView = new TouchpadVisualizationView(context,
- touchpadHardwareProperties);
+ mTouchpadHardwareProperties);
mTouchpadVisualizationView.setBackgroundColor(Color.WHITE);
- //TODO(b/365568238): set the view size according to the touchpad size from the
- // TouchpadHardwareProperties
- mTouchpadVisualizationView.setLayoutParams(new LayoutParams(778, 500));
//TODO(b/365562952): Add a display for recognized gesture info here
TextView gestureInfoView = new TextView(context);
gestureInfoView.setBackgroundColor(Color.GRAY);
- gestureInfoView.setTextSize(20);
+ gestureInfoView.setTextSize(TEXT_SIZE_SP);
gestureInfoView.setText("Touchpad Debug View 3");
gestureInfoView.setGravity(Gravity.CENTER);
gestureInfoView.setTextColor(Color.BLACK);
- gestureInfoView.setLayoutParams(new LayoutParams(1000, 200));
+ gestureInfoView.setLayoutParams(
+ new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
addView(nameView);
addView(mTouchpadVisualizationView);
addView(gestureInfoView);
- updateScreenDimensions();
+ updateViewsDimensions();
}
@Override
@@ -191,6 +201,7 @@
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
updateScreenDimensions();
+ updateViewsDimensions();
// Adjust view position to stay within screen bounds after rotation
mWindowLayoutParams.x =
@@ -204,6 +215,41 @@
return deltaX * deltaX + deltaY * deltaY >= mTouchSlop * mTouchSlop;
}
+ private void updateViewsDimensions() {
+ float resX = mTouchpadHardwareProperties.getResX() == 0f ? DEFAULT_RES_X
+ : mTouchpadHardwareProperties.getResX();
+ float resY = mTouchpadHardwareProperties.getResY() == 0f ? DEFAULT_RES_Y
+ : mTouchpadHardwareProperties.getResY();
+
+ float touchpadHeightMm = Math.abs(
+ mTouchpadHardwareProperties.getBottom() - mTouchpadHardwareProperties.getTop())
+ / resY;
+ float touchpadWidthMm = Math.abs(
+ mTouchpadHardwareProperties.getLeft() - mTouchpadHardwareProperties.getRight())
+ / resX;
+
+ float maxViewWidthPx = mScreenWidth * MAX_SCREEN_WIDTH_PROPORTION;
+ float maxViewHeightPx = mScreenHeight * MAX_SCREEN_HEIGHT_PROPORTION;
+
+ float minScaleFactorPx = TypedValue.applyDimension(COMPLEX_UNIT_DIP, MIN_SCALE_FACTOR,
+ getResources().getDisplayMetrics());
+
+ float scaleFactorBasedOnWidth =
+ touchpadWidthMm * minScaleFactorPx > maxViewWidthPx ? maxViewWidthPx
+ / touchpadWidthMm : minScaleFactorPx;
+ float scaleFactorBasedOnHeight =
+ touchpadHeightMm * minScaleFactorPx > maxViewHeightPx ? maxViewHeightPx
+ / touchpadHeightMm : minScaleFactorPx;
+ float scaleFactorUsed = Math.min(scaleFactorBasedOnHeight, scaleFactorBasedOnWidth);
+
+ mTouchpadVisualizationView.setLayoutParams(
+ new LayoutParams((int) (touchpadWidthMm * scaleFactorUsed),
+ (int) (touchpadHeightMm * scaleFactorUsed)));
+
+ mTouchpadVisualizationView.updateScaleFactor(scaleFactorUsed);
+ mTouchpadVisualizationView.invalidate();
+ }
+
private void updateScreenDimensions() {
Rect windowBounds =
mWindowManager.getCurrentWindowMetrics().getBounds();
diff --git a/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java b/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
index 9ba7d0a..2ed6f44 100644
--- a/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
+++ b/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
@@ -30,8 +30,11 @@
public class TouchpadVisualizationView extends View {
private static final String TAG = "TouchpadVizMain";
private static final boolean DEBUG = true;
+ private static final float DEFAULT_RES_X = 47f;
+ private static final float DEFAULT_RES_Y = 45f;
private final TouchpadHardwareProperties mTouchpadHardwareProperties;
+ private float mScaleFactor;
TouchpadHardwareState mLatestHardwareState = new TouchpadHardwareState(0, 0, 0, 0,
new TouchpadFingerState[]{});
@@ -42,6 +45,7 @@
TouchpadHardwareProperties touchpadHardwareProperties) {
super(context);
mTouchpadHardwareProperties = touchpadHardwareProperties;
+ mScaleFactor = 1;
mOvalPaint = new Paint();
mOvalPaint.setAntiAlias(true);
mOvalPaint.setARGB(255, 0, 0, 0);
@@ -73,14 +77,16 @@
mTouchpadHardwareProperties.getBottom(), 0, getHeight(),
touchpadFingerState.getPositionY());
- float newAngle = -translateRange(mTouchpadHardwareProperties.getOrientationMinimum(),
- mTouchpadHardwareProperties.getOrientationMaximum(), 0, 360,
- touchpadFingerState.getOrientation());
+ float newAngle = translateRange(0, mTouchpadHardwareProperties.getOrientationMaximum(),
+ 0, 90, touchpadFingerState.getOrientation());
- float newTouchMajor =
- touchpadFingerState.getTouchMajor() / mTouchpadHardwareProperties.getResX();
- float newTouchMinor =
- touchpadFingerState.getTouchMinor() / mTouchpadHardwareProperties.getResY();
+ float resX = mTouchpadHardwareProperties.getResX() == 0f ? DEFAULT_RES_X
+ : mTouchpadHardwareProperties.getResX();
+ float resY = mTouchpadHardwareProperties.getResY() == 0f ? DEFAULT_RES_Y
+ : mTouchpadHardwareProperties.getResY();
+
+ float newTouchMajor = touchpadFingerState.getTouchMajor() * mScaleFactor / resY;
+ float newTouchMinor = touchpadFingerState.getTouchMinor() * mScaleFactor / resX;
drawOval(canvas, newX, newY, newTouchMajor, newTouchMinor, newAngle, mOvalPaint);
}
@@ -101,6 +107,15 @@
invalidate();
}
+ /**
+ * Update the scale factor of the drawings in the view.
+ *
+ * @param scaleFactor the new scale factor
+ */
+ public void updateScaleFactor(float scaleFactor) {
+ mScaleFactor = scaleFactor;
+ }
+
private float translateRange(float rangeBeforeMin, float rangeBeforeMax,
float rangeAfterMin, float rangeAfterMax, float value) {
return rangeAfterMin + (value - rangeBeforeMin) / (rangeBeforeMax - rangeBeforeMin) * (
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f52a74f..8c23eaa 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2641,7 +2641,7 @@
return true;
}
// Only do transfer after transaction has done when starting window exist.
- if (mStartingData != null && mStartingData.mWaitForSyncTransactionCommit) {
+ if (mStartingData != null && mStartingData.mWaitForSyncTransactionCommitCount > 0) {
mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_COPY_TO_CLIENT;
return true;
}
@@ -2804,9 +2804,11 @@
@Override
void waitForSyncTransactionCommit(ArraySet<WindowContainer> wcAwaitingCommit) {
+ // Only add once per transition.
+ final boolean added = wcAwaitingCommit.contains(this);
super.waitForSyncTransactionCommit(wcAwaitingCommit);
- if (mStartingData != null) {
- mStartingData.mWaitForSyncTransactionCommit = true;
+ if (!added && mStartingData != null) {
+ mStartingData.mWaitForSyncTransactionCommitCount++;
}
}
@@ -2817,7 +2819,7 @@
return;
}
final StartingData lastData = mStartingData;
- lastData.mWaitForSyncTransactionCommit = false;
+ lastData.mWaitForSyncTransactionCommitCount--;
if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_REMOVE_DIRECTLY) {
removeStartingWindowAnimation(lastData.mPrepareRemoveAnimation);
} else if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_COPY_TO_CLIENT) {
@@ -2847,7 +2849,7 @@
final boolean animate;
final boolean hasImeSurface;
if (mStartingData != null) {
- if (mStartingData.mWaitForSyncTransactionCommit
+ if (mStartingData.mWaitForSyncTransactionCommitCount > 0
|| mSyncState != SYNC_STATE_NONE) {
mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_REMOVE_DIRECTLY;
mStartingData.mPrepareRemoveAnimation = prepareAnimation;
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 24fb207..22c7e8c 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -69,7 +69,7 @@
* Note this isn't equal to transition playing, the period should be
* Sync finishNow -> Start transaction apply.
*/
- boolean mWaitForSyncTransactionCommit;
+ int mWaitForSyncTransactionCommitCount;
/**
* For Shell transition.
@@ -112,7 +112,7 @@
public String toString() {
return getClass().getSimpleName() + "{"
+ Integer.toHexString(System.identityHashCode(this))
- + " waitForSyncTransactionCommit=" + mWaitForSyncTransactionCommit
+ + " mWaitForSyncTransactionCommitCount=" + mWaitForSyncTransactionCommitCount
+ " removeAfterTransaction= " + mRemoveAfterTransaction
+ "}";
}
diff --git a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
index 99e04cc..0719686 100644
--- a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
+++ b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
@@ -85,8 +85,8 @@
when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
mTouchpadDebugView = new TouchpadDebugView(mTestableContext, TOUCHPAD_DEVICE_ID,
- new TouchpadHardwareProperties.Builder(500f, 500f, 500f,
- 500f, 0f, 0f, -5f, 5f, (short) 10, true,
+ new TouchpadHardwareProperties.Builder(0f, 0f, 500f,
+ 500f, 45f, 47f, -4f, 5f, (short) 10, true,
true).build());
mTouchpadDebugView.measure(