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

Commit 0446fab7 authored by Susi Kharraz-Post's avatar Susi Kharraz-Post
Browse files

Add logging for profile switching for sharesheet

We want to know which profile people share from and if users are
switching from work to personal profile when sharing and vice versa.
This adds the current profile to the sharesheet and also logs when the
profile is switched.

Bug: 124503277
Test: Added new unit tests for ChooserActivity and IntentForwardActivity
Change-Id: Ideb83682bf3395258ff457988f4a3e9f519a844c
parent 4c5bfd24
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -381,6 +381,8 @@ public class ChooserActivity extends ResolverActivity {
        final long systemCost = mChooserShownTime - intentReceivedTime;

        getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN)
                .setSubtype(isWorkProfile() ? MetricsEvent.MANAGED_PROFILE :
                        MetricsEvent.PARENT_PROFILE)
                .addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType())
                .addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost));

@@ -417,6 +419,16 @@ public class ChooserActivity extends ResolverActivity {
        }
    }

    /**
     * Check if the profile currently used is a work profile.
     * @return true if it is work profile, false if it is parent profile (or no work profile is
     * set up)
     */
    protected boolean isWorkProfile() {
        return ((UserManager) getSystemService(Context.USER_SERVICE))
                .getUserInfo(UserHandle.myUserId()).isManagedProfile();
    }

    /**
     * Override method to add content preview area, specific to the chooser activity.
     */
+20 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.metrics.LogMaker;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -39,6 +40,8 @@ import android.util.Slog;
import android.widget.Toast;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;

