Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ec89411 authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Track notification clicked events in UsageStats

Expose some of the new events as SystemApi.

Make some of the timeouts configurable in AppStandbyController.

Make NOTIFICATION_SEEN event upgrade app to WORKING_SET for
12 hours. This is not perfect though and will require further
tweaking as it may result in the app becoming elevated higher
for much longer than necessary.

Change-Id: I62401cfabddf51b6f80b9bba8a358285b8cf9a51
Fixes: 72741441
Fixes: 72067231
Fixes: 72537465
Fixes: 72536347
Test: atest CtsUsageStatsTestCases:UsageStatsTests
parent af5a66bf
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -30,8 +30,8 @@ package android {
    field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
    field public static final java.lang.String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
    field public static final java.lang.String BIND_TELEPHONY_DATA_SERVICE = "android.permission.BIND_TELEPHONY_DATA_SERVICE";
    field public static final java.lang.String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE";
    field public static final java.lang.String BIND_TELEPHONY_NETWORK_SERVICE = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE";
    field public static final java.lang.String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE";
    field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
    field public static final java.lang.String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
    field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
@@ -687,6 +687,12 @@ package android.app.usage {
    field public static final java.lang.String SERVICE_INTERFACE = "android.app.usage.CacheQuotaService";
  }

  public static final class UsageEvents.Event {
    method public int getStandbyBucket();
    field public static final int NOTIFICATION_SEEN = 10; // 0xa
    field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb
  }

  public final class UsageStatsManager {
    method public int getAppStandbyBucket(java.lang.String);
    method public java.util.Map<java.lang.String, java.lang.Integer> getAppStandbyBuckets();
+14 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package android.app.usage;

import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.content.res.Configuration;
import android.os.Parcel;
import android.os.Parcelable;
@@ -104,12 +105,14 @@ public final class UsageEvents implements Parcelable {
         * An event type denoting that a notification was viewed by the user.
         * @hide
         */
        @SystemApi
        public static final int NOTIFICATION_SEEN = 10;

        /**
         * An event type denoting a change in App Standby Bucket.
         * @hide
         */
        @SystemApi
        public static final int STANDBY_BUCKET_CHANGED = 11;

        /** @hide */
@@ -257,6 +260,17 @@ public final class UsageEvents implements Parcelable {
            return mShortcutId;
        }

        /**
         * Returns the standby bucket of the app, if the event is of type
         * {@link #STANDBY_BUCKET_CHANGED}, otherwise returns 0.
         * @return the standby bucket associated with the event.
         * @hide
         */
        @SystemApi
        public int getStandbyBucket() {
            return mBucket;
        }

        /** @hide */
        public Event getObfuscatedIfInstantApp() {
            if ((mFlags & FLAG_IS_PACKAGE_INSTANT_APP) == 0) {
+18 −1
Original line number Diff line number Diff line
@@ -680,6 +680,7 @@ public class NotificationManagerService extends SystemService {
                        sbn.getId(), Notification.FLAG_AUTO_CANCEL,
                        Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
                        REASON_CLICK, null);
                reportUserInteraction(r);
            }
        }

@@ -700,7 +701,7 @@ public class NotificationManagerService extends SystemService {
                        .setSubtype(actionIndex));
                EventLogTags.writeNotificationActionClicked(key, actionIndex,
                        r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
                // TODO: Log action click via UsageStats.
                reportUserInteraction(r);
            }
        }

@@ -821,6 +822,7 @@ public class NotificationManagerService extends SystemService {
                NotificationRecord r = mNotificationsByKey.get(key);
                if (r != null) {
                    r.recordDirectReplied();
                    reportUserInteraction(r);
                }
            }
        }
@@ -1746,6 +1748,10 @@ public class NotificationManagerService extends SystemService {
        return INotificationManager.Stub.asInterface(mService);
    }

    /**
     * Report to usage stats that the notification was seen.
     * @param r notification record
     */
    protected void reportSeen(NotificationRecord r) {
        final int userId = r.sbn.getUserId();
        mAppUsageStats.reportEvent(r.sbn.getPackageName(),
@@ -1754,6 +1760,17 @@ public class NotificationManagerService extends SystemService {
                UsageEvents.Event.NOTIFICATION_SEEN);
    }

    /**
     * Report to usage stats that the notification was clicked.
     * @param r notification record
     */
    protected void reportUserInteraction(NotificationRecord r) {
        final int userId = r.sbn.getUserId();
        mAppUsageStats.reportEvent(r.sbn.getPackageName(),
                userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId,
                UsageEvents.Event.USER_INTERACTION);
    }

    @VisibleForTesting
    NotificationManagerInternal getInternalService() {
        return mInternalService;
+5 −0
Original line number Diff line number Diff line
@@ -179,6 +179,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        protected void reportSeen(NotificationRecord r) {
            return;
        }

        @Override
        protected void reportUserInteraction(NotificationRecord r) {
            return;
        }
    }

    @Before
+26 −6
Original line number Diff line number Diff line
@@ -177,6 +177,12 @@ public class AppStandbyController {
    long mAppIdleParoleDurationMillis;
    long[] mAppStandbyScreenThresholds = SCREEN_TIME_THRESHOLDS;
    long[] mAppStandbyElapsedThresholds = ELAPSED_TIME_THRESHOLDS;
    /** Minimum time a strong usage event should keep the bucket elevated. */
    long mStrongUsageTimeoutMillis;
    /** Minimum time a notification seen event should keep the bucket elevated. */
    long mNotificationSeenTimeoutMillis;
    /** Minimum time a system update event should keep the buckets elevated. */
    long mSystemUpdateUsageTimeoutMillis;

    volatile boolean mAppIdleEnabled;
    boolean mAppIdleTempParoled;
@@ -330,7 +336,7 @@ public class AppStandbyController {
                    synchronized (mAppIdleLock) {
                        AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
                                STANDBY_BUCKET_ACTIVE, elapsedRealtime,
                                elapsedRealtime + 2 * ONE_HOUR);
                                elapsedRealtime + mStrongUsageTimeoutMillis);
                        maybeInformListeners(packageName, userId, elapsedRealtime,
                                appUsage.currentBucket, false);
                    }
@@ -627,11 +633,11 @@ public class AppStandbyController {
                if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN) {
                    mAppIdleHistory.reportUsage(appHistory, event.mPackage,
                            STANDBY_BUCKET_WORKING_SET,
                            elapsedRealtime, elapsedRealtime + 2 * ONE_HOUR);
                            elapsedRealtime, elapsedRealtime + mNotificationSeenTimeoutMillis);
                } else {
                    mAppIdleHistory.reportUsage(event.mPackage, userId,
                            STANDBY_BUCKET_ACTIVE,
                            elapsedRealtime, elapsedRealtime + 2 * ONE_HOUR);
                            elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
                }

                final boolean userStartedInteracting =
@@ -1113,10 +1119,10 @@ public class AppStandbyController {
                final PackageInfo pi = packages.get(i);
                String packageName = pi.packageName;
                if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
                    // Mark app as used for 4 hours. After that it can timeout to whatever the
                    // Mark app as used for 2 hours. After that it can timeout to whatever the
                    // past usage pattern was.
                    mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE, 0,
                            elapsedRealtime + 4 * ONE_HOUR);
                            elapsedRealtime + mSystemUpdateUsageTimeoutMillis);
                }
            }
        }
