Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 013c72e3 authored by Liahav Eitan's avatar Liahav Eitan Committed by Cherrypicker Worker
Browse files

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 13b8f773)
Merged-In: I32a8960d0a59f26752ad838ba6c3aee3c4d64be0
parent fd5af1b0
Loading
Loading
Loading
Loading
+52 −4
Original line number Diff line number Diff line
@@ -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);
                    }
                    return targetResolveInfo;
                }, mExecutorService)
                .thenAcceptAsync(result -> {
                    // 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,
+4 −1
Original line number Diff line number Diff line
@@ -7695,8 +7695,11 @@
        </activity>
        <activity android:name="com.android.internal.app.IntentForwarderActivity"
                android:finishOnCloseSystemDialogs="true"
                android:theme="@style/Theme.Translucent.NoTitleBar"
                android:theme="@style/Theme.DeviceDefault.Resolver"
                android:excludeFromRecents="true"
                android:documentLaunchMode="never"
                android:relinquishTaskIdentity="true"
                android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
                android:label="@string/user_owner_label"
                android:exported="true"
                android:visibleToInstantApps="true"
+6 −0
Original line number Diff line number Diff line
@@ -14,6 +14,11 @@
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<!-- Layout used to decide whether to launch a single target in another profile.
     When this layout is used in ResolverActivity, the user can choose between a verified app in the
     other profile and the default browser in the current profile.
     In IntentForwarderActivity, they choose whether to launch in the other profile or cancel. -->
<com.android.internal.widget.ResolverDrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
@@ -24,6 +29,7 @@
    android:id="@id/contentPanel">

    <RelativeLayout
        android:id="@+id/title_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alwaysShow="true"
+33 −2
Original line number Diff line number Diff line
@@ -16,6 +16,12 @@

package com.android.internal.app;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
@@ -53,6 +59,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;

import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;

@@ -140,6 +147,8 @@ public class IntentForwarderActivityTest {
    @Test
    public void forwardToManagedProfile_canForward_sendIntent() throws Exception {
        sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
        sActivityName = "MyTestActivity";
        sPackageName = "test.package.name";

        // Intent can be forwarded.
        when(mIPm.canForwardTo(
@@ -160,7 +169,13 @@ public class IntentForwarderActivityTest {
        verify(mIPm).canForwardTo(intentCaptor.capture(), eq(TYPE_PLAIN_TEXT), anyInt(), anyInt());
        assertEquals(Intent.ACTION_SEND, intentCaptor.getValue().getAction());

        assertEquals(Intent.ACTION_SEND, 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_SEND, activity.mStartActivityIntent.getAction());
        assertNull(activity.mStartActivityIntent.getPackage());
@@ -250,6 +265,8 @@ public class IntentForwarderActivityTest {
    @Test
    public void forwardToManagedProfile_canForward_selectorIntent() throws Exception {
        sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
        sActivityName = "MyTestActivity";
        sPackageName = "test.package.name";

        // Intent can be forwarded.
        when(mIPm.canForwardTo(
@@ -264,6 +281,7 @@ public class IntentForwarderActivityTest {
        // Create selector intent.
        Intent intent = Intent.makeMainSelectorActivity(
                Intent.ACTION_VIEW, Intent.CATEGORY_BROWSABLE);

        IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);

        ArgumentCaptor<Intent> 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;