From b0c011e077e34c8ef20f21fce9c3a1d78b74c046 Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Mon, 18 Dec 2023 17:05:24 +0800 Subject: [PATCH] Restart or finish HomepageActivity when it's launched unexpectedly Settings homepage should be started with the flag FLAG_ACTIVITY_NEW_TASK to ensure it's the first activity in a task. Otherwise, there will be UI issues. When homepage is started with FLAG_ACTIVITY_NEW_TASK but not the first activity, it means another homepage activity has been started, so finishing the current invocation will bring up the previous activity in the task. On the other hand, when homapage is not started with the flag and not the first activty, it indicates that the invocation is from another app. Restarting the homepage activity with FLAG_ACTIVITY_NEW_TASK will keep the UI behavior consistent. Fix: 297857732 Fix: 309045575 Test: robotest, manual 1. Start Settings from QuickSettings, go to any subpage, navigate to home, click Settings icon on the launcher, and the previously opened page should be kept. 2. On a LS device, start Settings from another app without FLAG_ACTIVITY_NEW_TASK, Settings should be started in dual-pane mode. Change-Id: If1f31e26dc37f681bd97c185cbeac2de06bdd48f --- .../homepage/SettingsHomepageActivity.java | 27 ++++++++++++- .../SettingsHomepageActivityTest.java | 38 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java index 801679992a6..48d918c0a0b 100644 --- a/src/com/android/settings/homepage/SettingsHomepageActivity.java +++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java @@ -194,8 +194,12 @@ public class SettingsHomepageActivity extends FragmentActivity implements if (unprovisioned) { Log.e(TAG, "Device is not provisioned, exiting Settings"); finish(); + return; } + // Settings homepage should be the task root, otherwise there will be UI issues. + boolean isTaskRoot = isTaskRoot(); + mIsEmbeddingActivityEnabled = ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this); if (mIsEmbeddingActivityEnabled) { final UserManager um = getSystemService(UserManager.class); @@ -211,13 +215,34 @@ public class SettingsHomepageActivity extends FragmentActivity implements } else { intent.setPackage(getPackageName()); } - intent.removeFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (!isTaskRoot) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } else { + intent.removeFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } startActivityAsUser(intent, um.getProfileParent(userInfo.id).getUserHandle()); finish(); return; } } + if (!isTaskRoot) { + if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + Log.i(TAG, "Activity has been started, finishing"); + } else { + Log.i(TAG, "Homepage should be started with FLAG_ACTIVITY_NEW_TASK, restarting"); + Intent intent = new Intent(getIntent()) + .setPackage(getPackageName()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_FORWARD_RESULT) + .putExtra(EXTRA_USER_HANDLE, getUser()) + .putExtra(EXTRA_INITIAL_REFERRER, getCurrentReferrer()); + startActivity(intent); + } + finish(); + return; + } + setupEdgeToEdge(); setContentView(R.layout.settings_homepage_container); diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java index 0d1ee9c7caa..4c2d7455745 100644 --- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java +++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java @@ -24,11 +24,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -241,6 +243,42 @@ public class SettingsHomepageActivityTest { & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0); } + @Test + public void onCreate_TaskRoot_shouldNotFinish() { + SettingsHomepageActivity activity = + spy(Robolectric.buildActivity(SettingsHomepageActivity.class).get()); + doReturn(true).when(activity).isTaskRoot(); + + activity.onCreate(/* savedInstanceState */ null); + + verify(activity, never()).finish(); + } + + @Test + public void onCreate_notTaskRoot_shouldRestartActivity() { + SettingsHomepageActivity activity = + spy(Robolectric.buildActivity(SettingsHomepageActivity.class).get()); + doReturn(false).when(activity).isTaskRoot(); + + activity.onCreate(/* savedInstanceState */ null); + + verify(activity).finish(); + verify(activity).startActivity(any(Intent.class)); + } + + @Test + public void onCreate_notTaskRoot_flagNewTask_shouldOnlyFinish() { + SettingsHomepageActivity activity = + spy(Robolectric.buildActivity(SettingsHomepageActivity.class).get()); + doReturn(false).when(activity).isTaskRoot(); + activity.setIntent(new Intent().addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + + activity.onCreate(/* savedInstanceState */ null); + + verify(activity).finish(); + verify(activity, never()).startActivity(any(Intent.class)); + } + /** This test is for large screen devices Activity embedding. */ @Test @Config(shadows = ShadowActivityEmbeddingUtils.class)