import java.util.Arrays;
import java.util.HashSet;
@@ -66,6 +69,8 @@ public class IntentForwarderActivity extends Activity {

    private Injector mInjector;

    private MetricsLogger mMetricsLogger;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
@@ -78,9 +83,17 @@ public class IntentForwarderActivity extends Activity {
        if (className.equals(FORWARD_INTENT_TO_PARENT)) {
            userMessageId = com.android.internal.R.string.forward_intent_to_owner;
            targetUserId = getProfileParent();

            getMetricsLogger().write(
                    new LogMaker(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE)
                    .setSubtype(MetricsEvent.PARENT_PROFILE));
        } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
            userMessageId = com.android.internal.R.string.forward_intent_to_work;
            targetUserId = getManagedProfile();

            getMetricsLogger().write(
                    new LogMaker(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE)
                    .setSubtype(MetricsEvent.MANAGED_PROFILE));
        } else {
            Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
            userMessageId = -1;
@@ -257,6 +270,13 @@ public class IntentForwarderActivity extends Activity {
        intent.setComponent(null);
    }

    protected MetricsLogger getMetricsLogger() {
        if (mMetricsLogger == null) {
            mMetricsLogger = new MetricsLogger();
        }
        return mMetricsLogger;
    }

    @VisibleForTesting
    protected Injector createInjector() {
        return new InjectorImpl();
+38 −8
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ import androidx.test.rule.ActivityTestRule;
import com.android.internal.R;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;

import org.junit.Before;
import org.junit.Rule;
@@ -524,15 +524,45 @@ public class ChooserActivityTest {
        waitForIdle();
        verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
        assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
                is(MetricsProto.MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
                is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
        assertThat(logMakerCaptor
                .getAllValues().get(0)
                .getTaggedData(MetricsProto.MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
                .getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
                is(notNullValue()));
        assertThat(logMakerCaptor
                .getAllValues().get(0)
                .getTaggedData(MetricsProto.MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
                .getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
                is("TestType"));
        assertThat(logMakerCaptor
                        .getAllValues().get(0)
                        .getSubtype(),
                is(MetricsEvent.PARENT_PROFILE));
    }

    @Test
    public void testOnCreateLoggingFromWorkProfile() {
        Intent sendIntent = createSendTextIntent();
        sendIntent.setType("TestType");
        sOverrides.alternateProfileSetting = MetricsEvent.MANAGED_PROFILE;
        MetricsLogger mockLogger = sOverrides.metricsLogger;
        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
        mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test"));
        waitForIdle();
        verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
        assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
                is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
        assertThat(logMakerCaptor
                        .getAllValues().get(0)
                        .getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
                is(notNullValue()));
        assertThat(logMakerCaptor
                        .getAllValues().get(0)
                        .getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
                is("TestType"));
        assertThat(logMakerCaptor
                        .getAllValues().get(0)
                        .getSubtype(),
                is(MetricsEvent.MANAGED_PROFILE));
    }

    @Test
@@ -547,7 +577,7 @@ public class ChooserActivityTest {
        verify(mockLogger, Mockito.times(1)).write(logMakerCaptor.capture());
        // First invocation is from onCreate
        assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
                is(MetricsProto.MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
                is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
    }

    @Test
@@ -569,7 +599,7 @@ public class ChooserActivityTest {
        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
        // First invocation is from onCreate
        assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
                is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
                is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
        assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
                is(CONTENT_PREVIEW_TEXT));
    }
@@ -599,11 +629,11 @@ public class ChooserActivityTest {
        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
        // First invocation is from onCreate
        assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
                is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
                is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
        assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
                is(CONTENT_PREVIEW_IMAGE));
        assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
                is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
                is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
        assertThat(logMakerCaptor.getAllValues().get(2).getSubtype(),
                is(CONTENT_PREVIEW_IMAGE));
    }
+11 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.net.Uri;
import android.util.Size;

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

import java.util.function.Function;

@@ -112,6 +113,14 @@ public class ChooserWrapperActivity extends ChooserActivity {
        return super.queryResolver(resolver, uri);
    }

    @Override
    protected boolean isWorkProfile() {
        if (sOverrides.alternateProfileSetting != 0) {
            return sOverrides.alternateProfileSetting == MetricsEvent.MANAGED_PROFILE;
        }
        return super.isWorkProfile();
    }

    /**
     * We cannot directly mock the activity created since instrumentation creates it.
     * <p>
@@ -128,6 +137,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
        public boolean resolverForceException;
        public Bitmap previewThumbnail;
        public MetricsLogger metricsLogger;
        public int alternateProfileSetting;

        public void reset() {
            onSafelyStartCallback = null;
@@ -139,6 +149,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
            resolverForceException = false;
            resolverListController = mock(ResolverListController.class);
            metricsLogger = mock(MetricsLogger.class);
            alternateProfileSetting = 0;
        }
    }
}
+70 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ 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.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -40,6 +41,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
@@ -51,6 +53,9 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;

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

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -70,6 +75,11 @@ public class IntentForwarderActivityTest {
                    "android",
                    IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE
            );
    private static final ComponentName FORWARD_TO_PARENT_COMPONENT_NAME =
            new ComponentName(
                    "android",
                    IntentForwarderActivity.FORWARD_INTENT_TO_PARENT
            );
    private static final String TYPE_PLAIN_TEXT = "text/plain";

    private static UserInfo MANAGED_PROFILE_INFO = new UserInfo();
@@ -522,6 +532,60 @@ public class IntentForwarderActivityTest {
        verify(sInjector).showToast(anyInt(), anyInt());
    }

    @Test
    public void forwardToManagedProfile_LoggingTest() throws Exception {
        sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;

        // Intent can be forwarded.
        when(mIPm.canForwardTo(
                any(Intent.class), nullable(String.class), anyInt(), anyInt())).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 intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
        intent.setAction(Intent.ACTION_SEND);
        intent.setType(TYPE_PLAIN_TEXT);
        IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);

        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
        verify(activity.getMetricsLogger()).write(logMakerCaptor.capture());
        assertEquals(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE,
                logMakerCaptor.getValue().getCategory());
        assertEquals(MetricsEvent.MANAGED_PROFILE,
                logMakerCaptor.getValue().getSubtype());
    }

    @Test
    public void forwardToParent_LoggingTest() throws Exception {
        sComponentName = FORWARD_TO_PARENT_COMPONENT_NAME;

        // Intent can be forwarded.
        when(mIPm.canForwardTo(
                any(Intent.class), nullable(String.class), anyInt(), anyInt())).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 intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
        intent.setAction(Intent.ACTION_SEND);
        intent.setType(TYPE_PLAIN_TEXT);
        IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);

        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
        verify(activity.getMetricsLogger()).write(logMakerCaptor.capture());
        assertEquals(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE,
                logMakerCaptor.getValue().getCategory());
        assertEquals(MetricsEvent.PARENT_PROFILE,
                logMakerCaptor.getValue().getSubtype());
    }

    private void setupShouldSkipDisclosureTest() throws RemoteException {
        sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
        sActivityName = "MyTestActivity";
@@ -541,6 +605,7 @@ public class IntentForwarderActivityTest {

        private Intent mStartActivityIntent;
        private int mUserIdActivityLaunchedIn;
        private MetricsLogger mMetricsLogger = mock(MetricsLogger.class);

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -559,6 +624,11 @@ public class IntentForwarderActivityTest {
            mStartActivityIntent = intent;
            mUserIdActivityLaunchedIn = userId;
        }

        @Override
        protected MetricsLogger getMetricsLogger() {
            return mMetricsLogger;
        }
    }

    public class TestInjector implements IntentForwarderActivity.Injector {
Loading