Add useSystemProvidedLauncherForSecondary config
- Enabling this flag allows product to use the same secondary home launcher
specified in config_secondaryHomeComponent always.
- In product like car, some secondary displays, only built-in secondary home
launcher should be used.
Bug: 131112301
Test: Run added test
Change-Id: I62ca19b0570768cdc8dc9849306d6bf16bedccc4
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2beef42..9bd56ad 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3902,6 +3902,10 @@
{@see android.view.Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS} -->
<string name="config_secondaryHomeComponent" translatable="false">com.android.launcher3/com.android.launcher3.SecondaryDisplayLauncher</string>
+ <!-- Force secondary home launcher specified in config_secondaryHomeComponent always. If this is
+ not set, secondary home launcher can be replaced by user. -->
+ <bool name ="config_useSystemProvidedLauncherForSecondary">false</bool>
+
<!-- If device supports corner radius on windows.
This should be turned off on low-end devices to improve animation performance. -->
<bool name="config_supportsRoundedCornersOnWindows">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4af05f6..3b3a062 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3699,6 +3699,7 @@
<!-- For Secondary Launcher -->
<java-symbol type="string" name="config_secondaryHomeComponent" />
+ <java-symbol type="bool" name="config_useSystemProvidedLauncherForSecondary" />
<java-symbol type="string" name="battery_saver_notification_channel_name" />
<java-symbol type="string" name="battery_saver_sticky_disabled_notification_title" />
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 765c9d0..b97ecec 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5867,8 +5867,10 @@
*/
Intent getSecondaryHomeIntent(String preferredPackage) {
final Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
- if (preferredPackage == null) {
- // Using the component stored in config if no package name.
+ final boolean useSystemProvidedLauncher = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
+ if (preferredPackage == null || useSystemProvidedLauncher) {
+ // Using the component stored in config if no package name or forced.
final String secondaryHomeComponent = mContext.getResources().getString(
com.android.internal.R.string.config_secondaryHomeComponent);
intent.setComponent(ComponentName.unflattenFromString(secondaryHomeComponent));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 0f7b35c..c77e25f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -30,6 +30,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
@@ -54,6 +55,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
@@ -601,6 +603,73 @@
}
/**
+ * Tests that the default secondary home activity is always picked when it is in forced by
+ * config_useSystemProvidedLauncherForSecondary.
+ */
+ @Test
+ public void testResolveSecondaryHomeActivityForced() throws Exception {
+ Resources resources = mContext.getResources();
+ spyOn(resources);
+ try {
+ // setUp: set secondary launcher and force it.
+ final String defaultSecondaryHome =
+ "com.android.test/com.android.test.TestDefaultSecondaryHome";
+ final ComponentName secondaryComp = ComponentName.unflattenFromString(
+ defaultSecondaryHome);
+ doReturn(defaultSecondaryHome).when(resources).getString(
+ com.android.internal.R.string.config_secondaryHomeComponent);
+ doReturn(true).when(resources).getBoolean(
+ com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
+ final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null);
+ assertEquals(secondaryComp, secondaryHomeIntent.getComponent());
+ final ActivityInfo aInfoSecondary = new ActivityInfo();
+ aInfoSecondary.name = secondaryComp.getClassName();
+ aInfoSecondary.applicationInfo = new ApplicationInfo();
+ aInfoSecondary.applicationInfo.packageName = secondaryComp.getPackageName();
+ doReturn(aInfoSecondary).when(mRootActivityContainer).resolveHomeActivity(anyInt(),
+ refEq(secondaryHomeIntent));
+ final Intent homeIntent = mService.getHomeIntent();
+ final ActivityInfo aInfoDefault = new ActivityInfo();
+ aInfoDefault.name = "fakeHomeActivity";
+ aInfoDefault.applicationInfo = new ApplicationInfo();
+ aInfoDefault.applicationInfo.packageName = "fakeHomePackage";
+ doReturn(aInfoDefault).when(mRootActivityContainer).resolveHomeActivity(anyInt(),
+ refEq(homeIntent));
+ // Let resolveActivities call to validate both main launcher and second launcher so that
+ // resolveActivities call does not work as enabler for secondary.
+ final List<ResolveInfo> resolutions1 = new ArrayList<>();
+ final ResolveInfo resolveInfo1 = new ResolveInfo();
+ resolveInfo1.activityInfo = new ActivityInfo();
+ resolveInfo1.activityInfo.name = aInfoDefault.name;
+ resolveInfo1.activityInfo.applicationInfo = aInfoDefault.applicationInfo;
+ resolutions1.add(resolveInfo1);
+ doReturn(resolutions1).when(mRootActivityContainer).resolveActivities(anyInt(),
+ refEq(homeIntent));
+ final List<ResolveInfo> resolutions2 = new ArrayList<>();
+ final ResolveInfo resolveInfo2 = new ResolveInfo();
+ resolveInfo2.activityInfo = new ActivityInfo();
+ resolveInfo2.activityInfo.name = aInfoSecondary.name;
+ resolveInfo2.activityInfo.applicationInfo = aInfoSecondary.applicationInfo;
+ resolutions2.add(resolveInfo2);
+ doReturn(resolutions2).when(mRootActivityContainer).resolveActivities(anyInt(),
+ refEq(secondaryHomeIntent));
+ doReturn(true).when(mRootActivityContainer).canStartHomeOnDisplay(
+ any(), anyInt(), anyBoolean());
+
+ // Run the test
+ final Pair<ActivityInfo, Intent> resolvedInfo = mRootActivityContainer
+ .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
+ assertEquals(secondaryComp.getClassName(), resolvedInfo.first.name);
+ assertEquals(secondaryComp.getPackageName(),
+ resolvedInfo.first.applicationInfo.packageName);
+ assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
+ } finally {
+ // tearDown
+ reset(resources);
+ }
+ }
+
+ /**
* Tests that secondary home should be selected if default home not support secondary displays
* or there is no matched activity in the same package as selected default home.
*/