Merge "Add logging for profile switching for sharesheet"

This commit is contained in:
Susi Kharraz-Post
2019-02-22 18:00:34 +00:00
committed by Android (Google) Code Review
6 changed files with 161 additions and 8 deletions

View File

@@ -381,6 +381,8 @@ public class ChooserActivity extends ResolverActivity {
final long systemCost = mChooserShownTime - intentReceivedTime;
getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN)
.setSubtype(isWorkProfile() ? MetricsEvent.MANAGED_PROFILE :
MetricsEvent.PARENT_PROFILE)
.addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType())
.addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost));
@@ -417,6 +419,16 @@ public class ChooserActivity extends ResolverActivity {
}
}
/**
* Check if the profile currently used is a work profile.
* @return true if it is work profile, false if it is parent profile (or no work profile is
* set up)
*/
protected boolean isWorkProfile() {
return ((UserManager) getSystemService(Context.USER_SERVICE))
.getUserInfo(UserHandle.myUserId()).isManagedProfile();
}
/**
* Override method to add content preview area, specific to the chooser activity.
*/

View File

@@ -31,6 +31,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.metrics.LogMaker;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -39,6 +40,8 @@ import android.util.Slog;
import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.Arrays;
import java.util.HashSet;
@@ -66,6 +69,8 @@ public class IntentForwarderActivity extends Activity {
private Injector mInjector;
private MetricsLogger mMetricsLogger;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -78,9 +83,17 @@ public class IntentForwarderActivity extends Activity {
if (className.equals(FORWARD_INTENT_TO_PARENT)) {
userMessageId = com.android.internal.R.string.forward_intent_to_owner;
targetUserId = getProfileParent();
getMetricsLogger().write(
new LogMaker(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE)
.setSubtype(MetricsEvent.PARENT_PROFILE));
} else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
userMessageId = com.android.internal.R.string.forward_intent_to_work;
targetUserId = getManagedProfile();
getMetricsLogger().write(
new LogMaker(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE)
.setSubtype(MetricsEvent.MANAGED_PROFILE));
} else {
Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
userMessageId = -1;
@@ -257,6 +270,13 @@ public class IntentForwarderActivity extends Activity {
intent.setComponent(null);
}
protected MetricsLogger getMetricsLogger() {
if (mMetricsLogger == null) {
mMetricsLogger = new MetricsLogger();
}
return mMetricsLogger;
}
@VisibleForTesting
protected Injector createInjector() {
return new InjectorImpl();

View File

@@ -57,7 +57,7 @@ import androidx.test.rule.ActivityTestRule;
import com.android.internal.R;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import org.junit.Before;
import org.junit.Rule;
@@ -524,15 +524,45 @@ public class ChooserActivityTest {
waitForIdle();
verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
is(MetricsProto.MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
assertThat(logMakerCaptor
.getAllValues().get(0)
.getTaggedData(MetricsProto.MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
.getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
is(notNullValue()));
assertThat(logMakerCaptor
.getAllValues().get(0)
.getTaggedData(MetricsProto.MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
.getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
is("TestType"));
assertThat(logMakerCaptor
.getAllValues().get(0)
.getSubtype(),
is(MetricsEvent.PARENT_PROFILE));
}
@Test
public void testOnCreateLoggingFromWorkProfile() {
Intent sendIntent = createSendTextIntent();
sendIntent.setType("TestType");
sOverrides.alternateProfileSetting = MetricsEvent.MANAGED_PROFILE;
MetricsLogger mockLogger = sOverrides.metricsLogger;
ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test"));
waitForIdle();
verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
assertThat(logMakerCaptor
.getAllValues().get(0)
.getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
is(notNullValue()));
assertThat(logMakerCaptor
.getAllValues().get(0)
.getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
is("TestType"));
assertThat(logMakerCaptor
.getAllValues().get(0)
.getSubtype(),
is(MetricsEvent.MANAGED_PROFILE));
}
@Test
@@ -547,7 +577,7 @@ public class ChooserActivityTest {
verify(mockLogger, Mockito.times(1)).write(logMakerCaptor.capture());
// First invocation is from onCreate
assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
is(MetricsProto.MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
}
@Test
@@ -569,7 +599,7 @@ public class ChooserActivityTest {
verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
// First invocation is from onCreate
assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
is(CONTENT_PREVIEW_TEXT));
}
@@ -599,11 +629,11 @@ public class ChooserActivityTest {
verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
// First invocation is from onCreate
assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
is(CONTENT_PREVIEW_IMAGE));
assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
assertThat(logMakerCaptor.getAllValues().get(2).getSubtype(),
is(CONTENT_PREVIEW_IMAGE));
}

View File

@@ -28,6 +28,7 @@ import android.net.Uri;
import android.util.Size;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.function.Function;
@@ -112,6 +113,14 @@ public class ChooserWrapperActivity extends ChooserActivity {
return super.queryResolver(resolver, uri);
}
@Override
protected boolean isWorkProfile() {
if (sOverrides.alternateProfileSetting != 0) {
return sOverrides.alternateProfileSetting == MetricsEvent.MANAGED_PROFILE;
}
return super.isWorkProfile();
}
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>
@@ -128,6 +137,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
public boolean resolverForceException;
public Bitmap previewThumbnail;
public MetricsLogger metricsLogger;
public int alternateProfileSetting;
public void reset() {
onSafelyStartCallback = null;
@@ -139,6 +149,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
resolverForceException = false;
resolverListController = mock(ResolverListController.class);
metricsLogger = mock(MetricsLogger.class);
alternateProfileSetting = 0;
}
}
}

View File

@@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -40,6 +41,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
@@ -51,6 +53,9 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -70,6 +75,11 @@ public class IntentForwarderActivityTest {
"android",
IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE
);
private static final ComponentName FORWARD_TO_PARENT_COMPONENT_NAME =
new ComponentName(
"android",
IntentForwarderActivity.FORWARD_INTENT_TO_PARENT
);
private static final String TYPE_PLAIN_TEXT = "text/plain";
private static UserInfo MANAGED_PROFILE_INFO = new UserInfo();
@@ -522,6 +532,60 @@ public class IntentForwarderActivityTest {
verify(sInjector).showToast(anyInt(), anyInt());
}
@Test
public void forwardToManagedProfile_LoggingTest() throws Exception {
sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
// Intent can be forwarded.
when(mIPm.canForwardTo(
any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
// Managed profile exists.
List<UserInfo> profiles = new ArrayList<>();
profiles.add(CURRENT_USER_INFO);
profiles.add(MANAGED_PROFILE_INFO);
when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
intent.setAction(Intent.ACTION_SEND);
intent.setType(TYPE_PLAIN_TEXT);
IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
verify(activity.getMetricsLogger()).write(logMakerCaptor.capture());
assertEquals(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE,
logMakerCaptor.getValue().getCategory());
assertEquals(MetricsEvent.MANAGED_PROFILE,
logMakerCaptor.getValue().getSubtype());
}
@Test
public void forwardToParent_LoggingTest() throws Exception {
sComponentName = FORWARD_TO_PARENT_COMPONENT_NAME;
// Intent can be forwarded.
when(mIPm.canForwardTo(
any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
// Managed profile exists.
List<UserInfo> profiles = new ArrayList<>();
profiles.add(CURRENT_USER_INFO);
profiles.add(MANAGED_PROFILE_INFO);
when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
intent.setAction(Intent.ACTION_SEND);
intent.setType(TYPE_PLAIN_TEXT);
IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
verify(activity.getMetricsLogger()).write(logMakerCaptor.capture());
assertEquals(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE,
logMakerCaptor.getValue().getCategory());
assertEquals(MetricsEvent.PARENT_PROFILE,
logMakerCaptor.getValue().getSubtype());
}
private void setupShouldSkipDisclosureTest() throws RemoteException {
sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
sActivityName = "MyTestActivity";
@@ -541,6 +605,7 @@ public class IntentForwarderActivityTest {
private Intent mStartActivityIntent;
private int mUserIdActivityLaunchedIn;
private MetricsLogger mMetricsLogger = mock(MetricsLogger.class);
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -559,6 +624,11 @@ public class IntentForwarderActivityTest {
mStartActivityIntent = intent;
mUserIdActivityLaunchedIn = userId;
}
@Override
protected MetricsLogger getMetricsLogger() {
return mMetricsLogger;
}
}
public class TestInjector implements IntentForwarderActivity.Injector {

View File

@@ -247,6 +247,12 @@ message MetricsEvent {
LOCATION_GONE = 6; // the view isn't laid out at all
}
// Subtypes for profile logging
enum ActiveUserProfile {
PARENT_PROFILE = 1;
MANAGED_PROFILE = 2;
}
// Known visual elements: views or controls.
enum View {
// Unknown view
@@ -7007,6 +7013,10 @@ message MetricsEvent {
// Different display can have different orientations, so need to log display id
FIELD_DISPLAY_ID = 1660;
// ACTION: Changing from work to parent profile or vice versa
// OS: Q
ACTION_SWITCH_SHARE_PROFILE = 1661;
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS