From 013c72e38ad4544888aeb53b8f87a88acf5eac28 Mon Sep 17 00:00:00 2001 From: Liahav Eitan Date: Fri, 3 Feb 2023 14:59:28 +0000 Subject: [PATCH] Ask for user consent before resolving personal intent in work profile Bug: 262700480 Test: manual, see screencasts on bug Change-Id: I32a8960d0a59f26752ad838ba6c3aee3c4d64be0 (cherry picked from commit 13b8f773507cdbe7d70eccf25bd51ee275cb13bd) Merged-In: I32a8960d0a59f26752ad838ba6c3aee3c4d64be0 --- .../internal/app/IntentForwarderActivity.java | 56 +++++++++++++++++-- core/res/AndroidManifest.xml | 5 +- core/res/res/layout/miniresolver.xml | 6 ++ .../app/IntentForwarderActivityTest.java | 35 +++++++++++- 4 files changed, 95 insertions(+), 7 deletions(-) diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index 47b83be35f87e..ae192a4effc74 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -45,8 +45,13 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.Slog; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; import android.widget.Toast; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -151,17 +156,60 @@ public class IntentForwarderActivity extends Activity { if (isResolverActivityResolveInfo(targetResolveInfo)) { launchResolverActivityWithCorrectTab(intentReceived, className, newIntent, callingUserId, targetUserId); - return targetResolveInfo; + // When switching to the personal profile, automatically start the activity + } else if (className.equals(FORWARD_INTENT_TO_PARENT)) { + startActivityAsCaller(newIntent, targetUserId); } - startActivityAsCaller(newIntent, targetUserId); return targetResolveInfo; }, mExecutorService) .thenAcceptAsync(result -> { - maybeShowDisclosure(intentReceived, result, userMessage); - finish(); + // When switching to the personal profile, inform user after starting activity + if (className.equals(FORWARD_INTENT_TO_PARENT)) { + maybeShowDisclosure(intentReceived, result, userMessage); + finish(); + // When switching to the work profile, ask the user for consent before launching + } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) { + maybeShowUserConsentMiniResolver(result, newIntent, targetUserId); + } }, getApplicationContext().getMainExecutor()); } + private void maybeShowUserConsentMiniResolver( + ResolveInfo target, Intent launchIntent, int targetUserId) { + if (target == null || isIntentForwarderResolveInfo(target) || !isDeviceProvisioned()) { + finish(); + return; + } + + int layoutId = R.layout.miniresolver; + setContentView(layoutId); + + findViewById(R.id.title_container).setElevation(0); + + ImageView icon = findViewById(R.id.icon); + PackageManager packageManagerForTargetUser = + createContextAsUser(UserHandle.of(targetUserId), /* flags= */ 0) + .getPackageManager(); + icon.setImageDrawable(target.loadIcon(packageManagerForTargetUser)); + + View buttonContainer = findViewById(R.id.button_bar_container); + buttonContainer.setPadding(0, 0, 0, buttonContainer.getPaddingBottom()); + + ((TextView) findViewById(R.id.open_cross_profile)).setText( + getResources().getString( + R.string.miniresolver_open_in_work, + target.loadLabel(packageManagerForTargetUser))); + + // The mini-resolver's negative button is reused in this flow to cancel the intent + ((Button) findViewById(R.id.use_same_profile_browser)).setText(R.string.cancel); + findViewById(R.id.use_same_profile_browser).setOnClickListener(v -> finish()); + + findViewById(R.id.button_open).setOnClickListener(v -> { + startActivityAsCaller(launchIntent, targetUserId); + finish(); + }); + } + private String getForwardToPersonalMessage() { return getSystemService(DevicePolicyManager.class).getResources().getString( FORWARD_INTENT_TO_PERSONAL, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index e2431221d9959..c8335535cc390 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -7695,8 +7695,11 @@ + + intentCaptor = ArgumentCaptor.forClass(Intent.class); @@ -271,6 +289,13 @@ public class IntentForwarderActivityTest { intentCaptor.capture(), nullable(String.class), anyInt(), anyInt()); assertEquals(Intent.ACTION_VIEW, intentCaptor.getValue().getAction()); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + onView(withId(R.id.icon)).check(matches(isDisplayed())); + onView(withId(R.id.open_cross_profile)).check(matches(isDisplayed())); + onView(withId(R.id.use_same_profile_browser)).check(matches(isDisplayed())); + onView(withId(R.id.button_open)).perform(click()); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + assertNotNull(activity.mStartActivityIntent); assertEquals(Intent.ACTION_MAIN, activity.mStartActivityIntent.getAction()); assertNull(activity.mStartActivityIntent.getPackage()); @@ -608,7 +633,7 @@ public class IntentForwarderActivityTest { } private void setupShouldSkipDisclosureTest() throws RemoteException { - sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME; + sComponentName = FORWARD_TO_PARENT_COMPONENT_NAME; sActivityName = "MyTestActivity"; sPackageName = "test.package.name"; Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, @@ -619,6 +644,7 @@ public class IntentForwarderActivityTest { profiles.add(CURRENT_USER_INFO); profiles.add(MANAGED_PROFILE_INFO); when(mUserManager.getProfiles(anyInt())).thenReturn(profiles); + when(mUserManager.getProfileParent(anyInt())).thenReturn(CURRENT_USER_INFO); // Intent can be forwarded. when(mIPm.canForwardTo( any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true); @@ -653,6 +679,11 @@ public class IntentForwarderActivityTest { mUserIdActivityLaunchedIn = userId; } + @Override + public Context createContextAsUser(UserHandle user, int flags) { + return this; + } + @Override protected MetricsLogger getMetricsLogger() { return mMetricsLogger;