Collects metrics for the new Sharing Shortcuts api

Bug: 122904954
Test: atest com.android.server.pm.ShortcutManagerTest1 \
            com.android.server.pm.ShortcutManagerTest2 \
            com.android.server.pm.ShortcutManagerTest3 \
            com.android.server.pm.ShortcutManagerTest4 \
            com.android.server.pm.ShortcutManagerTest5 \
            com.android.server.pm.ShortcutManagerTest6 \
            com.android.server.pm.ShortcutManagerTest7 \
            com.android.server.pm.ShortcutManagerTest8 \
            com.android.server.pm.ShortcutManagerTest9 \
            com.android.server.pm.ShortcutManagerTest10
Change-Id: Ifafcaa789814618846d41431d6190e4d79e871e5
This commit is contained in:
Mehdi Alizadeh
2019-04-25 14:52:02 -07:00
parent cc1159a166
commit 97fb3ed8bc
7 changed files with 175 additions and 4 deletions

View File

@@ -202,6 +202,9 @@ public class ChooserActivity extends ResolverActivity {
private long mChooserShownTime;
protected boolean mIsSuccessfullySelected;
private long mQueriedTargetServicesTimeMs;
private long mQueriedSharingShortcutsTimeMs;
private ChooserListAdapter mChooserListAdapter;
private ChooserRowAdapter mChooserRowAdapter;
private int mChooserRowServiceSpacing;
@@ -273,6 +276,8 @@ public class ChooserActivity extends ResolverActivity {
sri.connection.destroy();
mServiceConnections.remove(sri.connection);
if (mServiceConnections.isEmpty()) {
logDirectShareTargetReceived(
MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_CHOOSER_SERVICE);
sendVoiceChoicesIfNeeded();
}
break;
@@ -283,6 +288,8 @@ public class ChooserActivity extends ResolverActivity {
}
unbindRemainingServices();
logDirectShareTargetReceived(
MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_CHOOSER_SERVICE);
sendVoiceChoicesIfNeeded();
mChooserListAdapter.completeServiceTargetLoading();
break;
@@ -305,6 +312,8 @@ public class ChooserActivity extends ResolverActivity {
break;
case SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED:
logDirectShareTargetReceived(
MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_SHORTCUT_MANAGER);
sendVoiceChoicesIfNeeded();
break;
@@ -1155,6 +1164,8 @@ public class ChooserActivity extends ResolverActivity {
}
void queryTargetServices(ChooserListAdapter adapter) {
mQueriedTargetServicesTimeMs = System.currentTimeMillis();
final PackageManager pm = getPackageManager();
ShortcutManager sm = (ShortcutManager) getSystemService(ShortcutManager.class);
int targetsToQuery = 0;
@@ -1281,6 +1292,7 @@ public class ChooserActivity extends ResolverActivity {
private void queryDirectShareTargets(
ChooserListAdapter adapter, boolean skipAppPredictionService) {
mQueriedSharingShortcutsTimeMs = System.currentTimeMillis();
if (!skipAppPredictionService) {
AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled();
if (appPredictor != null) {
@@ -1391,6 +1403,14 @@ public class ChooserActivity extends ResolverActivity {
// Do nothing. We'll send the voice stuff ourselves.
}
private void logDirectShareTargetReceived(int logCategory) {
final long queryTime =
logCategory == MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_SHORTCUT_MANAGER
? mQueriedSharingShortcutsTimeMs : mQueriedTargetServicesTimeMs;
final int apiLatency = (int) (System.currentTimeMillis() - queryTime);
getMetricsLogger().write(new LogMaker(logCategory).setSubtype(apiLatency));
}
void updateModelAndChooserCounts(TargetInfo info) {
if (info != null) {
sendClickToAppPredictor(info);

View File

@@ -263,6 +263,14 @@ message MetricsEvent {
PREVIOUSLY_VISIBLE = 2;
}
// Types for ACTION_SHORTCUTS_CHANGED
enum ShortcutsChangesInfo {
SHORTCUTS_CHANGED_UNKNOWN = 0;
SHORTCUTS_CHANGED_USER_ID = 1;
SHORTCUTS_CHANGED_PACKAGE_COUNT = 2;
SHORTCUTS_CHANGED_SHORTCUT_COUNT = 3;
}
// Explanations for notification importance, derived from
// NotificationRecord.mImportanceExplanation.
enum NotificationImportanceExplanation {
@@ -7222,6 +7230,19 @@ message MetricsEvent {
// OS: Q
ASSISTANT = 1716;
// ACTION: Published shortcuts in ShortcutManager changed
// TYPE: All the SHORTCUTS_CHANGED_* values in ShortcutsChangesInfo
// OS: Q
ACTION_SHORTCUTS_CHANGED = 1717;
// ACTION: Direct share targets loaded via ShortcutManager
// OS: Q
ACTION_DIRECT_SHARE_TARGETS_LOADED_SHORTCUT_MANAGER = 1718;
// ACTION: Direct share targets loaded via ChooserService
// OS: Q
ACTION_DIRECT_SHARE_TARGETS_LOADED_CHOOSER_SERVICE = 1719;
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS

View File

@@ -680,20 +680,23 @@ class ShortcutPackage extends ShortcutPackageItem {
final List<ShortcutManager.ShareShortcutInfo> result = new ArrayList<>();
for (int i = 0; i < shortcuts.size(); i++) {
final ShortcutInfo si = shortcuts.get(i);
final Set<String> categories = shortcuts.get(i).getCategories();
if (categories == null || categories.isEmpty()) {
continue;
}
for (int j = 0; j < matchedTargets.size(); j++) {
// Shortcut must have all of share target categories
boolean hasAllCategories = true;
final ShareTargetInfo target = matchedTargets.get(j);
for (int q = 0; q < target.mCategories.length; q++) {
if (!si.getCategories().contains(target.mCategories[q])) {
if (!categories.contains(target.mCategories[q])) {
hasAllCategories = false;
break;
}
}
if (hasAllCategories) {
result.add(new ShortcutManager.ShareShortcutInfo(si, new ComponentName(
getPackageName(), target.mTargetClass)));
result.add(new ShortcutManager.ShareShortcutInfo(shortcuts.get(i),
new ComponentName(getPackageName(), target.mTargetClass)));
break;
}
}
@@ -705,6 +708,45 @@ class ShortcutPackage extends ShortcutPackageItem {
return !mShareTargets.isEmpty();
}
/**
* Returns the number of shortcuts that can be used as a share target in the ShareSheet. Such
* shortcuts must have a matching category with at least one of the defined ShareTargets from
* the app's Xml resource.
*/
int getSharingShortcutCount() {
if (mShortcuts.isEmpty() || mShareTargets.isEmpty()) {
return 0;
}
// Get the list of all dynamic shortcuts in this package
final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
findAll(shortcuts, ShortcutInfo::isDynamicVisible, ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
int sharingShortcutCount = 0;
for (int i = 0; i < shortcuts.size(); i++) {
final Set<String> categories = shortcuts.get(i).getCategories();
if (categories == null || categories.isEmpty()) {
continue;
}
for (int j = 0; j < mShareTargets.size(); j++) {
// A SharingShortcut must have all of share target categories
boolean hasAllCategories = true;
final ShareTargetInfo target = mShareTargets.get(j);
for (int q = 0; q < target.mCategories.length; q++) {
if (!categories.contains(target.mCategories[q])) {
hasAllCategories = false;
break;
}
}
if (hasAllCategories) {
sharingShortcutCount++;
break;
}
}
}
return sharingShortcutCount;
}
/**
* Return the filenames (excluding path names) of icon bitmap files from this package.
*/

View File

@@ -95,6 +95,7 @@ import android.view.IWindowManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
@@ -413,6 +414,9 @@ public class ShortcutService extends IShortcutService.Stub {
@GuardedBy("mLock")
private Exception mLastWtfStacktrace;
@GuardedBy("mLock")
private final MetricsLogger mMetricsLogger = new MetricsLogger();
static class InvalidFileFormatException extends Exception {
public InvalidFileFormatException(String message, Throwable cause) {
super(message, cause);
@@ -981,6 +985,8 @@ public class ShortcutService extends IShortcutService.Stub {
Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
file.failWrite(os);
}
getUserShortcutsLocked(userId).logSharingShortcutStats(mMetricsLogger);
}
@GuardedBy("mLock")

View File

@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.pm.ShortcutManager;
import android.metrics.LogMaker;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.ArrayMap;
@@ -27,6 +28,8 @@ import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.Preconditions;
import com.android.server.pm.ShortcutService.DumpFilter;
import com.android.server.pm.ShortcutService.InvalidFileFormatException;
@@ -647,4 +650,23 @@ class ShortcutUser {
return result;
}
void logSharingShortcutStats(MetricsLogger logger) {
int packageWithShareTargetsCount = 0;
int totalSharingShortcutCount = 0;
for (int i = 0; i < mPackages.size(); i++) {
if (mPackages.valueAt(i).hasShareTargets()) {
packageWithShareTargetsCount++;
totalSharingShortcutCount += mPackages.valueAt(i).getSharingShortcutCount();
}
}
final LogMaker logMaker = new LogMaker(MetricsEvent.ACTION_SHORTCUTS_CHANGED);
logger.write(logMaker.setType(MetricsEvent.SHORTCUTS_CHANGED_USER_ID)
.setSubtype(mUserId));
logger.write(logMaker.setType(MetricsEvent.SHORTCUTS_CHANGED_PACKAGE_COUNT)
.setSubtype(packageWithShareTargetsCount));
logger.write(logMaker.setType(MetricsEvent.SHORTCUTS_CHANGED_SHORTCUT_COUNT)
.setSubtype(totalSharingShortcutCount));
}
}

View File

@@ -1583,6 +1583,22 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
return s;
}
/**
* Make a shortcut with an ID and Category.
*/
protected ShortcutInfo makeShortcutWithCategory(String id, Set<String> categories) {
final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id)
.setActivity(new ComponentName(mClientContext.getPackageName(), "main"))
.setShortLabel("title-" + id)
.setIntent(makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class))
.setCategories(categories);
final ShortcutInfo s = b.build();
s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
return s;
}
/**
* Make an intent.
*/
@@ -1817,6 +1833,17 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
return p == null ? null : p.getAllShareTargetsForTest();
}
/**
* @return the number of shortcuts stored internally for the caller that can be used as a share
* target in the ShareSheet. Such shortcuts have a matching category with at least one of the
* defined ShareTargets from the app's Xml resource.
*/
protected int getCallerSharingShortcutCount() {
final ShortcutPackage p = mService.getPackageShortcutForTest(
getCallingPackage(), getCallingUserId());
return p == null ? 0 : p.getSharingShortcutCount();
}
/**
* @return all shortcuts owned by caller that are actually visible via ShortcutManager.
* See also {@link #getCallerShortcuts}.

View File

@@ -17,6 +17,7 @@ package com.android.server.pm;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
import android.content.ComponentName;
import android.content.pm.ShortcutInfo;
@@ -25,6 +26,8 @@ import android.test.suitebuilder.annotation.SmallTest;
import com.android.frameworks.servicestests.R;
import com.android.server.pm.ShortcutService.ConfigConstants;
import java.util.Set;
/**
* Tests related to shortcut rank auto-adjustment.
*/
@@ -50,6 +53,10 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest {
return makeShortcutWithActivityAndRank(id, activity, ShortcutInfo.RANK_NOT_SET);
}
private ShortcutInfo shortcut(String id, Set<String> categories) {
return makeShortcutWithCategory(id, categories);
}
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -502,4 +509,30 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest {
runTestWithManifestShortcuts(() -> testDisableShortcuts_noManifestShortcuts());
}
public void testGetSharingShortcutCount() {
addManifestShortcutResource(
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_share_targets);
updatePackageVersion(CALLING_PACKAGE_1, 1);
mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// There are two valid <share-target> definitions in the test manifest with two different
// categories: {"com.test.category.CATEGORY1", "com.test.category.CATEGORY2"} and
// {"com.test.category.CATEGORY5", "com.test.category.CATEGORY6"}.
//
// Note that a shortcut is a match, only if it has ALL of the categories of at least one
// of the share-target definitions from the manifest.
mManager.addDynamicShortcuts(list(
shortcut("s1", set("com.test.category.CATEGORY1", "com.test.category.CATEGORY2")),
shortcut("s2", set("com.test.category.CATEGORY5")),
shortcut("s3", set("com.test.category.CATEGORY5", "com.test.category.CATEGORY6")),
shortcut("s4", set("com.test.category.CATEGORY1", "com.test.category.CATEGORY2",
"com.test.category.CATEGORY5", "com.test.category.CATEGORY6")),
shortcut("s5", A1)
));
assertEquals(3, getCallerSharingShortcutCount());
}
}