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

Commit 8eedb5ad authored by arangelov's avatar arangelov Committed by android-build-merger
Browse files

Merge "No disclaimer when switching profile for system SMS and dialer apps."...

Merge "No disclaimer when switching profile for system SMS and dialer apps." into pi-dev am: a7a496f3
am: 487ca863

Change-Id: I7d5a8a2e2784adc31ae0f366cf81650819228007
parents e69a4919 487ca863
Loading
Loading
Loading
Loading
+60 −20
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.internal.app;

import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;

import android.annotation.Nullable;
import android.annotation.StringRes;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -23,8 +27,11 @@ import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.admin.DevicePolicyManager;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.RemoteException;
@@ -32,12 +39,11 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
import android.widget.Toast;

import com.android.internal.annotations.VisibleForTesting;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
import java.util.Set;

/**
 * This is used in conjunction with
@@ -45,7 +51,6 @@ import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
 * be passed in and out of a managed profile.
 */
public class IntentForwarderActivity extends Activity  {

    public static String TAG = "IntentForwarderActivity";

    public static String FORWARD_INTENT_TO_PARENT
@@ -54,6 +59,9 @@ public class IntentForwarderActivity extends Activity {
    public static String FORWARD_INTENT_TO_MANAGED_PROFILE
            = "com.android.internal.app.ForwardIntentToManagedProfile";

    private static final Set<String> ALLOWED_TEXT_MESSAGE_SCHEME
            = new HashSet<>(Arrays.asList("sms", "smsto", "mms", "mmsto"));

    private Injector mInjector;

    @Override
@@ -94,19 +102,8 @@ public class IntentForwarderActivity extends Activity {
                newIntent.prepareToLeaveUser(callingUserId);
            }

            final android.content.pm.ResolveInfo ri =
                    mInjector.getPackageManager().resolveActivityAsUser(
                            newIntent,
                            MATCH_DEFAULT_ONLY,
            final ResolveInfo ri = mInjector.resolveActivityAsUser(newIntent, MATCH_DEFAULT_ONLY,
                    targetUserId);

            // Don't show the disclosure if next activity is ResolverActivity or ChooserActivity
            // as those will already have shown work / personal as neccesary etc.
            final boolean shouldShowDisclosure = ri == null || ri.activityInfo == null ||
                    !"android".equals(ri.activityInfo.packageName) ||
                    !(ResolverActivity.class.getName().equals(ri.activityInfo.name)
                            || ChooserActivity.class.getName().equals(ri.activityInfo.name));

            try {
                startActivityAsCaller(newIntent, null, false, targetUserId);
            } catch (RuntimeException e) {
@@ -125,8 +122,8 @@ public class IntentForwarderActivity extends Activity {
                        + ActivityThread.currentProcessName(), e);
            }

            if (shouldShowDisclosure) {
                Toast.makeText(this, getString(userMessageId), Toast.LENGTH_LONG).show();
            if (shouldShowDisclosure(ri, intentReceived)) {
                mInjector.showToast(userMessageId, Toast.LENGTH_LONG);
            }
        } else {
            Slog.wtf(TAG, "the intent: " + intentReceived + " cannot be forwarded from user "
@@ -135,6 +132,35 @@ public class IntentForwarderActivity extends Activity {
        finish();
    }

    private boolean shouldShowDisclosure(@Nullable ResolveInfo ri, Intent intent) {
        if (ri == null || ri.activityInfo == null) {
            return true;
        }
        if (ri.activityInfo.applicationInfo.isSystemApp()
                && (isDialerIntent(intent) || isTextMessageIntent(intent))) {
            return false;
        }
        return !isTargetResolverOrChooserActivity(ri.activityInfo);
    }

    private boolean isTextMessageIntent(Intent intent) {
        return Intent.ACTION_SENDTO.equals(intent.getAction()) && intent.getData() != null
            && ALLOWED_TEXT_MESSAGE_SCHEME.contains(intent.getData().getScheme());
    }

    private boolean isDialerIntent(Intent intent) {
        return Intent.ACTION_DIAL.equals(intent.getAction())
            || Intent.ACTION_CALL.equals(intent.getAction());
    }

    private boolean isTargetResolverOrChooserActivity(ActivityInfo activityInfo) {
        if (!"android".equals(activityInfo.packageName)) {
            return false;
        }
        return ResolverActivity.class.getName().equals(activityInfo.name)
            || ChooserActivity.class.getName().equals(activityInfo.name);
    }

    /**
     * Check whether the intent can be forwarded to target user. Return the intent used for
     * forwarding if it can be forwarded, {@code null} otherwise.
@@ -242,6 +268,16 @@ public class IntentForwarderActivity extends Activity {
        public PackageManager getPackageManager() {
            return IntentForwarderActivity.this.getPackageManager();
        }

        @Override
        public ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId) {
            return getPackageManager().resolveActivityAsUser(intent, flags, userId);
        }

        @Override
        public void showToast(int messageId, int duration) {
            Toast.makeText(IntentForwarderActivity.this, getString(messageId), duration).show();
        }
    }

    public interface Injector {
@@ -250,5 +286,9 @@ public class IntentForwarderActivity extends Activity {
        UserManager getUserManager();

        PackageManager getPackageManager();

        ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId);

        void showToast(@StringRes int messageId, int duration);
    }
}
+186 −19
Original line number Diff line number Diff line
@@ -16,46 +16,50 @@

package com.android.internal.app;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
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.ArgumentMatchers.nullable;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.List;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
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.ArgumentMatchers.nullable;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(AndroidJUnit4.class)
public class IntentForwarderActivityTest {

    private static final ComponentName FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME =
            new ComponentName(
                    "android",
@@ -77,22 +81,26 @@ public class IntentForwarderActivityTest {

    private static IntentForwarderActivity.Injector sInjector;
    private static ComponentName sComponentName;
    private static String sActivityName;
    private static String sPackageName;

    @Mock private IPackageManager mIPm;
    @Mock private PackageManager mPm;
    @Mock private UserManager mUserManager;
    @Mock private ApplicationInfo mApplicationInfo;

    @Rule
    public ActivityTestRule<IntentForwarderWrapperActivity> mActivityRule =
            new ActivityTestRule<>(IntentForwarderWrapperActivity.class, true, false);

    private Context mContext;
    public static final String PHONE_NUMBER = "123-456-789";

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mContext = InstrumentationRegistry.getTargetContext();
        sInjector = new TestInjector();
        sInjector = spy(new TestInjector());
    }

    @Test
@@ -252,6 +260,149 @@ public class IntentForwarderActivityTest {
        assertEquals(MANAGED_PROFILE_INFO.id, activity.mUserIdActivityLaunchedIn);
    }

    @Test
    public void shouldSkipDisclosure_notWhitelisted() throws RemoteException {
        setupShouldSkipDisclosureTest();
        Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
            .setAction(Intent.ACTION_SEND)
            .setType(TYPE_PLAIN_TEXT);

        mActivityRule.launchActivity(intent);

        verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
        verify(sInjector).showToast(anyInt(), anyInt());
    }

    @Test
    public void shouldSkipDisclosure_withResolverActivity() throws RemoteException {
        setupShouldSkipDisclosureTest();
        sActivityName = ResolverActivity.class.getName();
        sPackageName = "android";
        Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
            .setAction(Intent.ACTION_SEND)
            .setType(TYPE_PLAIN_TEXT);

        mActivityRule.launchActivity(intent);

        verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
        verify(sInjector, never()).showToast(anyInt(), anyInt());
    }

    @Test
    public void shouldSkipDisclosure_callIntent_call() throws RemoteException {
        setupShouldSkipDisclosureTest();
        Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
            .setAction(Intent.ACTION_CALL);

        mActivityRule.launchActivity(intent);

        verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
        verify(sInjector, never()).showToast(anyInt(), anyInt());
    }

    @Test
    public void shouldSkipDisclosure_callIntent_dial() throws RemoteException {
        setupShouldSkipDisclosureTest();
        Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
            .setAction(Intent.ACTION_DIAL);

        mActivityRule.launchActivity(intent);

        verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
        verify(sInjector, never()).showToast(anyInt(), anyInt());
    }

    @Test
    public void shouldSkipDisclosure_callIntent_notCallOrDial() throws RemoteException {
        setupShouldSkipDisclosureTest();
        Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
            .setAction(Intent.ACTION_ALARM_CHANGED);

        mActivityRule.launchActivity(intent);

        verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
        verify(sInjector).showToast(anyInt(), anyInt());
    }

    @Test
    public void shouldSkipDisclosure_textMessageIntent_sms() throws RemoteException {
        setupShouldSkipDisclosureTest();
        Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
            .setAction(Intent.ACTION_SENDTO)
            .setData(Uri.fromParts("sms", PHONE_NUMBER, null));

        mActivityRule.launchActivity(intent);

        verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
        verify(sInjector, never()).showToast(anyInt(), anyInt());
    }

    @Test
    public void shouldSkipDisclosure_textMessageIntent_smsto() throws RemoteException {
        setupShouldSkipDisclosureTest();
        Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
            .setAction(Intent.ACTION_SENDTO)
            .setData(Uri.fromParts("smsto", PHONE_NUMBER, null));

        mActivityRule.launchActivity(intent);

        verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
        verify(sInjector, never()).showToast(anyInt(), anyInt());
    }

    @Test
    public void shouldSkipDisclosure_textMessageIntent_mms() throws RemoteException {
        setupShouldSkipDisclosureTest();
        Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
            .setAction(Intent.ACTION_SENDTO)
            .setData(Uri.fromParts("mms", PHONE_NUMBER, null));

        mActivityRule.launchActivity(intent);

        verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
        verify(sInjector, never()).showToast(anyInt(), anyInt());
    }

    @Test
    public void shouldSkipDisclosure_textMessageIntent_mmsto() throws RemoteException {
        setupShouldSkipDisclosureTest();
        Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
            .setAction(Intent.ACTION_SENDTO)
            .setData(Uri.fromParts("mmsto", PHONE_NUMBER, null));

        mActivityRule.launchActivity(intent);

        verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
        verify(sInjector, never()).showToast(anyInt(), anyInt());
    }

    @Test
    public void shouldSkipDisclosure_textMessageIntent_invalidUri() throws RemoteException {
        setupShouldSkipDisclosureTest();
        Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
            .setAction(Intent.ACTION_SENDTO)
            .setData(Uri.fromParts("invalid", PHONE_NUMBER, null));

        mActivityRule.launchActivity(intent);

        verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
        verify(sInjector).showToast(anyInt(), anyInt());
    }

    private void setupShouldSkipDisclosureTest() throws RemoteException {
        sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
        sActivityName = "MyTestActivity";
        sPackageName = "test.package.name";
        when(mApplicationInfo.isSystemApp()).thenReturn(true);
        // Managed profile exists.
        List<UserInfo> profiles = new ArrayList<>();
        profiles.add(CURRENT_USER_INFO);
        profiles.add(MANAGED_PROFILE_INFO);
        when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
        // Intent can be forwarded.
        when(mIPm.canForwardTo(
            any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
    }

    public static class IntentForwarderWrapperActivity extends IntentForwarderActivity {
        private Intent mStartActivityIntent;
@@ -276,7 +427,7 @@ public class IntentForwarderActivityTest {
        }
    }

    class TestInjector implements IntentForwarderActivity.Injector {
    public class TestInjector implements IntentForwarderActivity.Injector {

        @Override
        public IPackageManager getIPackageManager() {
@@ -292,5 +443,21 @@ public class IntentForwarderActivityTest {
        public PackageManager getPackageManager() {
            return mPm;
        }

        @Override
        public ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId) {
            ActivityInfo activityInfo = new ActivityInfo();
            activityInfo.packageName = sPackageName;
            activityInfo.name = sActivityName;
            activityInfo.applicationInfo = mApplicationInfo;

            ResolveInfo resolveInfo = new ResolveInfo();
            resolveInfo.activityInfo = activityInfo;

            return resolveInfo;
        }

        @Override
        public void showToast(int messageId, int duration) {}
    }
}
 No newline at end of file