@@ -1395,6 +1401,12 @@ public class AppStandbyController {
        private static final String KEY_PAROLE_DURATION = "parole_duration";
        private static final String KEY_SCREEN_TIME_THRESHOLDS = "screen_thresholds";
        private static final String KEY_ELAPSED_TIME_THRESHOLDS = "elapsed_thresholds";
        private static final String KEY_STRONG_USAGE_HOLD_DURATION = "strong_usage_duration";
        private static final String KEY_NOTIFICATION_SEEN_HOLD_DURATION =
                "notification_seen_duration";
        private static final String KEY_SYSTEM_UPDATE_HOLD_DURATION =
                "system_update_usage_duration";


        private final KeyValueListParser mParser = new KeyValueListParser(',');

@@ -1455,7 +1467,15 @@ public class AppStandbyController {
                        ELAPSED_TIME_THRESHOLDS);
                mCheckIdleIntervalMillis = Math.min(mAppStandbyElapsedThresholds[1] / 4,
                        COMPRESS_TIME ? ONE_MINUTE : 4 * 60 * ONE_MINUTE); // 4 hours

                mStrongUsageTimeoutMillis = mParser.getDurationMillis
                        (KEY_STRONG_USAGE_HOLD_DURATION,
                                COMPRESS_TIME ? ONE_MINUTE : 1 * ONE_HOUR);
                mNotificationSeenTimeoutMillis = mParser.getDurationMillis
                        (KEY_NOTIFICATION_SEEN_HOLD_DURATION,
                                COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR);
                mSystemUpdateUsageTimeoutMillis = mParser.getDurationMillis
                        (KEY_SYSTEM_UPDATE_HOLD_DURATION,
                                COMPRESS_TIME ? 2 * ONE_MINUTE : 2 * ONE_HOUR);
            }
        }