summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java29
-rw-r--r--core/java/com/android/internal/widget/ResolverDrawerLayout.java20
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java109
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java9
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto26
5 files changed, 177 insertions, 16 deletions
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 0879af3df32a..119a015cd5ea 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -54,6 +54,7 @@ import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.metrics.LogMaker;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -186,9 +187,12 @@ public class ChooserActivity extends ResolverActivity {
private @interface ContentPreviewType {
}
- private static final int CONTENT_PREVIEW_IMAGE = 0;
- private static final int CONTENT_PREVIEW_FILE = 1;
- private static final int CONTENT_PREVIEW_TEXT = 2;
+ // Starting at 1 since 0 is considered "undefined" for some of the database transformations
+ // of tron logs.
+ private static final int CONTENT_PREVIEW_IMAGE = 1;
+ private static final int CONTENT_PREVIEW_FILE = 2;
+ private static final int CONTENT_PREVIEW_TEXT = 3;
+ protected MetricsLogger mMetricsLogger;
private final Handler mChooserHandler = new Handler() {
@Override
@@ -413,11 +417,12 @@ public class ChooserActivity extends ResolverActivity {
}
});
- MetricsLogger.action(this, MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN);
-
mChooserShownTime = System.currentTimeMillis();
final long systemCost = mChooserShownTime - intentReceivedTime;
- MetricsLogger.histogram(null, "system_cost_for_smart_sharing", (int) systemCost);
+
+ getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN)
+ .addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType())
+ .addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost));
if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
final IntentFilter filter = getTargetIntentFilter();
@@ -470,6 +475,9 @@ public class ChooserActivity extends ResolverActivity {
}
int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
+
+ getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
+ .setSubtype(previewType));
displayContentPreview(previewType, targetIntent);
}
@@ -1180,6 +1188,13 @@ public class ChooserActivity extends ResolverActivity {
}
}
+ protected MetricsLogger getMetricsLogger() {
+ if (mMetricsLogger == null) {
+ mMetricsLogger = new MetricsLogger();
+ }
+ return mMetricsLogger;
+ }
+
public class ChooserListController extends ResolverListController {
public ChooserListController(Context context,
PackageManager pm,
@@ -1726,6 +1741,8 @@ public class ChooserActivity extends ResolverActivity {
if (show != mShowServiceTargets) {
mShowServiceTargets = show;
notifyDataSetChanged();
+ getMetricsLogger().write(
+ new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN_DIRECT_TARGET));
}
}
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index b7e656bc9278..ee8637d8c773 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -17,15 +17,12 @@
package com.android.internal.widget;
-import com.android.internal.R;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -45,8 +42,13 @@ import android.view.animation.AnimationUtils;
import android.widget.AbsListView;
import android.widget.OverScroller;
+import com.android.internal.R;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
public class ResolverDrawerLayout extends ViewGroup {
private static final String TAG = "ResolverDrawerLayout";
+ private MetricsLogger mMetricsLogger;
/**
* Max width of the whole drawer layout
@@ -496,6 +498,9 @@ public class ResolverDrawerLayout extends ViewGroup {
final boolean isCollapsedNew = newPos != 0;
if (isCollapsedOld != isCollapsedNew) {
onCollapsedChanged(isCollapsedNew);
+ getMetricsLogger().write(
+ new LogMaker(MetricsEvent.ACTION_SHARESHEET_COLLAPSED_CHANGED)
+ .setSubtype(isCollapsedNew ? 1 : 0));
}
postInvalidateOnAnimation();
return dy;
@@ -1037,4 +1042,11 @@ public class ResolverDrawerLayout extends ViewGroup {
dispatchOnDismissed();
}
}
+
+ private MetricsLogger getMetricsLogger() {
+ if (mMetricsLogger == null) {
+ mMetricsLogger = new MetricsLogger();
+ }
+ return mMetricsLogger;
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index b6f56ada445e..3d59835a6719 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -27,7 +27,9 @@ import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -43,6 +45,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.metrics.LogMaker;
import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -51,11 +54,14 @@ 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 org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import java.util.ArrayList;
@@ -66,6 +72,11 @@ import java.util.List;
*/
@RunWith(AndroidJUnit4.class)
public class ChooserActivityTest {
+
+ private static final int CONTENT_PREVIEW_IMAGE = 1;
+ private static final int CONTENT_PREVIEW_FILE = 2;
+ private static final int CONTENT_PREVIEW_TEXT = 3;
+
@Rule
public ActivityTestRule<ChooserWrapperActivity> mActivityRule =
new ActivityTestRule<>(ChooserWrapperActivity.class, false,
@@ -402,16 +413,15 @@ public class ChooserActivityTest {
createResolvedComponentsForTestWithOtherProfile(1);
when(ChooserWrapperActivity.sOverrides.resolverListController.getResolversForIntent(
- Mockito.anyBoolean(),
- Mockito.anyBoolean(),
- Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
final ChooserWrapperActivity activity = mActivityRule
.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
onView(withId(R.id.copy_button)).perform(click());
-
ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(
Context.CLIPBOARD_SERVICE);
ClipData clipData = clipboard.getPrimaryClip();
@@ -488,8 +498,8 @@ public class ChooserActivityTest {
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
- Mockito.anyBoolean(),
- Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
onView(withId(R.id.content_preview_image_1_large)).check(matches(isDisplayed()));
@@ -498,6 +508,93 @@ public class ChooserActivityTest {
onView(withId(R.id.content_preview_image_3_small)).check(matches(isDisplayed()));
}
+ @Test
+ public void testOnCreateLogging() {
+ Intent sendIntent = createSendTextIntent();
+ sendIntent.setType("TestType");
+
+ 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(MetricsProto.MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
+ assertThat(logMakerCaptor
+ .getAllValues().get(0)
+ .getTaggedData(MetricsProto.MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
+ is(notNullValue()));
+ assertThat(logMakerCaptor
+ .getAllValues().get(0)
+ .getTaggedData(MetricsProto.MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
+ is("TestType"));
+ }
+
+ @Test
+ public void testEmptyPreviewLogging() {
+ Intent sendIntent = createSendTextIntentWithPreview(null, null);
+
+ MetricsLogger mockLogger = sOverrides.metricsLogger;
+ ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, "empty preview logger test"));
+ waitForIdle();
+ verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
+ // First invocation is from onCreate
+ assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
+ is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+ assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
+ is(CONTENT_PREVIEW_TEXT));
+ }
+
+ @Test
+ public void testTitlePreviewLogging() {
+ Intent sendIntent = createSendTextIntentWithPreview("TestTitle", null);
+
+ MetricsLogger mockLogger = sOverrides.metricsLogger;
+ ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+ verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
+ // First invocation is from onCreate
+ assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
+ is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+ assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
+ is(CONTENT_PREVIEW_TEXT));
+ }
+
+ @Test
+ public void testImagePreviewLogging() {
+ Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
+ + com.android.frameworks.coretests.R.drawable.test320x240);
+
+ ArrayList<Uri> uris = new ArrayList<>();
+ uris.add(uri);
+
+ Intent sendIntent = createSendImageIntentWithPreview(uris);
+ sOverrides.previewThumbnail = createBitmap();
+
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+
+ MetricsLogger mockLogger = sOverrides.metricsLogger;
+ ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+ 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));
+ assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
+ is(CONTENT_PREVIEW_IMAGE));
+ assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
+ is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+ assertThat(logMakerCaptor.getAllValues().get(2).getSubtype(),
+ is(CONTENT_PREVIEW_IMAGE));
+ }
+
private Intent createSendTextIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index ec8122fb2e47..f60467bd3df2 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -25,6 +25,8 @@ import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Size;
+import com.android.internal.logging.MetricsLogger;
+
import java.util.function.Function;
public class ChooserWrapperActivity extends ChooserActivity {
@@ -94,6 +96,11 @@ public class ChooserWrapperActivity extends ChooserActivity {
return super.isImageType(mimeType);
}
+ @Override
+ protected MetricsLogger getMetricsLogger() {
+ return sOverrides.metricsLogger;
+ }
+
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>
@@ -106,6 +113,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
public ResolverListController resolverListController;
public Boolean isVoiceInteraction;
public Bitmap previewThumbnail;
+ public MetricsLogger metricsLogger;
public void reset() {
onSafelyStartCallback = null;
@@ -113,6 +121,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
createPackageManager = null;
previewThumbnail = null;
resolverListController = mock(ResolverListController.class);
+ metricsLogger = mock(MetricsLogger.class);
}
}
}
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index eb8710d6759d..3c910696ba60 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6949,6 +6949,32 @@ message MetricsEvent {
// OS: Q
NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING = 1648;
+ // CATEGORY: ACTION_ACTIVITY_CHOOSER_SHOWN
+ // Field to add the mimetype for a ChooserActivity
+ // OS:Q
+ FIELD_SHARESHEET_MIMETYPE = 1649;
+
+ // CATEGORY: ACTION_ACTIVITY_CHOOSER_SHOWN
+ // Sharesheet direct targets are ready to show.
+ // OS:Q
+ ACTION_ACTIVITY_CHOOSER_SHOWN_DIRECT_TARGET = 1650;
+
+ // CATEGORY: ACTION_SHARESHEET_SCROLL
+ // Sharesheet are either expanded, scrolling through them or compacted again.
+ // OS:Q
+ // Subtype 1 means collapsed, 0 expanded
+ ACTION_SHARESHEET_COLLAPSED_CHANGED = 1651;
+
+ // ACTION: Share with screenshot extra
+ // OS: Q
+ ACTION_SHARE_WITH_PREVIEW = 1652;
+
+ // CATEGORY: ACTION_ACTIVITY_CHOOSER_SHOWN
+ // OS:Q
+ // The time elapsed from triggering the share to displaying the app targets
+ // formerly: histogram system_cost_for_smart_sharing
+ FIELD_TIME_TO_APP_TARGETS = 1653;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS