Loading core/java/android/app/usage/IUsageStatsManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -34,4 +34,6 @@ interface IUsageStatsManager { boolean isAppInactive(String packageName, int userId); void whitelistAppTemporarily(String packageName, long duration, int userId); void onCarrierPrivilegedAppsChanged(); void reportChooserSelection(String packageName, int userId, String contentType, in String[] annotations, String action); } core/java/android/app/usage/UsageEvents.java +40 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,12 @@ public final class UsageEvents implements Parcelable { */ public static final int SHORTCUT_INVOCATION = 8; /** * An event type denoting that a package was selected by the user for ChooserActivity. * @hide */ public static final int CHOOSER_ACTION = 9; /** * {@hide} */ Loading Loading @@ -118,6 +124,27 @@ public final class UsageEvents implements Parcelable { */ public String mShortcutId; /** * Action type passed to ChooserActivity * Only present for {@link #CHOOSER_ACTION} event types. * {@hide} */ public String mAction; /** * Content type passed to ChooserActivity. * Only present for {@link #CHOOSER_ACTION} event types. * {@hide} */ public String mContentType; /** * Content annotations passed to ChooserActivity. * Only present for {@link #CHOOSER_ACTION} event types. * {@hide} */ public String[] mContentAnnotations; /** * The package name of the source of this event. */ Loading Loading @@ -307,6 +334,11 @@ public final class UsageEvents implements Parcelable { case Event.SHORTCUT_INVOCATION: p.writeString(event.mShortcutId); break; case Event.CHOOSER_ACTION: p.writeString(event.mAction); p.writeString(event.mContentType); p.writeStringArray(event.mContentAnnotations); break; } } Loading @@ -333,6 +365,9 @@ public final class UsageEvents implements Parcelable { // Fill out the event-dependant fields. eventOut.mConfiguration = null; eventOut.mShortcutId = null; eventOut.mAction = null; eventOut.mContentType = null; eventOut.mContentAnnotations = null; switch (eventOut.mEventType) { case Event.CONFIGURATION_CHANGE: Loading @@ -342,6 +377,11 @@ public final class UsageEvents implements Parcelable { case Event.SHORTCUT_INVOCATION: eventOut.mShortcutId = p.readString(); break; case Event.CHOOSER_ACTION: eventOut.mAction = p.readString(); eventOut.mContentType = p.readString(); eventOut.mContentAnnotations = p.createStringArray(); break; } } Loading core/java/android/app/usage/UsageStats.java +62 −0 Original line number Diff line number Diff line Loading @@ -16,8 +16,10 @@ package android.app.usage; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; /** * Contains usage statistics for an app package for a specific Loading Loading @@ -61,6 +63,11 @@ public final class UsageStats implements Parcelable { */ public int mLastEvent; /** * {@hide} */ public ArrayMap<String, ArrayMap<String, Integer>> mChooserCounts; /** * {@hide} */ Loading @@ -75,6 +82,7 @@ public final class UsageStats implements Parcelable { mTotalTimeInForeground = stats.mTotalTimeInForeground; mLaunchCount = stats.mLaunchCount; mLastEvent = stats.mLastEvent; mChooserCounts = stats.mChooserCounts; } public String getPackageName() { Loading Loading @@ -142,6 +150,26 @@ public final class UsageStats implements Parcelable { mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp); mTotalTimeInForeground += right.mTotalTimeInForeground; mLaunchCount += right.mLaunchCount; if (mChooserCounts == null) { mChooserCounts = right.mChooserCounts; } else if (right.mChooserCounts != null) { final int chooserCountsSize = right.mChooserCounts.size(); for (int i = 0; i < chooserCountsSize; i++) { String action = right.mChooserCounts.keyAt(i); ArrayMap<String, Integer> counts = right.mChooserCounts.valueAt(i); if (!mChooserCounts.containsKey(action) || mChooserCounts.get(action) == null) { mChooserCounts.put(action, counts); continue; } final int annotationSize = counts.size(); for (int j = 0; j < annotationSize; j++) { String key = counts.keyAt(j); int rightValue = counts.valueAt(j); int leftValue = mChooserCounts.get(action).getOrDefault(key, 0); mChooserCounts.get(action).put(key, leftValue + rightValue); } } } } @Override Loading @@ -158,6 +186,21 @@ public final class UsageStats implements Parcelable { dest.writeLong(mTotalTimeInForeground); dest.writeInt(mLaunchCount); dest.writeInt(mLastEvent); Bundle allCounts = new Bundle(); if (mChooserCounts != null) { final int chooserCountSize = mChooserCounts.size(); for (int i = 0; i < chooserCountSize; i++) { String action = mChooserCounts.keyAt(i); ArrayMap<String, Integer> counts = mChooserCounts.valueAt(i); Bundle currentCounts = new Bundle(); final int annotationSize = counts.size(); for (int j = 0; j < annotationSize; j++) { currentCounts.putInt(counts.keyAt(j), counts.valueAt(j)); } allCounts.putBundle(action, currentCounts); } } dest.writeBundle(allCounts); } public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() { Loading @@ -171,6 +214,25 @@ public final class UsageStats implements Parcelable { stats.mTotalTimeInForeground = in.readLong(); stats.mLaunchCount = in.readInt(); stats.mLastEvent = in.readInt(); Bundle allCounts = in.readBundle(); if (allCounts != null) { stats.mChooserCounts = new ArrayMap<>(); for (String action : allCounts.keySet()) { if (!stats.mChooserCounts.containsKey(action)) { ArrayMap<String, Integer> newCounts = new ArrayMap<>(); stats.mChooserCounts.put(action, newCounts); } Bundle currentCounts = allCounts.getBundle(action); if (currentCounts != null) { for (String key : currentCounts.keySet()) { int value = currentCounts.getInt(key); if (value > 0) { stats.mChooserCounts.get(action).put(key, value); } } } } } return stats; } Loading core/java/android/app/usage/UsageStatsManager.java +19 −0 Original line number Diff line number Diff line Loading @@ -278,4 +278,23 @@ public final class UsageStatsManager { } catch (RemoteException re) { } } /** * Reports a Chooser action to the UsageStatsManager. * * @param packageName The package name of the app that is selected. * @param userId The user id of who makes the selection. * @param contentType The type of the content, e.g., Image, Video, App. * @param annotations The annotations of the content, e.g., Game, Selfie. * @param action The action type of Intent that invokes ChooserActivity. * {@link UsageEvents} * @hide */ public void reportChooserSelection(String packageName, int userId, String contentType, String[] annotations, String action) { try { mService.reportChooserSelection(packageName, userId, contentType, annotations, action); } catch (RemoteException re) { } } } core/java/com/android/internal/app/ChooserActivity.java +32 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.internal.app; import android.animation.ObjectAnimator; import android.annotation.NonNull; import android.app.Activity; import android.app.usage.UsageStatsManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -403,6 +404,7 @@ public class ChooserActivity extends ResolverActivity { } } } updateChooserCounts(target, mContentType); return super.onTargetSelected(target, alwaysCheck); } Loading Loading @@ -547,21 +549,47 @@ public class ChooserActivity extends ResolverActivity { // Do nothing. We'll send the voice stuff ourselves. } void updateChooserCounts(TargetInfo info, String annotation) { if (info != null) { UsageStatsManager usageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); if (usageStatsManager == null) { if (DEBUG) { Log.d(TAG, "Can not start UsageStatsManager"); } return; } final ResolveInfo ri = info.getResolveInfo(); if (ri != null && ri.activityInfo != null) { usageStatsManager.reportChooserSelection(ri.activityInfo.packageName, getUserId(), annotation, null, info.getResolvedIntent().getAction()); if (DEBUG) { Log.d(TAG, "ResolveInfo Package is" + ri.activityInfo.packageName); } } else if(DEBUG) { Log.d(TAG, "Can not log Chooser Counts of null ResovleInfo"); } } } void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) { if (mRefinementResultReceiver != null) { mRefinementResultReceiver.destroy(); mRefinementResultReceiver = null; } if (selectedTarget == null) { Log.e(TAG, "Refinement result intent did not match any known targets; canceling"); } else if (!checkTargetSourceIntent(selectedTarget, matchingIntent)) { Log.e(TAG, "onRefinementResult: Selected target " + selectedTarget + " cannot match refined source intent " + matchingIntent); } else if (super.onTargetSelected(selectedTarget.cloneFilledIn(matchingIntent, 0), false)) { } else { TargetInfo clonedTarget = selectedTarget.cloneFilledIn(matchingIntent, 0); if (super.onTargetSelected(clonedTarget, false)) { updateChooserCounts(clonedTarget, mContentType); finish(); return; } } onRefinementCanceled(); } Loading Loading
core/java/android/app/usage/IUsageStatsManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -34,4 +34,6 @@ interface IUsageStatsManager { boolean isAppInactive(String packageName, int userId); void whitelistAppTemporarily(String packageName, long duration, int userId); void onCarrierPrivilegedAppsChanged(); void reportChooserSelection(String packageName, int userId, String contentType, in String[] annotations, String action); }
core/java/android/app/usage/UsageEvents.java +40 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,12 @@ public final class UsageEvents implements Parcelable { */ public static final int SHORTCUT_INVOCATION = 8; /** * An event type denoting that a package was selected by the user for ChooserActivity. * @hide */ public static final int CHOOSER_ACTION = 9; /** * {@hide} */ Loading Loading @@ -118,6 +124,27 @@ public final class UsageEvents implements Parcelable { */ public String mShortcutId; /** * Action type passed to ChooserActivity * Only present for {@link #CHOOSER_ACTION} event types. * {@hide} */ public String mAction; /** * Content type passed to ChooserActivity. * Only present for {@link #CHOOSER_ACTION} event types. * {@hide} */ public String mContentType; /** * Content annotations passed to ChooserActivity. * Only present for {@link #CHOOSER_ACTION} event types. * {@hide} */ public String[] mContentAnnotations; /** * The package name of the source of this event. */ Loading Loading @@ -307,6 +334,11 @@ public final class UsageEvents implements Parcelable { case Event.SHORTCUT_INVOCATION: p.writeString(event.mShortcutId); break; case Event.CHOOSER_ACTION: p.writeString(event.mAction); p.writeString(event.mContentType); p.writeStringArray(event.mContentAnnotations); break; } } Loading @@ -333,6 +365,9 @@ public final class UsageEvents implements Parcelable { // Fill out the event-dependant fields. eventOut.mConfiguration = null; eventOut.mShortcutId = null; eventOut.mAction = null; eventOut.mContentType = null; eventOut.mContentAnnotations = null; switch (eventOut.mEventType) { case Event.CONFIGURATION_CHANGE: Loading @@ -342,6 +377,11 @@ public final class UsageEvents implements Parcelable { case Event.SHORTCUT_INVOCATION: eventOut.mShortcutId = p.readString(); break; case Event.CHOOSER_ACTION: eventOut.mAction = p.readString(); eventOut.mContentType = p.readString(); eventOut.mContentAnnotations = p.createStringArray(); break; } } Loading
core/java/android/app/usage/UsageStats.java +62 −0 Original line number Diff line number Diff line Loading @@ -16,8 +16,10 @@ package android.app.usage; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; /** * Contains usage statistics for an app package for a specific Loading Loading @@ -61,6 +63,11 @@ public final class UsageStats implements Parcelable { */ public int mLastEvent; /** * {@hide} */ public ArrayMap<String, ArrayMap<String, Integer>> mChooserCounts; /** * {@hide} */ Loading @@ -75,6 +82,7 @@ public final class UsageStats implements Parcelable { mTotalTimeInForeground = stats.mTotalTimeInForeground; mLaunchCount = stats.mLaunchCount; mLastEvent = stats.mLastEvent; mChooserCounts = stats.mChooserCounts; } public String getPackageName() { Loading Loading @@ -142,6 +150,26 @@ public final class UsageStats implements Parcelable { mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp); mTotalTimeInForeground += right.mTotalTimeInForeground; mLaunchCount += right.mLaunchCount; if (mChooserCounts == null) { mChooserCounts = right.mChooserCounts; } else if (right.mChooserCounts != null) { final int chooserCountsSize = right.mChooserCounts.size(); for (int i = 0; i < chooserCountsSize; i++) { String action = right.mChooserCounts.keyAt(i); ArrayMap<String, Integer> counts = right.mChooserCounts.valueAt(i); if (!mChooserCounts.containsKey(action) || mChooserCounts.get(action) == null) { mChooserCounts.put(action, counts); continue; } final int annotationSize = counts.size(); for (int j = 0; j < annotationSize; j++) { String key = counts.keyAt(j); int rightValue = counts.valueAt(j); int leftValue = mChooserCounts.get(action).getOrDefault(key, 0); mChooserCounts.get(action).put(key, leftValue + rightValue); } } } } @Override Loading @@ -158,6 +186,21 @@ public final class UsageStats implements Parcelable { dest.writeLong(mTotalTimeInForeground); dest.writeInt(mLaunchCount); dest.writeInt(mLastEvent); Bundle allCounts = new Bundle(); if (mChooserCounts != null) { final int chooserCountSize = mChooserCounts.size(); for (int i = 0; i < chooserCountSize; i++) { String action = mChooserCounts.keyAt(i); ArrayMap<String, Integer> counts = mChooserCounts.valueAt(i); Bundle currentCounts = new Bundle(); final int annotationSize = counts.size(); for (int j = 0; j < annotationSize; j++) { currentCounts.putInt(counts.keyAt(j), counts.valueAt(j)); } allCounts.putBundle(action, currentCounts); } } dest.writeBundle(allCounts); } public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() { Loading @@ -171,6 +214,25 @@ public final class UsageStats implements Parcelable { stats.mTotalTimeInForeground = in.readLong(); stats.mLaunchCount = in.readInt(); stats.mLastEvent = in.readInt(); Bundle allCounts = in.readBundle(); if (allCounts != null) { stats.mChooserCounts = new ArrayMap<>(); for (String action : allCounts.keySet()) { if (!stats.mChooserCounts.containsKey(action)) { ArrayMap<String, Integer> newCounts = new ArrayMap<>(); stats.mChooserCounts.put(action, newCounts); } Bundle currentCounts = allCounts.getBundle(action); if (currentCounts != null) { for (String key : currentCounts.keySet()) { int value = currentCounts.getInt(key); if (value > 0) { stats.mChooserCounts.get(action).put(key, value); } } } } } return stats; } Loading
core/java/android/app/usage/UsageStatsManager.java +19 −0 Original line number Diff line number Diff line Loading @@ -278,4 +278,23 @@ public final class UsageStatsManager { } catch (RemoteException re) { } } /** * Reports a Chooser action to the UsageStatsManager. * * @param packageName The package name of the app that is selected. * @param userId The user id of who makes the selection. * @param contentType The type of the content, e.g., Image, Video, App. * @param annotations The annotations of the content, e.g., Game, Selfie. * @param action The action type of Intent that invokes ChooserActivity. * {@link UsageEvents} * @hide */ public void reportChooserSelection(String packageName, int userId, String contentType, String[] annotations, String action) { try { mService.reportChooserSelection(packageName, userId, contentType, annotations, action); } catch (RemoteException re) { } } }
core/java/com/android/internal/app/ChooserActivity.java +32 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.internal.app; import android.animation.ObjectAnimator; import android.annotation.NonNull; import android.app.Activity; import android.app.usage.UsageStatsManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -403,6 +404,7 @@ public class ChooserActivity extends ResolverActivity { } } } updateChooserCounts(target, mContentType); return super.onTargetSelected(target, alwaysCheck); } Loading Loading @@ -547,21 +549,47 @@ public class ChooserActivity extends ResolverActivity { // Do nothing. We'll send the voice stuff ourselves. } void updateChooserCounts(TargetInfo info, String annotation) { if (info != null) { UsageStatsManager usageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); if (usageStatsManager == null) { if (DEBUG) { Log.d(TAG, "Can not start UsageStatsManager"); } return; } final ResolveInfo ri = info.getResolveInfo(); if (ri != null && ri.activityInfo != null) { usageStatsManager.reportChooserSelection(ri.activityInfo.packageName, getUserId(), annotation, null, info.getResolvedIntent().getAction()); if (DEBUG) { Log.d(TAG, "ResolveInfo Package is" + ri.activityInfo.packageName); } } else if(DEBUG) { Log.d(TAG, "Can not log Chooser Counts of null ResovleInfo"); } } } void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) { if (mRefinementResultReceiver != null) { mRefinementResultReceiver.destroy(); mRefinementResultReceiver = null; } if (selectedTarget == null) { Log.e(TAG, "Refinement result intent did not match any known targets; canceling"); } else if (!checkTargetSourceIntent(selectedTarget, matchingIntent)) { Log.e(TAG, "onRefinementResult: Selected target " + selectedTarget + " cannot match refined source intent " + matchingIntent); } else if (super.onTargetSelected(selectedTarget.cloneFilledIn(matchingIntent, 0), false)) { } else { TargetInfo clonedTarget = selectedTarget.cloneFilledIn(matchingIntent, 0); if (super.onTargetSelected(clonedTarget, false)) { updateChooserCounts(clonedTarget, mContentType); finish(); return; } } onRefinementCanceled(); } Loading