summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
author Mark Renouf <mrenouf@google.com> 2023-09-14 20:57:57 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-09-14 20:57:57 +0000
commit63cd47c3db33a2901aed2e14f6de8be9997014d9 (patch)
tree5a5933ad762d3161b49fdb943c67958c4fe28146 /java
parent0aff6449c2f52ffb76108be40869d612a5daffc3 (diff)
parentae322c4ddbcb552979fba17a22b931081020014e (diff)
Merge "Injects EventLog, provides FakeEventLog within tests" into main
Diffstat (limited to 'java')
-rw-r--r--java/src/com/android/intentresolver/ChooserActivity.java14
-rw-r--r--java/src/com/android/intentresolver/inject/SingletonModule.kt15
-rw-r--r--java/src/com/android/intentresolver/logging/EventLogImpl.java109
-rw-r--r--java/src/com/android/intentresolver/logging/EventLogModule.kt46
-rw-r--r--java/src/com/android/intentresolver/logging/FrameworkStatsLogger.kt35
-rw-r--r--java/tests/src/com/android/intentresolver/ChooserActionFactoryTest.kt3
-rw-r--r--java/tests/src/com/android/intentresolver/ChooserActivityOverrideData.java3
-rw-r--r--java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java6
-rw-r--r--java/tests/src/com/android/intentresolver/IChooserWrapper.java2
-rw-r--r--java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java205
-rw-r--r--java/tests/src/com/android/intentresolver/logging/EventLogImplTest.java10
-rw-r--r--java/tests/src/com/android/intentresolver/logging/FakeEventLog.kt197
-rw-r--r--java/tests/src/com/android/intentresolver/logging/FakeFrameworkStatsLogger.kt95
-rw-r--r--java/tests/src/com/android/intentresolver/logging/TestEventLogModule.kt39
14 files changed, 559 insertions, 220 deletions
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java
index c27d3bac..acfd3572 100644
--- a/java/src/com/android/intentresolver/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/ChooserActivity.java
@@ -85,7 +85,6 @@ 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;
@@ -172,6 +171,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
public @interface ShareTargetType {}
@Inject public FeatureFlags mFeatureFlags;
+ @Inject public EventLog mEventLog;
private ChooserIntegratedDeviceComponents mIntegratedDeviceComponents;
@@ -189,9 +189,6 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
private ChooserContentPreviewUi mChooserContentPreviewUi;
private boolean mShouldDisplayLandscape;
- // statsd logger wrapper
- protected EventLog mEventLog;
-
private long mChooserShownTime;
protected boolean mIsSuccessfullySelected;
@@ -237,8 +234,6 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
final long intentReceivedTime = System.currentTimeMillis();
mLatencyTracker.onActionStart(ACTION_LOAD_SHARE_SHEET);
- getEventLog().logSharesheetTriggered();
-
try {
mChooserRequest = new ChooserRequestParameters(
getIntent(),
@@ -276,6 +271,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
new DefaultTargetDataLoader(this, getLifecycle(), false),
/* safeForwardingMode= */ true);
+ getEventLog().logSharesheetTriggered();
+
mIntegratedDeviceComponents = getIntegratedDeviceComponents();
mRefinementManager = new ViewModelProvider(this).get(ChooserRefinementManager.class);
@@ -1107,9 +1104,6 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
}
protected EventLog getEventLog() {
- if (mEventLog == null) {
- mEventLog = new EventLogImpl();
- }
return mEventLog;
}
@@ -1573,6 +1567,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation);
mChooserMultiProfilePagerAdapter.getActiveAdapterView().addOnScrollListener(
new RecyclerView.OnScrollListener() {
+ @Override
public void onScrollStateChanged(RecyclerView view, int scrollState) {
if (scrollState == RecyclerView.SCROLL_STATE_IDLE) {
if (mScrollStatus == SCROLL_STATUS_SCROLLING_VERTICAL) {
@@ -1587,6 +1582,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
}
}
+ @Override
public void onScrolled(RecyclerView view, int dx, int dy) {
if (view.getChildCount() > 0) {
View child = view.getLayoutManager().findViewByPosition(0);
diff --git a/java/src/com/android/intentresolver/inject/SingletonModule.kt b/java/src/com/android/intentresolver/inject/SingletonModule.kt
new file mode 100644
index 00000000..fbda8be6
--- /dev/null
+++ b/java/src/com/android/intentresolver/inject/SingletonModule.kt
@@ -0,0 +1,15 @@
+package com.android.intentresolver.inject
+
+import com.android.intentresolver.logging.EventLogImpl
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@InstallIn(SingletonComponent::class)
+@Module
+class SingletonModule {
+
+ @Provides @Singleton fun instanceIdSequence() = EventLogImpl.newIdSequence()
+}
diff --git a/java/src/com/android/intentresolver/logging/EventLogImpl.java b/java/src/com/android/intentresolver/logging/EventLogImpl.java
index 33e617b1..26c79d00 100644
--- a/java/src/com/android/intentresolver/logging/EventLogImpl.java
+++ b/java/src/com/android/intentresolver/logging/EventLogImpl.java
@@ -32,10 +32,13 @@ 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;
+import javax.inject.Inject;
+
+import dagger.hilt.android.scopes.ActivityScoped;
+
/**
* Helper for writing Sharesheet atoms to statsd log.
*/
@@ -45,29 +48,26 @@ public class EventLogImpl implements EventLog {
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 InstanceId mInstanceId;
private final UiEventLogger mUiEventLogger;
private final FrameworkStatsLogger mFrameworkStatsLogger;
private final MetricsLogger mMetricsLogger;
- public EventLogImpl() {
- this(new UiEventLoggerImpl(), new DefaultFrameworkStatsLogger(), new MetricsLogger());
+ public static InstanceIdSequence newIdSequence() {
+ return new InstanceIdSequence(SHARESHEET_INSTANCE_ID_MAX);
}
- @VisibleForTesting
- EventLogImpl(
- UiEventLogger uiEventLogger,
- FrameworkStatsLogger frameworkLogger,
- MetricsLogger metricsLogger) {
+ @Inject
+ public EventLogImpl(UiEventLogger uiEventLogger, FrameworkStatsLogger frameworkLogger,
+ MetricsLogger metricsLogger, InstanceId instanceId) {
mUiEventLogger = uiEventLogger;
mFrameworkStatsLogger = frameworkLogger;
mMetricsLogger = metricsLogger;
+ mInstanceId = instanceId;
}
+
/** Records metrics for the start time of the {@link ChooserActivity}. */
@Override
public void logChooserActivityShown(
@@ -94,7 +94,7 @@ public class EventLogImpl implements EventLog {
mFrameworkStatsLogger.write(FrameworkStatsLog.SHARESHEET_STARTED,
/* event_id = 1 */ SharesheetStartedEvent.SHARE_STARTED.getId(),
/* package_name = 2 */ packageName,
- /* instance_id = 3 */ getInstanceId().getId(),
+ /* instance_id = 3 */ mInstanceId.getId(),
/* mime_type = 4 */ mimeType,
/* num_app_provided_direct_targets = 5 */ appProvidedDirect,
/* num_app_provided_app_targets = 6 */ appProvidedApp,
@@ -116,7 +116,7 @@ public class EventLogImpl implements EventLog {
/* event_id = 1 */
SharesheetTargetSelectedEvent.SHARESHEET_CUSTOM_ACTION_SELECTED.getId(),
/* package_name = 2 */ null,
- /* instance_id = 3 */ getInstanceId().getId(),
+ /* instance_id = 3 */ mInstanceId.getId(),
/* position_picked = 4 */ positionPicked,
/* is_pinned = 5 */ false);
}
@@ -140,7 +140,7 @@ public class EventLogImpl implements EventLog {
mFrameworkStatsLogger.write(FrameworkStatsLog.RANKING_SELECTED,
/* event_id = 1 */ SharesheetTargetSelectedEvent.fromTargetType(targetType).getId(),
/* package_name = 2 */ packageName,
- /* instance_id = 3 */ getInstanceId().getId(),
+ /* instance_id = 3 */ mInstanceId.getId(),
/* position_picked = 4 */ positionPicked,
/* is_pinned = 5 */ isPinned);
@@ -198,7 +198,7 @@ public class EventLogImpl implements EventLog {
mFrameworkStatsLogger.write(FrameworkStatsLog.RANKING_SELECTED,
/* event_id = 1 */ SharesheetTargetSelectedEvent.fromTargetType(targetType).getId(),
/* package_name = 2 */ "",
- /* instance_id = 3 */ getInstanceId().getId(),
+ /* instance_id = 3 */ mInstanceId.getId(),
/* position_picked = 4 */ -1,
/* is_pinned = 5 */ false);
}
@@ -217,13 +217,13 @@ public class EventLogImpl implements EventLog {
/** Logs a UiEventReported event for the system sharesheet being triggered by the user. */
@Override
public void logSharesheetTriggered() {
- log(SharesheetStandardEvent.SHARESHEET_TRIGGERED, getInstanceId());
+ log(SharesheetStandardEvent.SHARESHEET_TRIGGERED, mInstanceId);
}
/** Logs a UiEventReported event for the system sharesheet completing loading app targets. */
@Override
public void logSharesheetAppLoadComplete() {
- log(SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE, getInstanceId());
+ log(SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE, mInstanceId);
}
/**
@@ -231,7 +231,7 @@ public class EventLogImpl implements EventLog {
*/
@Override
public void logSharesheetDirectLoadComplete() {
- log(SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE, getInstanceId());
+ log(SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE, mInstanceId);
}
/**
@@ -239,7 +239,7 @@ public class EventLogImpl implements EventLog {
*/
@Override
public void logSharesheetDirectLoadTimeout() {
- log(SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_TIMEOUT, getInstanceId());
+ log(SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_TIMEOUT, mInstanceId);
}
/**
@@ -248,14 +248,14 @@ public class EventLogImpl implements EventLog {
*/
@Override
public void logSharesheetProfileChanged() {
- log(SharesheetStandardEvent.SHARESHEET_PROFILE_CHANGED, getInstanceId());
+ log(SharesheetStandardEvent.SHARESHEET_PROFILE_CHANGED, mInstanceId);
}
/** 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());
+ SharesheetStandardEvent.SHARESHEET_EXPANDED, mInstanceId);
}
/**
@@ -263,7 +263,7 @@ public class EventLogImpl implements EventLog {
*/
@Override
public void logSharesheetAppShareRankingTimeout() {
- log(SharesheetStandardEvent.SHARESHEET_APP_SHARE_RANKING_TIMEOUT, getInstanceId());
+ log(SharesheetStandardEvent.SHARESHEET_APP_SHARE_RANKING_TIMEOUT, mInstanceId);
}
/**
@@ -271,7 +271,7 @@ public class EventLogImpl implements EventLog {
*/
@Override
public void logSharesheetEmptyDirectShareRow() {
- log(SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW, getInstanceId());
+ log(SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW, mInstanceId);
}
/**
@@ -288,19 +288,6 @@ public class EventLogImpl implements EventLog {
}
/**
- * @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 {
@@ -463,52 +450,4 @@ public class EventLogImpl implements EventLog {
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/EventLogModule.kt b/java/src/com/android/intentresolver/logging/EventLogModule.kt
new file mode 100644
index 00000000..eba8ecc8
--- /dev/null
+++ b/java/src/com/android/intentresolver/logging/EventLogModule.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.logging.InstanceId
+import com.android.internal.logging.InstanceIdSequence
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.logging.UiEventLoggerImpl
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ActivityComponent
+import dagger.hilt.android.scopes.ActivityScoped
+
+@Module
+@InstallIn(ActivityComponent::class)
+interface EventLogModule {
+
+ @Binds @ActivityScoped fun eventLog(value: EventLogImpl): EventLog
+
+ companion object {
+ @Provides
+ fun instanceId(sequence: InstanceIdSequence): InstanceId = sequence.newInstanceId()
+
+ @Provides fun uiEventLogger(): UiEventLogger = UiEventLoggerImpl()
+
+ @Provides fun frameworkLogger(): FrameworkStatsLogger = object : FrameworkStatsLogger {}
+
+ @Provides fun metricsLogger(): MetricsLogger = MetricsLogger()
+ }
+}
diff --git a/java/src/com/android/intentresolver/logging/FrameworkStatsLogger.kt b/java/src/com/android/intentresolver/logging/FrameworkStatsLogger.kt
index e0682b9e..6508d305 100644
--- a/java/src/com/android/intentresolver/logging/FrameworkStatsLogger.kt
+++ b/java/src/com/android/intentresolver/logging/FrameworkStatsLogger.kt
@@ -21,7 +21,8 @@ import com.android.internal.util.FrameworkStatsLog
internal annotation class ForUiEvent(vararg val uiEventId: Int)
/** Isolates the specific method signatures to use for each of the logged UiEvents. */
-internal interface FrameworkStatsLogger {
+interface FrameworkStatsLogger {
+
@ForUiEvent(FrameworkStatsLog.SHARESHEET_STARTED)
fun write(
frameworkEventId: Int,
@@ -35,8 +36,23 @@ internal interface FrameworkStatsLogger {
previewType: Int,
intentType: Int,
numCustomActions: Int,
- modifyShareActionProvided: Boolean
- )
+ modifyShareActionProvided: Boolean,
+ ) {
+ 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
+ )
+ }
@ForUiEvent(FrameworkStatsLog.RANKING_SELECTED)
fun write(
@@ -45,6 +61,15 @@ internal interface FrameworkStatsLogger {
packageName: String?,
instanceId: Int,
positionPicked: Int,
- isPinned: Boolean
- )
+ isPinned: Boolean,
+ ) {
+ 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/tests/src/com/android/intentresolver/ChooserActionFactoryTest.kt b/java/tests/src/com/android/intentresolver/ChooserActionFactoryTest.kt
index e2b987c2..2d1ac4e4 100644
--- a/java/tests/src/com/android/intentresolver/ChooserActionFactoryTest.kt
+++ b/java/tests/src/com/android/intentresolver/ChooserActionFactoryTest.kt
@@ -28,13 +28,12 @@ import android.graphics.drawable.Icon
import android.service.chooser.ChooserAction
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.intentresolver.logging.EventLogImpl
+import com.android.intentresolver.logging.EventLog
import com.google.common.collect.ImmutableList
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.function.Consumer
-import com.android.intentresolver.logging.EventLog
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
diff --git a/java/tests/src/com/android/intentresolver/ChooserActivityOverrideData.java b/java/tests/src/com/android/intentresolver/ChooserActivityOverrideData.java
index b5c14ff1..d77aa099 100644
--- a/java/tests/src/com/android/intentresolver/ChooserActivityOverrideData.java
+++ b/java/tests/src/com/android/intentresolver/ChooserActivityOverrideData.java
@@ -29,7 +29,6 @@ import android.os.UserHandle;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.CrossProfileIntentsChecker;
import com.android.intentresolver.chooser.TargetInfo;
import com.android.intentresolver.contentpreview.ImageLoader;
-import com.android.intentresolver.logging.EventLogImpl;
import com.android.intentresolver.shortcuts.ShortcutLoader;
import java.util.function.Consumer;
@@ -64,7 +63,6 @@ public class ChooserActivityOverrideData {
public Cursor resolverCursor;
public boolean resolverForceException;
public ImageLoader imageLoader;
- public EventLogImpl mEventLog;
public int alternateProfileSetting;
public Resources resources;
public UserHandle workProfileUserHandle;
@@ -86,7 +84,6 @@ public class ChooserActivityOverrideData {
resolverForceException = false;
resolverListController = mock(ChooserActivity.ChooserListController.class);
workResolverListController = mock(ChooserActivity.ChooserListController.class);
- mEventLog = mock(EventLogImpl.class);
alternateProfileSetting = 0;
resources = null;
workProfileUserHandle = null;
diff --git a/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java b/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java
index d488e02b..27b7037f 100644
--- a/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java
+++ b/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java
@@ -39,7 +39,6 @@ import com.android.intentresolver.chooser.DisplayResolveInfo;
import com.android.intentresolver.chooser.TargetInfo;
import com.android.intentresolver.grid.ChooserGridAdapter;
import com.android.intentresolver.icons.TargetDataLoader;
-import com.android.intentresolver.logging.EventLogImpl;
import com.android.intentresolver.shortcuts.ShortcutLoader;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -204,11 +203,6 @@ public class ChooserWrapperActivity extends ChooserActivity implements IChooserW
}
@Override
- public EventLogImpl getEventLog() {
- return sOverrides.mEventLog;
- }
-
- @Override
public Cursor queryResolver(ContentResolver resolver, Uri uri) {
if (sOverrides.resolverCursor != null) {
return sOverrides.resolverCursor;
diff --git a/java/tests/src/com/android/intentresolver/IChooserWrapper.java b/java/tests/src/com/android/intentresolver/IChooserWrapper.java
index 54e4da9e..d439b037 100644
--- a/java/tests/src/com/android/intentresolver/IChooserWrapper.java
+++ b/java/tests/src/com/android/intentresolver/IChooserWrapper.java
@@ -23,7 +23,6 @@ import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import com.android.intentresolver.chooser.DisplayResolveInfo;
-import com.android.intentresolver.logging.EventLogImpl;
import java.util.concurrent.Executor;
@@ -42,6 +41,5 @@ public interface IChooserWrapper {
CharSequence pLabel, CharSequence pInfo, Intent replacementIntent,
@Nullable TargetPresentationGetter resolveInfoPresentationGetter);
UserHandle getCurrentUserHandle();
- EventLogImpl getEventLog();
Executor getMainExecutor();
}
diff --git a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java
index 0b3cb20a..9f16ced5 100644
--- a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java
+++ b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java
@@ -36,6 +36,7 @@ import static com.android.intentresolver.ChooserListAdapter.CALLER_TARGET_SCORE_
import static com.android.intentresolver.ChooserListAdapter.SHORTCUT_TARGET_SCORE_BOOST;
import static com.android.intentresolver.MatcherUtils.first;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static junit.framework.Assert.assertNull;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.is;
@@ -44,9 +45,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -93,7 +92,6 @@ import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
import android.text.style.UnderlineSpan;
-import android.util.HashedStringCache;
import android.util.Pair;
import android.util.SparseArray;
import android.view.View;
@@ -113,11 +111,14 @@ import androidx.test.rule.ActivityTestRule;
import com.android.intentresolver.chooser.DisplayResolveInfo;
import com.android.intentresolver.contentpreview.ImageLoader;
import com.android.intentresolver.logging.EventLog;
-import com.android.intentresolver.logging.EventLogImpl;
+import com.android.intentresolver.logging.FakeEventLog;
import com.android.intentresolver.shortcuts.ShortcutLoader;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import dagger.hilt.android.testing.HiltAndroidRule;
+import dagger.hilt.android.testing.HiltAndroidTest;
+
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
@@ -146,9 +147,6 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-
/**
* Instrumentation tests for ChooserActivity.
* <p>
@@ -159,6 +157,10 @@ import dagger.hilt.android.testing.HiltAndroidTest;
@HiltAndroidTest
public class UnbundledChooserActivityTest {
+ private static FakeEventLog getEventLog(ChooserWrapperActivity activity) {
+ return (FakeEventLog) activity.mEventLog;
+ }
+
private static final UserHandle PERSONAL_USER_HANDLE = InstrumentationRegistry
.getInstrumentation().getTargetContext().getUser();
private static final Function<PackageManager, PackageManager> DEFAULT_PM = pm -> pm;
@@ -179,6 +181,20 @@ public class UnbundledChooserActivityTest {
});
}
+ private static final String TEST_MIME_TYPE = "application/TestType";
+
+ 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(order = 0)
+ public HiltAndroidRule mHiltAndroidRule = new HiltAndroidRule(this);
+
+ @Rule(order = 1)
+ public ActivityTestRule<ChooserWrapperActivity> mActivityRule =
+ new ActivityTestRule<>(ChooserWrapperActivity.class, false, false);
+
@Before
public void setUp() {
// TODO: use the other form of `adoptShellPermissionIdentity()` where we explicitly list the
@@ -189,21 +205,9 @@ public class UnbundledChooserActivityTest {
.adoptShellPermissionIdentity();
cleanOverrideData();
+ mHiltAndroidRule.inject();
}
- @Rule(order = 0)
- public HiltAndroidRule mHiltAndroidRule = new HiltAndroidRule(this);
-
- @Rule(order = 1)
- public ActivityTestRule<ChooserWrapperActivity> mActivityRule =
- new ActivityTestRule<>(ChooserWrapperActivity.class, false, false);
-
- private static final String TEST_MIME_TYPE = "application/TestType";
-
- private static final int CONTENT_PREVIEW_IMAGE = 1;
- private static final int CONTENT_PREVIEW_FILE = 2;
- private static final int CONTENT_PREVIEW_TEXT = 3;
-
private final Function<PackageManager, PackageManager> mPackageManagerOverride;
public UnbundledChooserActivityTest(
@@ -845,15 +849,16 @@ public class UnbundledChooserActivityTest {
setupResolverControllers(resolvedComponentInfos);
- final IChooserWrapper activity = (IChooserWrapper)
+ ChooserWrapperActivity activity =
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
onView(withId(R.id.copy)).check(matches(isDisplayed()));
onView(withId(R.id.copy)).perform(click());
-
- EventLog logger = activity.getEventLog();
- verify(logger, times(1)).logActionSelected(eq(EventLogImpl.SELECTION_TYPE_COPY));
+ FakeEventLog eventLog = getEventLog(activity);
+ assertThat(eventLog.getActionSelected())
+ .isEqualTo(new FakeEventLog.ActionSelected(
+ /* targetType = */ EventLog.SELECTION_TYPE_COPY));
}
@Test
@@ -864,8 +869,7 @@ public class UnbundledChooserActivityTest {
setupResolverControllers(resolvedComponentInfos);
- final IChooserWrapper activity = (IChooserWrapper)
- mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
onView(withId(com.android.internal.R.id.chooser_nearby_button))
@@ -888,8 +892,7 @@ public class UnbundledChooserActivityTest {
setupResolverControllers(resolvedComponentInfos);
- final IChooserWrapper activity = (IChooserWrapper)
- mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
onView(withId(com.android.internal.R.id.chooser_edit_button)).check(matches(isDisplayed()));
@@ -1200,12 +1203,15 @@ public class UnbundledChooserActivityTest {
Intent sendIntent = createSendTextIntent();
sendIntent.setType(TEST_MIME_TYPE);
- final IChooserWrapper activity = (IChooserWrapper)
+ ChooserWrapperActivity activity =
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test"));
- EventLog logger = activity.getEventLog();
waitForIdle();
- verify(logger).logChooserActivityShown(eq(false), eq(TEST_MIME_TYPE), anyLong());
+ FakeEventLog eventLog = getEventLog(activity);
+ FakeEventLog.ChooserActivityShown event = eventLog.getChooserActivityShown();
+ assertThat(event).isNotNull();
+ assertThat(event.isWorkProfile()).isFalse();
+ assertThat(event.getTargetMimeType()).isEqualTo(TEST_MIME_TYPE);
}
@Test
@@ -1215,25 +1221,31 @@ public class UnbundledChooserActivityTest {
ChooserActivityOverrideData.getInstance().alternateProfileSetting =
MetricsEvent.MANAGED_PROFILE;
- final IChooserWrapper activity = (IChooserWrapper)
+ ChooserWrapperActivity activity =
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test"));
- EventLog logger = activity.getEventLog();
waitForIdle();
- verify(logger).logChooserActivityShown(eq(true), eq(TEST_MIME_TYPE), anyLong());
+ FakeEventLog eventLog = getEventLog(activity);
+ FakeEventLog.ChooserActivityShown event = eventLog.getChooserActivityShown();
+ assertThat(event).isNotNull();
+ assertThat(event.isWorkProfile()).isTrue();
+ assertThat(event.getTargetMimeType()).isEqualTo(TEST_MIME_TYPE);
}
@Test
public void testEmptyPreviewLogging() {
Intent sendIntent = createSendTextIntentWithPreview(null, null);
- final IChooserWrapper activity = (IChooserWrapper)
- mActivityRule.launchActivity(
- Intent.createChooser(sendIntent, "empty preview logger test"));
- EventLog logger = activity.getEventLog();
+ ChooserWrapperActivity activity =
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent,
+ "empty preview logger test"));
waitForIdle();
- verify(logger).logChooserActivityShown(eq(false), eq(null), anyLong());
+ FakeEventLog eventLog = getEventLog(activity);
+ FakeEventLog.ChooserActivityShown event = eventLog.getChooserActivityShown();
+ assertThat(event).isNotNull();
+ assertThat(event.isWorkProfile()).isFalse();
+ assertThat(event.getTargetMimeType()).isNull();
}
@Test
@@ -1244,13 +1256,14 @@ public class UnbundledChooserActivityTest {
setupResolverControllers(resolvedComponentInfos);
- final IChooserWrapper activity = (IChooserWrapper)
+ ChooserWrapperActivity activity =
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- // Second invocation is from onCreate
- EventLog logger = activity.getEventLog();
- Mockito.verify(logger, times(1)).logActionShareWithPreview(eq(CONTENT_PREVIEW_TEXT));
+ FakeEventLog eventLog = getEventLog(activity);
+ assertThat(eventLog.getActionShareWithPreview())
+ .isEqualTo(new FakeEventLog.ActionShareWithPreview(
+ /* previewType = */ CONTENT_PREVIEW_TEXT));
}
@Test
@@ -1268,11 +1281,14 @@ public class UnbundledChooserActivityTest {
setupResolverControllers(resolvedComponentInfos);
- final IChooserWrapper activity = (IChooserWrapper)
+ ChooserWrapperActivity activity =
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- EventLog logger = activity.getEventLog();
- Mockito.verify(logger, times(1)).logActionShareWithPreview(eq(CONTENT_PREVIEW_IMAGE));
+
+ FakeEventLog eventLog = getEventLog(activity);
+ assertThat(eventLog.getActionShareWithPreview())
+ .isEqualTo(new FakeEventLog.ActionShareWithPreview(
+ /* previewType = */ CONTENT_PREVIEW_IMAGE));
}
@Test
@@ -1421,7 +1437,7 @@ public class UnbundledChooserActivityTest {
createShortcutLoaderFactory();
// Start activity
- final IChooserWrapper activity = (IChooserWrapper)
+ ChooserWrapperActivity activity =
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
@@ -1471,22 +1487,15 @@ public class UnbundledChooserActivityTest {
.perform(click());
waitForIdle();
- ArgumentCaptor<HashedStringCache.HashResult> hashCaptor =
- ArgumentCaptor.forClass(HashedStringCache.HashResult.class);
- verify(activity.getEventLog(), times(1)).logShareTargetSelected(
- eq(EventLogImpl.SELECTION_TYPE_SERVICE),
- /* packageName= */ any(),
- /* positionPicked= */ anyInt(),
- /* directTargetAlsoRanked= */ eq(-1),
- /* numCallerProvided= */ anyInt(),
- /* directTargetHashed= */ hashCaptor.capture(),
- /* isPinned= */ anyBoolean(),
- /* successfullySelected= */ anyBoolean(),
- /* selectionCost= */ anyLong());
- String hashedName = hashCaptor.getValue().hashedString;
- assertThat(
- "Hash is not predictable but must be obfuscated",
- hashedName, is(not(name)));
+ FakeEventLog eventLog = getEventLog(activity);
+ assertThat(eventLog.getShareTargetSelected()).hasSize(1);
+ FakeEventLog.ShareTargetSelected call = eventLog.getShareTargetSelected().get(0);
+ assertThat(call.getTargetType()).isEqualTo(EventLog.SELECTION_TYPE_SERVICE);
+ assertThat(call.getDirectTargetAlsoRanked()).isEqualTo(-1);
+ var hashResult = call.getDirectTargetHashed();
+ var hash = hashResult == null ? "" : hashResult.hashedString;
+ assertWithMessage("Hash is not predictable but must be obfuscated")
+ .that(hash).isNotEqualTo(name);
}
// This test is too long and too slow and should not be taken as an example for future tests.
@@ -1502,7 +1511,7 @@ public class UnbundledChooserActivityTest {
createShortcutLoaderFactory();
// Start activity
- final IChooserWrapper activity = (IChooserWrapper)
+ ChooserWrapperActivity activity =
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
@@ -1554,16 +1563,12 @@ public class UnbundledChooserActivityTest {
.perform(click());
waitForIdle();
- verify(activity.getEventLog(), times(1)).logShareTargetSelected(
- eq(EventLogImpl.SELECTION_TYPE_SERVICE),
- /* packageName= */ any(),
- /* positionPicked= */ anyInt(),
- /* directTargetAlsoRanked= */ eq(0),
- /* numCallerProvided= */ anyInt(),
- /* directTargetHashed= */ any(),
- /* isPinned= */ anyBoolean(),
- /* successfullySelected= */ anyBoolean(),
- /* selectionCost= */ anyLong());
+ FakeEventLog eventLog = getEventLog(activity);
+ assertThat(eventLog.getShareTargetSelected()).hasSize(1);
+ FakeEventLog.ShareTargetSelected call = eventLog.getShareTargetSelected().get(0);
+
+ assertThat(call.getTargetType()).isEqualTo(EventLog.SELECTION_TYPE_SERVICE);
+ assertThat(call.getDirectTargetAlsoRanked()).isEqualTo(0);
}
@Test
@@ -1935,14 +1940,14 @@ public class UnbundledChooserActivityTest {
ResolveInfo ri = ResolverDataProvider.createResolveInfo(16, 0, PERSONAL_USER_HANDLE);
// Start activity
- final IChooserWrapper wrapper = (IChooserWrapper)
+ ChooserWrapperActivity activity =
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
// Insert the direct share target
Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>();
directShareToShortcutInfos.put(serviceTargets.get(0), null);
InstrumentationRegistry.getInstrumentation().runOnMainSync(
- () -> wrapper.getAdapter().addServiceResults(
- wrapper.createTestDisplayResolveInfo(sendIntent,
+ () -> activity.getAdapter().addServiceResults(
+ activity.createTestDisplayResolveInfo(sendIntent,
ri,
"testLabel",
"testInfo",
@@ -1957,11 +1962,11 @@ public class UnbundledChooserActivityTest {
assertThat(
String.format("Chooser should have %d targets (%d apps, 1 direct, 15 A-Z)",
appTargetsExpected + 16, appTargetsExpected),
- wrapper.getAdapter().getCount(), is(appTargetsExpected + 16));
+ activity.getAdapter().getCount(), is(appTargetsExpected + 16));
assertThat("Chooser should have exactly one selectable direct target",
- wrapper.getAdapter().getSelectableServiceTargetCount(), is(1));
+ activity.getAdapter().getSelectableServiceTargetCount(), is(1));
assertThat("The resolver info must match the resolver info used to create the target",
- wrapper.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();
@@ -1969,18 +1974,16 @@ public class UnbundledChooserActivityTest {
.perform(click());
waitForIdle();
- EventLog logger = wrapper.getEventLog();
- verify(logger, times(1)).logShareTargetSelected(
- eq(EventLogImpl.SELECTION_TYPE_SERVICE),
- /* packageName= */ any(),
- /* positionPicked= */ anyInt(),
- // The packages sholdn't match for app target and direct target:
- /* directTargetAlsoRanked= */ eq(-1),
- /* numCallerProvided= */ anyInt(),
- /* directTargetHashed= */ any(),
- /* isPinned= */ anyBoolean(),
- /* successfullySelected= */ anyBoolean(),
- /* selectionCost= */ anyLong());
+ FakeEventLog eventLog = getEventLog(activity);
+ var invocations = eventLog.getShareTargetSelected();
+ assertWithMessage("Only one ShareTargetSelected event logged")
+ .that(invocations).hasSize(1);
+ FakeEventLog.ShareTargetSelected call = invocations.get(0);
+ assertWithMessage("targetType should be SELECTION_TYPE_SERVICE")
+ .that(call.getTargetType()).isEqualTo(EventLog.SELECTION_TYPE_SERVICE);
+ assertWithMessage(
+ "The packages shouldn't match for app target and direct target")
+ .that(call.getDirectTargetAlsoRanked()).isEqualTo(-1);
}
@Test
@@ -2253,7 +2256,7 @@ public class UnbundledChooserActivityTest {
};
// Start activity
- final IChooserWrapper activity = (IChooserWrapper)
+ ChooserWrapperActivity activity =
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
@@ -2301,18 +2304,10 @@ public class UnbundledChooserActivityTest {
.perform(click());
waitForIdle();
- EventLog logger = activity.getEventLog();
- ArgumentCaptor<Integer> typeCaptor = ArgumentCaptor.forClass(Integer.class);
- verify(logger, times(1)).logShareTargetSelected(
- eq(EventLogImpl.SELECTION_TYPE_SERVICE),
- /* packageName= */ any(),
- /* positionPicked= */ anyInt(),
- /* directTargetAlsoRanked= */ anyInt(),
- /* numCallerProvided= */ anyInt(),
- /* directTargetHashed= */ any(),
- /* isPinned= */ anyBoolean(),
- /* successfullySelected= */ anyBoolean(),
- /* selectionCost= */ anyLong());
+ FakeEventLog eventLog = getEventLog(activity);
+ assertThat(eventLog.getShareTargetSelected()).hasSize(1);
+ FakeEventLog.ShareTargetSelected call = eventLog.getShareTargetSelected().get(0);
+ assertThat(call.getTargetType()).isEqualTo(EventLog.SELECTION_TYPE_SERVICE);
}
@Test
diff --git a/java/tests/src/com/android/intentresolver/logging/EventLogImplTest.java b/java/tests/src/com/android/intentresolver/logging/EventLogImplTest.java
index 19177798..d75ea99b 100644
--- a/java/tests/src/com/android/intentresolver/logging/EventLogImplTest.java
+++ b/java/tests/src/com/android/intentresolver/logging/EventLogImplTest.java
@@ -37,6 +37,7 @@ import com.android.intentresolver.logging.EventLogImpl.SharesheetStartedEvent;
import com.android.intentresolver.logging.EventLogImpl.SharesheetTargetSelectedEvent;
import com.android.intentresolver.contentpreview.ContentPreviewType;
import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLogger.UiEventEnum;
@@ -59,10 +60,12 @@ public final class EventLogImplTest {
private EventLogImpl mChooserLogger;
+ private final InstanceIdSequence mSequence = EventLogImpl.newIdSequence();
+
@Before
public void setUp() {
- //Mockito.reset(mUiEventLog, mFrameworkLog, mMetricsLogger);
- mChooserLogger = new EventLogImpl(mUiEventLog, mFrameworkLog, mMetricsLogger);
+ mChooserLogger = new EventLogImpl(mUiEventLog, mFrameworkLog, mMetricsLogger,
+ mSequence.newInstanceId());
}
@After
@@ -320,7 +323,8 @@ public final class EventLogImplTest {
public void testDifferentLoggerInstancesUseDifferentInstanceIds() {
ArgumentCaptor<Integer> idIntCaptor = ArgumentCaptor.forClass(Integer.class);
EventLogImpl chooserLogger2 =
- new EventLogImpl(mUiEventLog, mFrameworkLog, mMetricsLogger);
+ new EventLogImpl(mUiEventLog, mFrameworkLog, mMetricsLogger,
+ mSequence.newInstanceId());
final int targetType = EventLogImpl.SELECTION_TYPE_COPY;
final String packageName = "com.test.foo";
diff --git a/java/tests/src/com/android/intentresolver/logging/FakeEventLog.kt b/java/tests/src/com/android/intentresolver/logging/FakeEventLog.kt
new file mode 100644
index 00000000..9ed47db6
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/logging/FakeEventLog.kt
@@ -0,0 +1,197 @@
+/*
+ * 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
+import android.util.Log
+import com.android.internal.logging.InstanceId
+import javax.inject.Inject
+
+private const val TAG = "EventLog"
+private const val LOG = true
+
+/** A fake EventLog. */
+class FakeEventLog @Inject constructor(private val instanceId: InstanceId) : EventLog {
+
+ var chooserActivityShown: ChooserActivityShown? = null
+ var actionSelected: ActionSelected? = null
+ var customActionSelected: CustomActionSelected? = null
+ var actionShareWithPreview: ActionShareWithPreview? = null
+ val shareTargetSelected: MutableList<ShareTargetSelected> = mutableListOf()
+
+ private fun log(message: () -> Any?) {
+ if (LOG) {
+ Log.d(TAG, "[%04x] ".format(instanceId.id) + message())
+ }
+ }
+
+ override fun logChooserActivityShown(
+ isWorkProfile: Boolean,
+ targetMimeType: String?,
+ systemCost: Long
+ ) {
+ chooserActivityShown = ChooserActivityShown(isWorkProfile, targetMimeType, systemCost)
+ log { chooserActivityShown }
+ }
+
+ override fun logShareStarted(
+ packageName: String?,
+ mimeType: String?,
+ appProvidedDirect: Int,
+ appProvidedApp: Int,
+ isWorkprofile: Boolean,
+ previewType: Int,
+ intent: String?,
+ customActionCount: Int,
+ modifyShareActionProvided: Boolean
+ ) {
+ log {
+ ShareStarted(
+ packageName,
+ mimeType,
+ appProvidedDirect,
+ appProvidedApp,
+ isWorkprofile,
+ previewType,
+ intent,
+ customActionCount,
+ modifyShareActionProvided
+ )
+ }
+ }
+
+ override fun logCustomActionSelected(positionPicked: Int) {
+ customActionSelected = CustomActionSelected(positionPicked)
+ log { "logCustomActionSelected(positionPicked=$positionPicked)" }
+ }
+
+ override fun logShareTargetSelected(
+ targetType: Int,
+ packageName: String?,
+ positionPicked: Int,
+ directTargetAlsoRanked: Int,
+ numCallerProvided: Int,
+ directTargetHashed: HashedStringCache.HashResult?,
+ isPinned: Boolean,
+ successfullySelected: Boolean,
+ selectionCost: Long
+ ) {
+ shareTargetSelected.add(
+ ShareTargetSelected(
+ targetType,
+ packageName,
+ positionPicked,
+ directTargetAlsoRanked,
+ numCallerProvided,
+ directTargetHashed,
+ isPinned,
+ successfullySelected,
+ selectionCost
+ )
+ )
+ log { shareTargetSelected.last() }
+ shareTargetSelected.limitSize(10)
+ }
+
+ private fun MutableList<*>.limitSize(n: Int) {
+ while (size > n) {
+ removeFirst()
+ }
+ }
+
+ override fun logDirectShareTargetReceived(category: Int, latency: Int) {
+ log { "logDirectShareTargetReceived(category=$category, latency=$latency)" }
+ }
+
+ override fun logActionShareWithPreview(previewType: Int) {
+ actionShareWithPreview = ActionShareWithPreview(previewType)
+ log { actionShareWithPreview }
+ }
+
+ override fun logActionSelected(targetType: Int) {
+ actionSelected = ActionSelected(targetType)
+ log { actionSelected }
+ }
+
+ override fun logContentPreviewWarning(uri: Uri?) {
+ log { "logContentPreviewWarning(uri=$uri)" }
+ }
+
+ override fun logSharesheetTriggered() {
+ log { "logSharesheetTriggered()" }
+ }
+
+ override fun logSharesheetAppLoadComplete() {
+ log { "logSharesheetAppLoadComplete()" }
+ }
+
+ override fun logSharesheetDirectLoadComplete() {
+ log { "logSharesheetAppLoadComplete()" }
+ }
+
+ override fun logSharesheetDirectLoadTimeout() {
+ log { "logSharesheetDirectLoadTimeout()" }
+ }
+
+ override fun logSharesheetProfileChanged() {
+ log { "logSharesheetProfileChanged()" }
+ }
+
+ override fun logSharesheetExpansionChanged(isCollapsed: Boolean) {
+ log { "logSharesheetExpansionChanged(isCollapsed=$isCollapsed)" }
+ }
+
+ override fun logSharesheetAppShareRankingTimeout() {
+ log { "logSharesheetAppShareRankingTimeout()" }
+ }
+
+ override fun logSharesheetEmptyDirectShareRow() {
+ log { "logSharesheetEmptyDirectShareRow()" }
+ }
+
+ data class ActionSelected(val targetType: Int)
+ data class CustomActionSelected(val positionPicked: Int)
+ data class ActionShareWithPreview(val previewType: Int)
+ data class ChooserActivityShown(
+ val isWorkProfile: Boolean,
+ val targetMimeType: String?,
+ val systemCost: Long
+ )
+ data class ShareStarted(
+ val packageName: String?,
+ val mimeType: String?,
+ val appProvidedDirect: Int,
+ val appProvidedApp: Int,
+ val isWorkprofile: Boolean,
+ val previewType: Int,
+ val intent: String?,
+ val customActionCount: Int,
+ val modifyShareActionProvided: Boolean
+ )
+ data class ShareTargetSelected(
+ val targetType: Int,
+ val packageName: String?,
+ val positionPicked: Int,
+ val directTargetAlsoRanked: Int,
+ val numCallerProvided: Int,
+ val directTargetHashed: HashedStringCache.HashResult?,
+ val pinned: Boolean,
+ val successfullySelected: Boolean,
+ val selectionCost: Long
+ )
+}
diff --git a/java/tests/src/com/android/intentresolver/logging/FakeFrameworkStatsLogger.kt b/java/tests/src/com/android/intentresolver/logging/FakeFrameworkStatsLogger.kt
new file mode 100644
index 00000000..dcf8d23f
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/logging/FakeFrameworkStatsLogger.kt
@@ -0,0 +1,95 @@
+package com.android.intentresolver.logging
+/*
+ * 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.
+ */
+
+import com.android.internal.util.FrameworkStatsLog
+
+internal data class ShareSheetStarted(
+ val frameworkEventId: Int = FrameworkStatsLog.SHARESHEET_STARTED,
+ val appEventId: Int,
+ val packageName: String?,
+ val instanceId: Int,
+ val mimeType: String?,
+ val numAppProvidedDirectTargets: Int,
+ val numAppProvidedAppTargets: Int,
+ val isWorkProfile: Boolean,
+ val previewType: Int,
+ val intentType: Int,
+ val numCustomActions: Int,
+ val modifyShareActionProvided: Boolean
+)
+
+internal data class RankingSelected(
+ val frameworkEventId: Int = FrameworkStatsLog.RANKING_SELECTED,
+ val appEventId: Int,
+ val packageName: String?,
+ val instanceId: Int,
+ val positionPicked: Int,
+ val isPinned: Boolean
+)
+
+internal class FakeFrameworkStatsLogger : FrameworkStatsLogger {
+ var shareSheetStarted: ShareSheetStarted? = null
+ var rankingSelected: RankingSelected? = null
+ override 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
+ ) {
+ shareSheetStarted =
+ ShareSheetStarted(
+ frameworkEventId,
+ appEventId,
+ packageName,
+ instanceId,
+ mimeType,
+ numAppProvidedDirectTargets,
+ numAppProvidedAppTargets,
+ isWorkProfile,
+ previewType,
+ intentType,
+ numCustomActions,
+ modifyShareActionProvided
+ )
+ }
+ override fun write(
+ frameworkEventId: Int,
+ appEventId: Int,
+ packageName: String?,
+ instanceId: Int,
+ positionPicked: Int,
+ isPinned: Boolean
+ ) {
+ rankingSelected =
+ RankingSelected(
+ frameworkEventId,
+ appEventId,
+ packageName,
+ instanceId,
+ positionPicked,
+ isPinned
+ )
+ }
+}
diff --git a/java/tests/src/com/android/intentresolver/logging/TestEventLogModule.kt b/java/tests/src/com/android/intentresolver/logging/TestEventLogModule.kt
new file mode 100644
index 00000000..cd808af4
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/logging/TestEventLogModule.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.logging.InstanceId
+import com.android.internal.logging.InstanceIdSequence
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.android.components.ActivityComponent
+import dagger.hilt.android.scopes.ActivityScoped
+import dagger.hilt.testing.TestInstallIn
+
+/** Binds a [FakeEventLog] as [EventLog] in tests. */
+@Module
+@TestInstallIn(components = [ActivityComponent::class], replaces = [EventLogModule::class])
+interface TestEventLogModule {
+
+ @Binds @ActivityScoped fun fakeEventLog(impl: FakeEventLog): EventLog
+
+ companion object {
+ @Provides
+ fun instanceId(sequence: InstanceIdSequence): InstanceId = sequence.newInstanceId()
+ }
+}