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

Commit fb3c3679 authored by Susi Kharraz-Post's avatar Susi Kharraz-Post Committed by Android (Google) Code Review
Browse files

Merge "Add logging field for direct share selection" into qt-dev

parents f43587e4 8c14f77c
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -219,6 +219,8 @@ public class ChooserActivity extends ResolverActivity {
    private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED = 4;
    private static final int LIST_VIEW_UPDATE_MESSAGE = 5;

    private static final int MAX_LOG_RANK_POSITION = 12;

    @VisibleForTesting
    public static final int LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS = 250;

@@ -1015,6 +1017,7 @@ public class ChooserActivity extends ResolverActivity {
            // Lower values mean the ranking was better.
            int cat = 0;
            int value = which;
            int directTargetAlsoRanked = -1;
            HashedStringCache.HashResult directTargetHashed = null;
            switch (mChooserListAdapter.getPositionTargetType(which)) {
                case ChooserListAdapter.TARGET_CALLER:
@@ -1034,6 +1037,7 @@ public class ChooserActivity extends ResolverActivity {
                            target.getComponentName().getPackageName()
                                    + target.getTitle().toString(),
                            mMaxHashSaltDays);
                    directTargetAlsoRanked = getRankedPosition((SelectableTargetInfo) targetInfo);
                    break;
                case ChooserListAdapter.TARGET_STANDARD:
                    cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET;
@@ -1056,6 +1060,8 @@ public class ChooserActivity extends ResolverActivity {
                    targetLogMaker.addTaggedData(
                                    MetricsEvent.FIELD_HASHED_TARGET_SALT_GEN,
                                    directTargetHashed.saltGeneration);
                    targetLogMaker.addTaggedData(MetricsEvent.FIELD_RANKED_POSITION,
                                    directTargetAlsoRanked);
                }
                getMetricsLogger().write(targetLogMaker);
                MetricsLogger.action(this, cat, value);
@@ -1074,6 +1080,21 @@ public class ChooserActivity extends ResolverActivity {
        }
    }

    private int getRankedPosition(SelectableTargetInfo targetInfo) {
        String targetPackageName =
                targetInfo.getChooserTarget().getComponentName().getPackageName();
        int maxRankedResults = Math.min(mChooserListAdapter.mDisplayList.size(),
                        MAX_LOG_RANK_POSITION);

        for (int i = 0; i < maxRankedResults; i++) {
            if (mChooserListAdapter.mDisplayList.get(i)
                    .getResolveInfo().activityInfo.packageName.equals(targetPackageName)) {
                return i;
            }
        }
        return -1;
    }

    void queryTargetServices(ChooserListAdapter adapter) {
        final PackageManager pm = getPackageManager();
        ShortcutManager sm = (ShortcutManager) getSystemService(ShortcutManager.class);
+11 −0
Original line number Diff line number Diff line
@@ -80,6 +80,17 @@ public class HashedStringCacheTest {
        assertThat(cachedResult2.hashedString, is(cachedResult.hashedString));
    }


    @Test
    public void testThatMultipleInputResultInDifferentHash() {
        HashedStringCache cache = HashedStringCache.getInstance();
        HashedStringCache.HashResult cachedResult =
                cache.hashString(mContext, TAG, TEST_STRING, 7);
        HashedStringCache.HashResult cachedResult2 =
                cache.hashString(mContext, TAG, "different_test", 7);
        assertThat(cachedResult2.hashedString, is(not(cachedResult.hashedString)));
    }

    @Test
    public void testThatZeroDaysResultsInNewHash() {
        HashedStringCache cache = HashedStringCache.getInstance();
+108 −29
Original line number Diff line number Diff line
@@ -62,9 +62,6 @@ import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;

import java.util.Arrays;
import java.util.Collection;
import java.util.function.Function;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -74,7 +71,10 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;

/**
 * Chooser activity instrumentation tests
@@ -770,8 +770,6 @@ public class ChooserActivityTest {
    }

    // This test is too long and too slow and should not be taken as an example for future tests.
    // This is necessary because it tests that multiple calls result in the same result but
    // normally a test this long should be broken into smaller tests testing individual components.
    @Test
    public void testDirectTargetSelectionLogging() throws InterruptedException {
        Intent sendIntent = createSendTextIntent();
@@ -785,7 +783,7 @@ public class ChooserActivityTest {
        MetricsLogger mockLogger = sOverrides.metricsLogger;
        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
        // Create direct share target
        List<ChooserTarget> serviceTargets = createDirectShareTargets(1);
        List<ChooserTarget> serviceTargets = createDirectShareTargets(1, "");
        ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0);

        // Start activity
@@ -832,20 +830,36 @@ public class ChooserActivityTest {
                .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_HASHED_TARGET_NAME);
        assertThat("Hash is not predictable but must be obfuscated",
                hashedName, is(not(name)));
        assertThat("The packages shouldn't match for app target and direct target", logMakerCaptor
                .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(-1));
    }

        // Running the same again to check if the hashed name is the same as before.
    // This test is too long and too slow and should not be taken as an example for future tests.
    @Test
    public void testDirectTargetLoggingWithRankedAppTarget() throws InterruptedException {
        Intent sendIntent = createSendTextIntent();
        // We need app targets for direct targets to get displayed
        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
                Mockito.anyBoolean(),
                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);

        Intent sendIntent2 = createSendTextIntent();
        // Set up resources
        MetricsLogger mockLogger = sOverrides.metricsLogger;
        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
        // Create direct share target
        List<ChooserTarget> serviceTargets = createDirectShareTargets(1,
                resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
        ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0);

        // Start activity
        final ChooserWrapperActivity activity2 = mActivityRule
                .launchActivity(Intent.createChooser(sendIntent2, null));
        waitForIdle();
        final ChooserWrapperActivity activity = mActivityRule
                .launchActivity(Intent.createChooser(sendIntent, null));

        // Insert the direct share target
        InstrumentationRegistry.getInstrumentation().runOnMainSync(
                () -> activity2.getAdapter().addServiceResults(
                        activity2.createTestDisplayResolveInfo(sendIntent,
                () -> activity.getAdapter().addServiceResults(
                        activity.createTestDisplayResolveInfo(sendIntent,
                                ri,
                                "testLabel",
                                "testInfo",
@@ -859,28 +873,88 @@ public class ChooserActivityTest {
        Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);

        assertThat("Chooser should have 3 targets (2 apps, 1 direct)",
                activity2.getAdapter().getCount(), is(3));
                activity.getAdapter().getCount(), is(3));
        assertThat("Chooser should have exactly one selectable direct target",
                activity2.getAdapter().getSelectableServiceTargetCount(), is(1));
                activity.getAdapter().getSelectableServiceTargetCount(), is(1));
        assertThat("The resolver info must match the resolver info used to create the target",
                activity2.getAdapter().getItem(0).getResolveInfo(), is(ri));
                activity.getAdapter().getItem(0).getResolveInfo(), is(ri));

        // Click on the direct target
        String name = serviceTargets.get(0).getTitle().toString();
        onView(withText(name))
                .perform(click());
        waitForIdle();

        // Currently we're seeing 6 invocations (3 from above, doubled up)
        //      4. ChooserActivity.onCreate()
        //      5. ChooserActivity$ChooserRowAdapter.createContentPreviewView()
        //      6. ChooserActivity.startSelected -- which is the one we're after
        verify(mockLogger, Mockito.times(6)).write(logMakerCaptor.capture());
        assertThat(logMakerCaptor.getAllValues().get(5).getCategory(),
        // Currently we're seeing 3 invocations
        //      1. ChooserActivity.onCreate()
        //      2. ChooserActivity$ChooserRowAdapter.createContentPreviewView()
        //      3. ChooserActivity.startSelected -- which is the one we're after
        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
        assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
                is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET));
        String hashedName2 = (String) logMakerCaptor
                .getAllValues().get(5).getTaggedData(MetricsEvent.FIELD_HASHED_TARGET_NAME);
        assertThat("Hashing the same name should result in the same hashed value",
                hashedName2, is(hashedName));
        assertThat("The packages should match for app target and direct target", logMakerCaptor
                .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(0));
    }

    // This test is too long and too slow and should not be taken as an example for future tests.
    @Test
    public void testDirectTargetLoggingWithAppTargetNotRanked() throws InterruptedException {
        Intent sendIntent = createSendTextIntent();
        // We need app targets for direct targets to get displayed
        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(15);
        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
                Mockito.anyBoolean(),
                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);

        // Set up resources
        MetricsLogger mockLogger = sOverrides.metricsLogger;
        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
        // Create direct share target
        List<ChooserTarget> serviceTargets = createDirectShareTargets(1,
                resolvedComponentInfos.get(14).getResolveInfoAt(0).activityInfo.packageName);
        ResolveInfo ri = ResolverDataProvider.createResolveInfo(16, 0);

        // Start activity
        final ChooserWrapperActivity activity = mActivityRule
                .launchActivity(Intent.createChooser(sendIntent, null));
        // Insert the direct share target
        InstrumentationRegistry.getInstrumentation().runOnMainSync(
                () -> activity.getAdapter().addServiceResults(
                        activity.createTestDisplayResolveInfo(sendIntent,
                                ri,
                                "testLabel",
                                "testInfo",
                                sendIntent),
                        serviceTargets,
                        false)
        );
        // Thread.sleep shouldn't be a thing in an integration test but it's
        // necessary here because of the way the code is structured
        // TODO: restructure the tests b/129870719
        Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);

        assertThat("Chooser should have 20 targets (4 apps, 1 direct, 15 A-Z)",
                activity.getAdapter().getCount(), is(20));
        assertThat("Chooser should have exactly one selectable direct target",
                activity.getAdapter().getSelectableServiceTargetCount(), is(1));
        assertThat("The resolver info must match the resolver info used to create the target",
                activity.getAdapter().getItem(0).getResolveInfo(), is(ri));

        // Click on the direct target
        String name = serviceTargets.get(0).getTitle().toString();
        onView(withText(name))
                .perform(click());
        waitForIdle();

        // Currently we're seeing 3 invocations
        //      1. ChooserActivity.onCreate()
        //      2. ChooserActivity$ChooserRowAdapter.createContentPreviewView()
        //      3. ChooserActivity.startSelected -- which is the one we're after
        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
        assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
                is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET));
        assertThat("The packages shouldn't match for app target and direct target", logMakerCaptor
                .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(-1));
    }

    private Intent createSendTextIntent() {
@@ -946,12 +1020,17 @@ public class ChooserActivityTest {
        return infoList;
    }

    private List<ChooserTarget> createDirectShareTargets(int numberOfResults) {
    private List<ChooserTarget> createDirectShareTargets(int numberOfResults, String packageName) {
        Icon icon = Icon.createWithBitmap(createBitmap());
        String testTitle = "testTitle";
        List<ChooserTarget> targets = new ArrayList<>();
        for (int i = 0; i < numberOfResults; i++) {
            ComponentName componentName = ResolverDataProvider.createComponentName(i);
            ComponentName componentName;
            if (packageName.isEmpty()) {
                componentName = ResolverDataProvider.createComponentName(i);
            } else {
                componentName = new ComponentName(packageName, packageName + ".class");
            }
            ChooserTarget tempTarget = new ChooserTarget(
                    testTitle + i,
                    icon,