From 4fe01c7ca647194636c592949516677e68fc4a80 Mon Sep 17 00:00:00 2001 From: Mark Renouf Date: Wed, 13 Sep 2023 11:10:10 -0400 Subject: Extract an interface for EventLog, rename implementation This is a purely automated refactor with no functional changes. Test: atest IntentResolverUnitTests Bug: 300157408 Flag: EXEMPT Change-Id: I7440a6bb1035999f202e799402f09bcb1d657ecc --- .../intentresolver/ChooserActionFactory.java | 26 +- .../android/intentresolver/ChooserActivity.java | 3 +- .../android/intentresolver/logging/EventLog.java | 539 --------------------- .../com/android/intentresolver/logging/EventLog.kt | 74 +++ .../intentresolver/logging/EventLogImpl.java | 514 ++++++++++++++++++++ .../intentresolver/logging/FrameworkStatsLogger.kt | 50 ++ .../model/AbstractResolverComparator.java | 4 +- .../AppPredictionServiceResolverComparator.java | 2 +- .../ResolverRankerServiceResolverComparator.java | 13 +- 9 files changed, 663 insertions(+), 562 deletions(-) delete mode 100644 java/src/com/android/intentresolver/logging/EventLog.java create mode 100644 java/src/com/android/intentresolver/logging/EventLog.kt create mode 100644 java/src/com/android/intentresolver/logging/EventLogImpl.java create mode 100644 java/src/com/android/intentresolver/logging/FrameworkStatsLogger.kt (limited to 'java/src') diff --git a/java/src/com/android/intentresolver/ChooserActionFactory.java b/java/src/com/android/intentresolver/ChooserActionFactory.java index a54e8c62..2c97c0b1 100644 --- a/java/src/com/android/intentresolver/ChooserActionFactory.java +++ b/java/src/com/android/intentresolver/ChooserActionFactory.java @@ -98,7 +98,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio private final @Nullable ChooserAction mModifyShareAction; private final Consumer mExcludeSharedTextAction; private final Consumer mFinishCallback; - private final EventLog mLogger; + private final EventLog mLog; /** * @param context @@ -117,7 +117,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio Context context, ChooserRequestParameters chooserRequest, ChooserIntegratedDeviceComponents integratedDeviceComponents, - EventLog logger, + EventLog log, Consumer onUpdateSharedTextIsExcluded, Callable firstVisibleImageQuery, ActionActivityStarter activityStarter, @@ -129,7 +129,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio chooserRequest.getTargetIntent(), chooserRequest.getReferrerPackageName(), finishCallback, - logger), + log), makeEditButtonRunnable( getEditSharingTarget( context, @@ -137,11 +137,11 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio integratedDeviceComponents), firstVisibleImageQuery, activityStarter, - logger), + log), chooserRequest.getChooserActions(), chooserRequest.getModifyShareAction(), onUpdateSharedTextIsExcluded, - logger, + log, finishCallback); } @@ -153,7 +153,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio List customActions, @Nullable ChooserAction modifyShareAction, Consumer onUpdateSharedTextIsExcluded, - EventLog logger, + EventLog log, Consumer finishCallback) { mContext = context; mCopyButtonRunnable = copyButtonRunnable; @@ -161,7 +161,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio mCustomActions = ImmutableList.copyOf(customActions); mModifyShareAction = modifyShareAction; mExcludeSharedTextAction = onUpdateSharedTextIsExcluded; - mLogger = logger; + mLog = log; mFinishCallback = finishCallback; } @@ -188,7 +188,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio mCustomActions.get(i), mFinishCallback, () -> { - mLogger.logCustomActionSelected(position); + mLog.logCustomActionSelected(position); } ); if (actionRow != null) { @@ -209,7 +209,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio mModifyShareAction, mFinishCallback, () -> { - mLogger.logActionSelected(EventLog.SELECTION_TYPE_MODIFY_SHARE); + mLog.logActionSelected(EventLog.SELECTION_TYPE_MODIFY_SHARE); }); } @@ -233,7 +233,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio Intent targetIntent, String referrerPackageName, Consumer finishCallback, - EventLog logger) { + EventLog log) { final ClipData clipData; try { clipData = extractTextToCopy(targetIntent); @@ -249,7 +249,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio Context.CLIPBOARD_SERVICE); clipboardManager.setPrimaryClipAsPackage(clipData, referrerPackageName); - logger.logActionSelected(EventLog.SELECTION_TYPE_COPY); + log.logActionSelected(EventLog.SELECTION_TYPE_COPY); finishCallback.accept(Activity.RESULT_OK); }; } @@ -328,10 +328,10 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio TargetInfo editSharingTarget, Callable firstVisibleImageQuery, ActionActivityStarter activityStarter, - EventLog logger) { + EventLog log) { return () -> { // Log share completion via edit. - logger.logActionSelected(EventLog.SELECTION_TYPE_EDIT); + log.logActionSelected(EventLog.SELECTION_TYPE_EDIT); View firstImageView = null; try { diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index ebe6f04b..0a4f9f46 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -85,6 +85,7 @@ import com.android.intentresolver.grid.ChooserGridAdapter; import com.android.intentresolver.icons.DefaultTargetDataLoader; import com.android.intentresolver.icons.TargetDataLoader; import com.android.intentresolver.logging.EventLog; +import com.android.intentresolver.logging.EventLogImpl; import com.android.intentresolver.measurements.Tracer; import com.android.intentresolver.model.AbstractResolverComparator; import com.android.intentresolver.model.AppPredictionServiceResolverComparator; @@ -1111,7 +1112,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements protected EventLog getEventLog() { if (mEventLog == null) { - mEventLog = new EventLog(); + mEventLog = new EventLogImpl(); } return mEventLog; } diff --git a/java/src/com/android/intentresolver/logging/EventLog.java b/java/src/com/android/intentresolver/logging/EventLog.java deleted file mode 100644 index b30e825b..00000000 --- a/java/src/com/android/intentresolver/logging/EventLog.java +++ /dev/null @@ -1,539 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.intentresolver.logging; - -import android.annotation.Nullable; -import android.content.Intent; -import android.metrics.LogMaker; -import android.net.Uri; -import android.provider.MediaStore; -import android.util.HashedStringCache; -import android.util.Log; - -import com.android.intentresolver.ChooserActivity; -import com.android.intentresolver.contentpreview.ContentPreviewType; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.logging.InstanceId; -import com.android.internal.logging.InstanceIdSequence; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.UiEvent; -import com.android.internal.logging.UiEventLogger; -import com.android.internal.logging.UiEventLoggerImpl; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.util.FrameworkStatsLog; - -/** - * Helper for writing Sharesheet atoms to statsd log. - * @hide - */ -public class EventLog { - private static final String TAG = "ChooserActivity"; - private static final boolean DEBUG = true; - - public static final int SELECTION_TYPE_SERVICE = 1; - public static final int SELECTION_TYPE_APP = 2; - public static final int SELECTION_TYPE_STANDARD = 3; - public static final int SELECTION_TYPE_COPY = 4; - public static final int SELECTION_TYPE_NEARBY = 5; - public static final int SELECTION_TYPE_EDIT = 6; - public static final int SELECTION_TYPE_MODIFY_SHARE = 7; - public static final int SELECTION_TYPE_CUSTOM_ACTION = 8; - - /** - * This shim is provided only for testing. In production, clients will only ever use a - * {@link DefaultFrameworkStatsLogger}. - */ - @VisibleForTesting - interface FrameworkStatsLogger { - /** Overload to use for logging {@code FrameworkStatsLog.SHARESHEET_STARTED}. */ - void write( - int frameworkEventId, - int appEventId, - String packageName, - int instanceId, - String mimeType, - int numAppProvidedDirectTargets, - int numAppProvidedAppTargets, - boolean isWorkProfile, - int previewType, - int intentType, - int numCustomActions, - boolean modifyShareActionProvided); - - /** Overload to use for logging {@code FrameworkStatsLog.RANKING_SELECTED}. */ - void write( - int frameworkEventId, - int appEventId, - String packageName, - int instanceId, - int positionPicked, - boolean isPinned); - } - - private static final int SHARESHEET_INSTANCE_ID_MAX = (1 << 13); - - // A small per-notification ID, used for statsd logging. - // TODO: consider precomputing and storing as final. - private static InstanceIdSequence sInstanceIdSequence; - private InstanceId mInstanceId; - - private final UiEventLogger mUiEventLogger; - private final FrameworkStatsLogger mFrameworkStatsLogger; - private final MetricsLogger mMetricsLogger; - - public EventLog() { - this(new UiEventLoggerImpl(), new DefaultFrameworkStatsLogger(), new MetricsLogger()); - } - - @VisibleForTesting - EventLog( - UiEventLogger uiEventLogger, - FrameworkStatsLogger frameworkLogger, - MetricsLogger metricsLogger) { - mUiEventLogger = uiEventLogger; - mFrameworkStatsLogger = frameworkLogger; - mMetricsLogger = metricsLogger; - } - - /** Records metrics for the start time of the {@link ChooserActivity}. */ - public void logChooserActivityShown( - boolean isWorkProfile, String targetMimeType, long systemCost) { - mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN) - .setSubtype( - isWorkProfile ? MetricsEvent.MANAGED_PROFILE : MetricsEvent.PARENT_PROFILE) - .addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, targetMimeType) - .addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost)); - } - - /** Logs a UiEventReported event for the system sharesheet completing initial start-up. */ - public void logShareStarted( - String packageName, - String mimeType, - int appProvidedDirect, - int appProvidedApp, - boolean isWorkprofile, - int previewType, - String intent, - int customActionCount, - boolean modifyShareActionProvided) { - mFrameworkStatsLogger.write(FrameworkStatsLog.SHARESHEET_STARTED, - /* event_id = 1 */ SharesheetStartedEvent.SHARE_STARTED.getId(), - /* package_name = 2 */ packageName, - /* instance_id = 3 */ getInstanceId().getId(), - /* mime_type = 4 */ mimeType, - /* num_app_provided_direct_targets = 5 */ appProvidedDirect, - /* num_app_provided_app_targets = 6 */ appProvidedApp, - /* is_workprofile = 7 */ isWorkprofile, - /* previewType = 8 */ typeFromPreviewInt(previewType), - /* intentType = 9 */ typeFromIntentString(intent), - /* num_provided_custom_actions = 10 */ customActionCount, - /* modify_share_action_provided = 11 */ modifyShareActionProvided); - } - - /** - * Log that a custom action has been tapped by the user. - * - * @param positionPicked index of the custom action within the list of custom actions. - */ - public void logCustomActionSelected(int positionPicked) { - mFrameworkStatsLogger.write(FrameworkStatsLog.RANKING_SELECTED, - /* event_id = 1 */ - SharesheetTargetSelectedEvent.SHARESHEET_CUSTOM_ACTION_SELECTED.getId(), - /* package_name = 2 */ null, - /* instance_id = 3 */ getInstanceId().getId(), - /* position_picked = 4 */ positionPicked, - /* is_pinned = 5 */ false); - } - - /** - * Logs a UiEventReported event for the system sharesheet when the user selects a target. - * TODO: document parameters and/or consider breaking up by targetType so we don't have to - * support an overly-generic signature. - */ - public void logShareTargetSelected( - int targetType, - String packageName, - int positionPicked, - int directTargetAlsoRanked, - int numCallerProvided, - @Nullable HashedStringCache.HashResult directTargetHashed, - boolean isPinned, - boolean successfullySelected, - long selectionCost) { - mFrameworkStatsLogger.write(FrameworkStatsLog.RANKING_SELECTED, - /* event_id = 1 */ SharesheetTargetSelectedEvent.fromTargetType(targetType).getId(), - /* package_name = 2 */ packageName, - /* instance_id = 3 */ getInstanceId().getId(), - /* position_picked = 4 */ positionPicked, - /* is_pinned = 5 */ isPinned); - - int category = getTargetSelectionCategory(targetType); - if (category != 0) { - LogMaker targetLogMaker = new LogMaker(category).setSubtype(positionPicked); - if (directTargetHashed != null) { - targetLogMaker.addTaggedData( - MetricsEvent.FIELD_HASHED_TARGET_NAME, directTargetHashed.hashedString); - targetLogMaker.addTaggedData( - MetricsEvent.FIELD_HASHED_TARGET_SALT_GEN, - directTargetHashed.saltGeneration); - targetLogMaker.addTaggedData(MetricsEvent.FIELD_RANKED_POSITION, - directTargetAlsoRanked); - } - targetLogMaker.addTaggedData(MetricsEvent.FIELD_IS_CATEGORY_USED, numCallerProvided); - mMetricsLogger.write(targetLogMaker); - } - - if (successfullySelected) { - if (DEBUG) { - Log.d(TAG, "User Selection Time Cost is " + selectionCost); - Log.d(TAG, "position of selected app/service/caller is " + positionPicked); - } - MetricsLogger.histogram( - null, "user_selection_cost_for_smart_sharing", (int) selectionCost); - MetricsLogger.histogram(null, "app_position_for_smart_sharing", positionPicked); - } - } - - /** Log when direct share targets were received. */ - public void logDirectShareTargetReceived(int category, int latency) { - mMetricsLogger.write(new LogMaker(category).setSubtype(latency)); - } - - /** - * Log when we display a preview UI of the specified {@code previewType} as part of our - * Sharesheet session. - */ - public void logActionShareWithPreview(int previewType) { - mMetricsLogger.write( - new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW).setSubtype(previewType)); - } - - /** Log when the user selects an action button with the specified {@code targetType}. */ - public void logActionSelected(int targetType) { - if (targetType == SELECTION_TYPE_COPY) { - LogMaker targetLogMaker = new LogMaker( - MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SYSTEM_TARGET).setSubtype(1); - mMetricsLogger.write(targetLogMaker); - } - mFrameworkStatsLogger.write(FrameworkStatsLog.RANKING_SELECTED, - /* event_id = 1 */ SharesheetTargetSelectedEvent.fromTargetType(targetType).getId(), - /* package_name = 2 */ "", - /* instance_id = 3 */ getInstanceId().getId(), - /* position_picked = 4 */ -1, - /* is_pinned = 5 */ false); - } - - /** Log a warning that we couldn't display the content preview from the supplied {@code uri}. */ - public void logContentPreviewWarning(Uri uri) { - // The ContentResolver already logs the exception. Log something more informative. - Log.w(TAG, "Could not load (" + uri.toString() + ") thumbnail/name for preview. If " - + "desired, consider using Intent#createChooser to launch the ChooserActivity, " - + "and set your Intent's clipData and flags in accordance with that method's " - + "documentation"); - - } - - /** Logs a UiEventReported event for the system sharesheet being triggered by the user. */ - public void logSharesheetTriggered() { - log(SharesheetStandardEvent.SHARESHEET_TRIGGERED, getInstanceId()); - } - - /** Logs a UiEventReported event for the system sharesheet completing loading app targets. */ - public void logSharesheetAppLoadComplete() { - log(SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE, getInstanceId()); - } - - /** - * Logs a UiEventReported event for the system sharesheet completing loading service targets. - */ - public void logSharesheetDirectLoadComplete() { - log(SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE, getInstanceId()); - } - - /** - * Logs a UiEventReported event for the system sharesheet timing out loading service targets. - */ - public void logSharesheetDirectLoadTimeout() { - log(SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_TIMEOUT, getInstanceId()); - } - - /** - * Logs a UiEventReported event for the system sharesheet switching - * between work and main profile. - */ - public void logSharesheetProfileChanged() { - log(SharesheetStandardEvent.SHARESHEET_PROFILE_CHANGED, getInstanceId()); - } - - /** Logs a UiEventReported event for the system sharesheet getting expanded or collapsed. */ - public void logSharesheetExpansionChanged(boolean isCollapsed) { - log(isCollapsed ? SharesheetStandardEvent.SHARESHEET_COLLAPSED : - SharesheetStandardEvent.SHARESHEET_EXPANDED, getInstanceId()); - } - - /** - * Logs a UiEventReported event for the system sharesheet app share ranking timing out. - */ - public void logSharesheetAppShareRankingTimeout() { - log(SharesheetStandardEvent.SHARESHEET_APP_SHARE_RANKING_TIMEOUT, getInstanceId()); - } - - /** - * Logs a UiEventReported event for the system sharesheet when direct share row is empty. - */ - public void logSharesheetEmptyDirectShareRow() { - log(SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW, getInstanceId()); - } - - /** - * Logs a UiEventReported event for a given share activity - * @param event - * @param instanceId - */ - private void log(UiEventLogger.UiEventEnum event, InstanceId instanceId) { - mUiEventLogger.logWithInstanceId( - event, - 0, - null, - instanceId); - } - - /** - * @return A unique {@link InstanceId} to join across events recorded by this logger instance. - */ - private InstanceId getInstanceId() { - if (mInstanceId == null) { - if (sInstanceIdSequence == null) { - sInstanceIdSequence = new InstanceIdSequence(SHARESHEET_INSTANCE_ID_MAX); - } - mInstanceId = sInstanceIdSequence.newInstanceId(); - } - return mInstanceId; - } - - /** - * The UiEvent enums that this class can log. - */ - enum SharesheetStartedEvent implements UiEventLogger.UiEventEnum { - @UiEvent(doc = "Basic system Sharesheet has started and is visible.") - SHARE_STARTED(228); - - private final int mId; - SharesheetStartedEvent(int id) { - mId = id; - } - @Override - public int getId() { - return mId; - } - } - - /** - * The UiEvent enums that this class can log. - */ - enum SharesheetTargetSelectedEvent implements UiEventLogger.UiEventEnum { - INVALID(0), - @UiEvent(doc = "User selected a service target.") - SHARESHEET_SERVICE_TARGET_SELECTED(232), - @UiEvent(doc = "User selected an app target.") - SHARESHEET_APP_TARGET_SELECTED(233), - @UiEvent(doc = "User selected a standard target.") - SHARESHEET_STANDARD_TARGET_SELECTED(234), - @UiEvent(doc = "User selected the copy target.") - SHARESHEET_COPY_TARGET_SELECTED(235), - @UiEvent(doc = "User selected the nearby target.") - SHARESHEET_NEARBY_TARGET_SELECTED(626), - @UiEvent(doc = "User selected the edit target.") - SHARESHEET_EDIT_TARGET_SELECTED(669), - @UiEvent(doc = "User selected the modify share target.") - SHARESHEET_MODIFY_SHARE_SELECTED(1316), - @UiEvent(doc = "User selected a custom action.") - SHARESHEET_CUSTOM_ACTION_SELECTED(1317); - - private final int mId; - SharesheetTargetSelectedEvent(int id) { - mId = id; - } - @Override public int getId() { - return mId; - } - - public static SharesheetTargetSelectedEvent fromTargetType(int targetType) { - switch(targetType) { - case SELECTION_TYPE_SERVICE: - return SHARESHEET_SERVICE_TARGET_SELECTED; - case SELECTION_TYPE_APP: - return SHARESHEET_APP_TARGET_SELECTED; - case SELECTION_TYPE_STANDARD: - return SHARESHEET_STANDARD_TARGET_SELECTED; - case SELECTION_TYPE_COPY: - return SHARESHEET_COPY_TARGET_SELECTED; - case SELECTION_TYPE_NEARBY: - return SHARESHEET_NEARBY_TARGET_SELECTED; - case SELECTION_TYPE_EDIT: - return SHARESHEET_EDIT_TARGET_SELECTED; - case SELECTION_TYPE_MODIFY_SHARE: - return SHARESHEET_MODIFY_SHARE_SELECTED; - case SELECTION_TYPE_CUSTOM_ACTION: - return SHARESHEET_CUSTOM_ACTION_SELECTED; - default: - return INVALID; - } - } - } - - /** - * The UiEvent enums that this class can log. - */ - enum SharesheetStandardEvent implements UiEventLogger.UiEventEnum { - INVALID(0), - @UiEvent(doc = "User clicked share.") - SHARESHEET_TRIGGERED(227), - @UiEvent(doc = "User changed from work to personal profile or vice versa.") - SHARESHEET_PROFILE_CHANGED(229), - @UiEvent(doc = "User expanded target list.") - SHARESHEET_EXPANDED(230), - @UiEvent(doc = "User collapsed target list.") - SHARESHEET_COLLAPSED(231), - @UiEvent(doc = "Sharesheet app targets is fully populated.") - SHARESHEET_APP_LOAD_COMPLETE(322), - @UiEvent(doc = "Sharesheet direct targets is fully populated.") - SHARESHEET_DIRECT_LOAD_COMPLETE(323), - @UiEvent(doc = "Sharesheet direct targets timed out.") - SHARESHEET_DIRECT_LOAD_TIMEOUT(324), - @UiEvent(doc = "Sharesheet app share ranking timed out.") - SHARESHEET_APP_SHARE_RANKING_TIMEOUT(831), - @UiEvent(doc = "Sharesheet empty direct share row.") - SHARESHEET_EMPTY_DIRECT_SHARE_ROW(828); - - private final int mId; - SharesheetStandardEvent(int id) { - mId = id; - } - @Override public int getId() { - return mId; - } - } - - /** - * Returns the enum used in sharesheet started atom to indicate what preview type was used. - */ - private static int typeFromPreviewInt(int previewType) { - switch(previewType) { - case ContentPreviewType.CONTENT_PREVIEW_IMAGE: - return FrameworkStatsLog.SHARESHEET_STARTED__PREVIEW_TYPE__CONTENT_PREVIEW_IMAGE; - case ContentPreviewType.CONTENT_PREVIEW_FILE: - return FrameworkStatsLog.SHARESHEET_STARTED__PREVIEW_TYPE__CONTENT_PREVIEW_FILE; - case ContentPreviewType.CONTENT_PREVIEW_TEXT: - default: - return FrameworkStatsLog - .SHARESHEET_STARTED__PREVIEW_TYPE__CONTENT_PREVIEW_TYPE_UNKNOWN; - } - } - - /** - * Returns the enum used in sharesheet started atom to indicate what intent triggers the - * ChooserActivity. - */ - private static int typeFromIntentString(String intent) { - if (intent == null) { - return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_DEFAULT; - } - switch (intent) { - case Intent.ACTION_VIEW: - return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_VIEW; - case Intent.ACTION_EDIT: - return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_EDIT; - case Intent.ACTION_SEND: - return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_SEND; - case Intent.ACTION_SENDTO: - return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_SENDTO; - case Intent.ACTION_SEND_MULTIPLE: - return FrameworkStatsLog - .SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_SEND_MULTIPLE; - case MediaStore.ACTION_IMAGE_CAPTURE: - return FrameworkStatsLog - .SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_IMAGE_CAPTURE; - case Intent.ACTION_MAIN: - return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_MAIN; - default: - return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_DEFAULT; - } - } - - @VisibleForTesting - static int getTargetSelectionCategory(int targetType) { - switch (targetType) { - case SELECTION_TYPE_SERVICE: - return MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET; - case SELECTION_TYPE_APP: - return MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET; - case SELECTION_TYPE_STANDARD: - return MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET; - default: - return 0; - } - } - - private static class DefaultFrameworkStatsLogger implements FrameworkStatsLogger { - @Override - public void write( - int frameworkEventId, - int appEventId, - String packageName, - int instanceId, - String mimeType, - int numAppProvidedDirectTargets, - int numAppProvidedAppTargets, - boolean isWorkProfile, - int previewType, - int intentType, - int numCustomActions, - boolean modifyShareActionProvided) { - FrameworkStatsLog.write( - frameworkEventId, - /* event_id = 1 */ appEventId, - /* package_name = 2 */ packageName, - /* instance_id = 3 */ instanceId, - /* mime_type = 4 */ mimeType, - /* num_app_provided_direct_targets */ numAppProvidedDirectTargets, - /* num_app_provided_app_targets */ numAppProvidedAppTargets, - /* is_workprofile */ isWorkProfile, - /* previewType = 8 */ previewType, - /* intentType = 9 */ intentType, - /* num_provided_custom_actions = 10 */ numCustomActions, - /* modify_share_action_provided = 11 */ modifyShareActionProvided); - } - - @Override - public void write( - int frameworkEventId, - int appEventId, - String packageName, - int instanceId, - int positionPicked, - boolean isPinned) { - FrameworkStatsLog.write( - frameworkEventId, - /* event_id = 1 */ appEventId, - /* package_name = 2 */ packageName, - /* instance_id = 3 */ instanceId, - /* position_picked = 4 */ positionPicked, - /* is_pinned = 5 */ isPinned); - } - } -} diff --git a/java/src/com/android/intentresolver/logging/EventLog.kt b/java/src/com/android/intentresolver/logging/EventLog.kt new file mode 100644 index 00000000..476bd4bf --- /dev/null +++ b/java/src/com/android/intentresolver/logging/EventLog.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.intentresolver.logging + +import android.net.Uri +import android.util.HashedStringCache + +/** Logs notable events during ShareSheet usage. */ +interface EventLog { + + companion object { + const val SELECTION_TYPE_SERVICE = 1 + const val SELECTION_TYPE_APP = 2 + const val SELECTION_TYPE_STANDARD = 3 + const val SELECTION_TYPE_COPY = 4 + const val SELECTION_TYPE_NEARBY = 5 + const val SELECTION_TYPE_EDIT = 6 + const val SELECTION_TYPE_MODIFY_SHARE = 7 + const val SELECTION_TYPE_CUSTOM_ACTION = 8 + } + + fun logChooserActivityShown(isWorkProfile: Boolean, targetMimeType: String?, systemCost: Long) + + fun logShareStarted( + packageName: String?, + mimeType: String?, + appProvidedDirect: Int, + appProvidedApp: Int, + isWorkprofile: Boolean, + previewType: Int, + intent: String?, + customActionCount: Int, + modifyShareActionProvided: Boolean + ) + + fun logCustomActionSelected(positionPicked: Int) + fun logShareTargetSelected( + targetType: Int, + packageName: String?, + positionPicked: Int, + directTargetAlsoRanked: Int, + numCallerProvided: Int, + directTargetHashed: HashedStringCache.HashResult?, + isPinned: Boolean, + successfullySelected: Boolean, + selectionCost: Long + ) + + fun logDirectShareTargetReceived(category: Int, latency: Int) + fun logActionShareWithPreview(previewType: Int) + fun logActionSelected(targetType: Int) + fun logContentPreviewWarning(uri: Uri?) + fun logSharesheetTriggered() + fun logSharesheetAppLoadComplete() + fun logSharesheetDirectLoadComplete() + fun logSharesheetDirectLoadTimeout() + fun logSharesheetProfileChanged() + fun logSharesheetExpansionChanged(isCollapsed: Boolean) + fun logSharesheetAppShareRankingTimeout() + fun logSharesheetEmptyDirectShareRow() +} diff --git a/java/src/com/android/intentresolver/logging/EventLogImpl.java b/java/src/com/android/intentresolver/logging/EventLogImpl.java new file mode 100644 index 00000000..33e617b1 --- /dev/null +++ b/java/src/com/android/intentresolver/logging/EventLogImpl.java @@ -0,0 +1,514 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.intentresolver.logging; + +import android.annotation.Nullable; +import android.content.Intent; +import android.metrics.LogMaker; +import android.net.Uri; +import android.provider.MediaStore; +import android.util.HashedStringCache; +import android.util.Log; + +import com.android.intentresolver.ChooserActivity; +import com.android.intentresolver.contentpreview.ContentPreviewType; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.InstanceId; +import com.android.internal.logging.InstanceIdSequence; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; +import com.android.internal.logging.UiEventLoggerImpl; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.util.FrameworkStatsLog; + +/** + * Helper for writing Sharesheet atoms to statsd log. + */ +public class EventLogImpl implements EventLog { + private static final String TAG = "ChooserActivity"; + private static final boolean DEBUG = true; + + private static final int SHARESHEET_INSTANCE_ID_MAX = (1 << 13); + + // A small per-notification ID, used for statsd logging. + // TODO: consider precomputing and storing as final. + private static InstanceIdSequence sInstanceIdSequence; + private InstanceId mInstanceId; + + private final UiEventLogger mUiEventLogger; + private final FrameworkStatsLogger mFrameworkStatsLogger; + private final MetricsLogger mMetricsLogger; + + public EventLogImpl() { + this(new UiEventLoggerImpl(), new DefaultFrameworkStatsLogger(), new MetricsLogger()); + } + + @VisibleForTesting + EventLogImpl( + UiEventLogger uiEventLogger, + FrameworkStatsLogger frameworkLogger, + MetricsLogger metricsLogger) { + mUiEventLogger = uiEventLogger; + mFrameworkStatsLogger = frameworkLogger; + mMetricsLogger = metricsLogger; + } + + /** Records metrics for the start time of the {@link ChooserActivity}. */ + @Override + public void logChooserActivityShown( + boolean isWorkProfile, String targetMimeType, long systemCost) { + mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN) + .setSubtype( + isWorkProfile ? MetricsEvent.MANAGED_PROFILE : MetricsEvent.PARENT_PROFILE) + .addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, targetMimeType) + .addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost)); + } + + /** Logs a UiEventReported event for the system sharesheet completing initial start-up. */ + @Override + public void logShareStarted( + String packageName, + String mimeType, + int appProvidedDirect, + int appProvidedApp, + boolean isWorkprofile, + int previewType, + String intent, + int customActionCount, + boolean modifyShareActionProvided) { + mFrameworkStatsLogger.write(FrameworkStatsLog.SHARESHEET_STARTED, + /* event_id = 1 */ SharesheetStartedEvent.SHARE_STARTED.getId(), + /* package_name = 2 */ packageName, + /* instance_id = 3 */ getInstanceId().getId(), + /* mime_type = 4 */ mimeType, + /* num_app_provided_direct_targets = 5 */ appProvidedDirect, + /* num_app_provided_app_targets = 6 */ appProvidedApp, + /* is_workprofile = 7 */ isWorkprofile, + /* previewType = 8 */ typeFromPreviewInt(previewType), + /* intentType = 9 */ typeFromIntentString(intent), + /* num_provided_custom_actions = 10 */ customActionCount, + /* modify_share_action_provided = 11 */ modifyShareActionProvided); + } + + /** + * Log that a custom action has been tapped by the user. + * + * @param positionPicked index of the custom action within the list of custom actions. + */ + @Override + public void logCustomActionSelected(int positionPicked) { + mFrameworkStatsLogger.write(FrameworkStatsLog.RANKING_SELECTED, + /* event_id = 1 */ + SharesheetTargetSelectedEvent.SHARESHEET_CUSTOM_ACTION_SELECTED.getId(), + /* package_name = 2 */ null, + /* instance_id = 3 */ getInstanceId().getId(), + /* position_picked = 4 */ positionPicked, + /* is_pinned = 5 */ false); + } + + /** + * Logs a UiEventReported event for the system sharesheet when the user selects a target. + * TODO: document parameters and/or consider breaking up by targetType so we don't have to + * support an overly-generic signature. + */ + @Override + public void logShareTargetSelected( + int targetType, + String packageName, + int positionPicked, + int directTargetAlsoRanked, + int numCallerProvided, + @Nullable HashedStringCache.HashResult directTargetHashed, + boolean isPinned, + boolean successfullySelected, + long selectionCost) { + mFrameworkStatsLogger.write(FrameworkStatsLog.RANKING_SELECTED, + /* event_id = 1 */ SharesheetTargetSelectedEvent.fromTargetType(targetType).getId(), + /* package_name = 2 */ packageName, + /* instance_id = 3 */ getInstanceId().getId(), + /* position_picked = 4 */ positionPicked, + /* is_pinned = 5 */ isPinned); + + int category = getTargetSelectionCategory(targetType); + if (category != 0) { + LogMaker targetLogMaker = new LogMaker(category).setSubtype(positionPicked); + if (directTargetHashed != null) { + targetLogMaker.addTaggedData( + MetricsEvent.FIELD_HASHED_TARGET_NAME, directTargetHashed.hashedString); + targetLogMaker.addTaggedData( + MetricsEvent.FIELD_HASHED_TARGET_SALT_GEN, + directTargetHashed.saltGeneration); + targetLogMaker.addTaggedData(MetricsEvent.FIELD_RANKED_POSITION, + directTargetAlsoRanked); + } + targetLogMaker.addTaggedData(MetricsEvent.FIELD_IS_CATEGORY_USED, numCallerProvided); + mMetricsLogger.write(targetLogMaker); + } + + if (successfullySelected) { + if (DEBUG) { + Log.d(TAG, "User Selection Time Cost is " + selectionCost); + Log.d(TAG, "position of selected app/service/caller is " + positionPicked); + } + MetricsLogger.histogram( + null, "user_selection_cost_for_smart_sharing", (int) selectionCost); + MetricsLogger.histogram(null, "app_position_for_smart_sharing", positionPicked); + } + } + + /** Log when direct share targets were received. */ + @Override + public void logDirectShareTargetReceived(int category, int latency) { + mMetricsLogger.write(new LogMaker(category).setSubtype(latency)); + } + + /** + * Log when we display a preview UI of the specified {@code previewType} as part of our + * Sharesheet session. + */ + @Override + public void logActionShareWithPreview(int previewType) { + mMetricsLogger.write( + new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW).setSubtype(previewType)); + } + + /** Log when the user selects an action button with the specified {@code targetType}. */ + @Override + public void logActionSelected(int targetType) { + if (targetType == SELECTION_TYPE_COPY) { + LogMaker targetLogMaker = new LogMaker( + MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SYSTEM_TARGET).setSubtype(1); + mMetricsLogger.write(targetLogMaker); + } + mFrameworkStatsLogger.write(FrameworkStatsLog.RANKING_SELECTED, + /* event_id = 1 */ SharesheetTargetSelectedEvent.fromTargetType(targetType).getId(), + /* package_name = 2 */ "", + /* instance_id = 3 */ getInstanceId().getId(), + /* position_picked = 4 */ -1, + /* is_pinned = 5 */ false); + } + + /** Log a warning that we couldn't display the content preview from the supplied {@code uri}. */ + @Override + public void logContentPreviewWarning(Uri uri) { + // The ContentResolver already logs the exception. Log something more informative. + Log.w(TAG, "Could not load (" + uri.toString() + ") thumbnail/name for preview. If " + + "desired, consider using Intent#createChooser to launch the ChooserActivity, " + + "and set your Intent's clipData and flags in accordance with that method's " + + "documentation"); + + } + + /** Logs a UiEventReported event for the system sharesheet being triggered by the user. */ + @Override + public void logSharesheetTriggered() { + log(SharesheetStandardEvent.SHARESHEET_TRIGGERED, getInstanceId()); + } + + /** Logs a UiEventReported event for the system sharesheet completing loading app targets. */ + @Override + public void logSharesheetAppLoadComplete() { + log(SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE, getInstanceId()); + } + + /** + * Logs a UiEventReported event for the system sharesheet completing loading service targets. + */ + @Override + public void logSharesheetDirectLoadComplete() { + log(SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE, getInstanceId()); + } + + /** + * Logs a UiEventReported event for the system sharesheet timing out loading service targets. + */ + @Override + public void logSharesheetDirectLoadTimeout() { + log(SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_TIMEOUT, getInstanceId()); + } + + /** + * Logs a UiEventReported event for the system sharesheet switching + * between work and main profile. + */ + @Override + public void logSharesheetProfileChanged() { + log(SharesheetStandardEvent.SHARESHEET_PROFILE_CHANGED, getInstanceId()); + } + + /** Logs a UiEventReported event for the system sharesheet getting expanded or collapsed. */ + @Override + public void logSharesheetExpansionChanged(boolean isCollapsed) { + log(isCollapsed ? SharesheetStandardEvent.SHARESHEET_COLLAPSED : + SharesheetStandardEvent.SHARESHEET_EXPANDED, getInstanceId()); + } + + /** + * Logs a UiEventReported event for the system sharesheet app share ranking timing out. + */ + @Override + public void logSharesheetAppShareRankingTimeout() { + log(SharesheetStandardEvent.SHARESHEET_APP_SHARE_RANKING_TIMEOUT, getInstanceId()); + } + + /** + * Logs a UiEventReported event for the system sharesheet when direct share row is empty. + */ + @Override + public void logSharesheetEmptyDirectShareRow() { + log(SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW, getInstanceId()); + } + + /** + * Logs a UiEventReported event for a given share activity + * @param event + * @param instanceId + */ + private void log(UiEventLogger.UiEventEnum event, InstanceId instanceId) { + mUiEventLogger.logWithInstanceId( + event, + 0, + null, + instanceId); + } + + /** + * @return A unique {@link InstanceId} to join across events recorded by this logger instance. + */ + private InstanceId getInstanceId() { + if (mInstanceId == null) { + if (sInstanceIdSequence == null) { + sInstanceIdSequence = new InstanceIdSequence(SHARESHEET_INSTANCE_ID_MAX); + } + mInstanceId = sInstanceIdSequence.newInstanceId(); + } + return mInstanceId; + } + + /** + * The UiEvent enums that this class can log. + */ + enum SharesheetStartedEvent implements UiEventLogger.UiEventEnum { + @UiEvent(doc = "Basic system Sharesheet has started and is visible.") + SHARE_STARTED(228); + + private final int mId; + SharesheetStartedEvent(int id) { + mId = id; + } + @Override + public int getId() { + return mId; + } + } + + /** + * The UiEvent enums that this class can log. + */ + enum SharesheetTargetSelectedEvent implements UiEventLogger.UiEventEnum { + INVALID(0), + @UiEvent(doc = "User selected a service target.") + SHARESHEET_SERVICE_TARGET_SELECTED(232), + @UiEvent(doc = "User selected an app target.") + SHARESHEET_APP_TARGET_SELECTED(233), + @UiEvent(doc = "User selected a standard target.") + SHARESHEET_STANDARD_TARGET_SELECTED(234), + @UiEvent(doc = "User selected the copy target.") + SHARESHEET_COPY_TARGET_SELECTED(235), + @UiEvent(doc = "User selected the nearby target.") + SHARESHEET_NEARBY_TARGET_SELECTED(626), + @UiEvent(doc = "User selected the edit target.") + SHARESHEET_EDIT_TARGET_SELECTED(669), + @UiEvent(doc = "User selected the modify share target.") + SHARESHEET_MODIFY_SHARE_SELECTED(1316), + @UiEvent(doc = "User selected a custom action.") + SHARESHEET_CUSTOM_ACTION_SELECTED(1317); + + private final int mId; + SharesheetTargetSelectedEvent(int id) { + mId = id; + } + @Override public int getId() { + return mId; + } + + public static SharesheetTargetSelectedEvent fromTargetType(int targetType) { + switch(targetType) { + case SELECTION_TYPE_SERVICE: + return SHARESHEET_SERVICE_TARGET_SELECTED; + case SELECTION_TYPE_APP: + return SHARESHEET_APP_TARGET_SELECTED; + case SELECTION_TYPE_STANDARD: + return SHARESHEET_STANDARD_TARGET_SELECTED; + case SELECTION_TYPE_COPY: + return SHARESHEET_COPY_TARGET_SELECTED; + case SELECTION_TYPE_NEARBY: + return SHARESHEET_NEARBY_TARGET_SELECTED; + case SELECTION_TYPE_EDIT: + return SHARESHEET_EDIT_TARGET_SELECTED; + case SELECTION_TYPE_MODIFY_SHARE: + return SHARESHEET_MODIFY_SHARE_SELECTED; + case SELECTION_TYPE_CUSTOM_ACTION: + return SHARESHEET_CUSTOM_ACTION_SELECTED; + default: + return INVALID; + } + } + } + + /** + * The UiEvent enums that this class can log. + */ + enum SharesheetStandardEvent implements UiEventLogger.UiEventEnum { + INVALID(0), + @UiEvent(doc = "User clicked share.") + SHARESHEET_TRIGGERED(227), + @UiEvent(doc = "User changed from work to personal profile or vice versa.") + SHARESHEET_PROFILE_CHANGED(229), + @UiEvent(doc = "User expanded target list.") + SHARESHEET_EXPANDED(230), + @UiEvent(doc = "User collapsed target list.") + SHARESHEET_COLLAPSED(231), + @UiEvent(doc = "Sharesheet app targets is fully populated.") + SHARESHEET_APP_LOAD_COMPLETE(322), + @UiEvent(doc = "Sharesheet direct targets is fully populated.") + SHARESHEET_DIRECT_LOAD_COMPLETE(323), + @UiEvent(doc = "Sharesheet direct targets timed out.") + SHARESHEET_DIRECT_LOAD_TIMEOUT(324), + @UiEvent(doc = "Sharesheet app share ranking timed out.") + SHARESHEET_APP_SHARE_RANKING_TIMEOUT(831), + @UiEvent(doc = "Sharesheet empty direct share row.") + SHARESHEET_EMPTY_DIRECT_SHARE_ROW(828); + + private final int mId; + SharesheetStandardEvent(int id) { + mId = id; + } + @Override public int getId() { + return mId; + } + } + + /** + * Returns the enum used in sharesheet started atom to indicate what preview type was used. + */ + private static int typeFromPreviewInt(int previewType) { + switch(previewType) { + case ContentPreviewType.CONTENT_PREVIEW_IMAGE: + return FrameworkStatsLog.SHARESHEET_STARTED__PREVIEW_TYPE__CONTENT_PREVIEW_IMAGE; + case ContentPreviewType.CONTENT_PREVIEW_FILE: + return FrameworkStatsLog.SHARESHEET_STARTED__PREVIEW_TYPE__CONTENT_PREVIEW_FILE; + case ContentPreviewType.CONTENT_PREVIEW_TEXT: + default: + return FrameworkStatsLog + .SHARESHEET_STARTED__PREVIEW_TYPE__CONTENT_PREVIEW_TYPE_UNKNOWN; + } + } + + /** + * Returns the enum used in sharesheet started atom to indicate what intent triggers the + * ChooserActivity. + */ + private static int typeFromIntentString(String intent) { + if (intent == null) { + return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_DEFAULT; + } + switch (intent) { + case Intent.ACTION_VIEW: + return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_VIEW; + case Intent.ACTION_EDIT: + return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_EDIT; + case Intent.ACTION_SEND: + return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_SEND; + case Intent.ACTION_SENDTO: + return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_SENDTO; + case Intent.ACTION_SEND_MULTIPLE: + return FrameworkStatsLog + .SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_SEND_MULTIPLE; + case MediaStore.ACTION_IMAGE_CAPTURE: + return FrameworkStatsLog + .SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_IMAGE_CAPTURE; + case Intent.ACTION_MAIN: + return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_MAIN; + default: + return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_DEFAULT; + } + } + + @VisibleForTesting + static int getTargetSelectionCategory(int targetType) { + switch (targetType) { + case SELECTION_TYPE_SERVICE: + return MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET; + case SELECTION_TYPE_APP: + return MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET; + case SELECTION_TYPE_STANDARD: + return MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET; + default: + return 0; + } + } + + private static class DefaultFrameworkStatsLogger implements FrameworkStatsLogger { + @Override + public void write( + int frameworkEventId, + int appEventId, + String packageName, + int instanceId, + String mimeType, + int numAppProvidedDirectTargets, + int numAppProvidedAppTargets, + boolean isWorkProfile, + int previewType, + int intentType, + int numCustomActions, + boolean modifyShareActionProvided) { + FrameworkStatsLog.write( + frameworkEventId, + /* event_id = 1 */ appEventId, + /* package_name = 2 */ packageName, + /* instance_id = 3 */ instanceId, + /* mime_type = 4 */ mimeType, + /* num_app_provided_direct_targets */ numAppProvidedDirectTargets, + /* num_app_provided_app_targets */ numAppProvidedAppTargets, + /* is_workprofile */ isWorkProfile, + /* previewType = 8 */ previewType, + /* intentType = 9 */ intentType, + /* num_provided_custom_actions = 10 */ numCustomActions, + /* modify_share_action_provided = 11 */ modifyShareActionProvided); + } + + @Override + public void write( + int frameworkEventId, + int appEventId, + String packageName, + int instanceId, + int positionPicked, + boolean isPinned) { + FrameworkStatsLog.write( + frameworkEventId, + /* event_id = 1 */ appEventId, + /* package_name = 2 */ packageName, + /* instance_id = 3 */ instanceId, + /* position_picked = 4 */ positionPicked, + /* is_pinned = 5 */ isPinned); + } + } +} diff --git a/java/src/com/android/intentresolver/logging/FrameworkStatsLogger.kt b/java/src/com/android/intentresolver/logging/FrameworkStatsLogger.kt new file mode 100644 index 00000000..e0682b9e --- /dev/null +++ b/java/src/com/android/intentresolver/logging/FrameworkStatsLogger.kt @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.intentresolver.logging + +import com.android.internal.util.FrameworkStatsLog + +/** A documenting annotation for FrameworkStatsLog methods and their associated UiEvents. */ +internal annotation class ForUiEvent(vararg val uiEventId: Int) + +/** Isolates the specific method signatures to use for each of the logged UiEvents. */ +internal interface FrameworkStatsLogger { + @ForUiEvent(FrameworkStatsLog.SHARESHEET_STARTED) + fun write( + frameworkEventId: Int, + appEventId: Int, + packageName: String?, + instanceId: Int, + mimeType: String?, + numAppProvidedDirectTargets: Int, + numAppProvidedAppTargets: Int, + isWorkProfile: Boolean, + previewType: Int, + intentType: Int, + numCustomActions: Int, + modifyShareActionProvided: Boolean + ) + + @ForUiEvent(FrameworkStatsLog.RANKING_SELECTED) + fun write( + frameworkEventId: Int, + appEventId: Int, + packageName: String?, + instanceId: Int, + positionPicked: Int, + isPinned: Boolean + ) +} diff --git a/java/src/com/android/intentresolver/model/AbstractResolverComparator.java b/java/src/com/android/intentresolver/model/AbstractResolverComparator.java index ff2d6a0f..932d8590 100644 --- a/java/src/com/android/intentresolver/model/AbstractResolverComparator.java +++ b/java/src/com/android/intentresolver/model/AbstractResolverComparator.java @@ -30,10 +30,11 @@ import android.os.Message; import android.os.UserHandle; import android.util.Log; -import com.android.intentresolver.logging.EventLog; import com.android.intentresolver.ResolvedComponentInfo; import com.android.intentresolver.ResolverActivity; +import com.android.intentresolver.ResolverListController; import com.android.intentresolver.chooser.TargetInfo; +import com.android.intentresolver.logging.EventLog; import java.text.Collator; import java.util.ArrayList; @@ -75,6 +76,7 @@ public abstract class AbstractResolverComparator implements Comparator targetUserSpaceList, - @Nullable ComponentName promoteToFirst) { + String referrerPackage, Runnable afterCompute, EventLog eventLog, + List targetUserSpaceList, @Nullable ComponentName promoteToFirst) { super(launchedFromContext, intent, targetUserSpaceList, promoteToFirst); mCollator = Collator.getInstance( launchedFromContext.getResources().getConfiguration().locale); -- cgit v1.2.3-59-g8ed1b