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

Commit c0fe0626 authored by Suprabh Shukla's avatar Suprabh Shukla Committed by Android (Google) Code Review
Browse files

Merge "An api to query usage events for the caller"

parents b93a014c 217ccda8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -7445,6 +7445,7 @@ package android.app.usage {
    method public java.util.Map<java.lang.String, android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long);
    method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long);
    method public android.app.usage.UsageEvents queryEvents(long, long);
    method public android.app.usage.UsageEvents queryEventsForSelf(long, long);
    method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long);
    field public static final int INTERVAL_BEST = 4; // 0x4
    field public static final int INTERVAL_DAILY = 0; // 0x0
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ interface IUsageStatsManager {
    ParceledListSlice queryConfigurationStats(int bucketType, long beginTime, long endTime,
            String callingPackage);
    UsageEvents queryEvents(long beginTime, long endTime, String callingPackage);
    UsageEvents queryEventsForPackage(long beginTime, long endTime, String callingPackage);
    void setAppInactive(String packageName, boolean inactive, int userId);
    boolean isAppInactive(String packageName, int userId);
    void whitelistAppTemporarily(String packageName, long duration, int userId);
+34 −4
Original line number Diff line number Diff line
@@ -52,10 +52,13 @@ import java.util.Map;
 * </pre>
 * A request for data in the middle of a time interval will include that interval.
 * <p/>
 * <b>NOTE:</b> This API requires the permission android.permission.PACKAGE_USAGE_STATS.
 * However, declaring the permission implies intention to use the API and the user of the device
 * still needs to grant permission through the Settings application.
 * See {@link android.provider.Settings#ACTION_USAGE_ACCESS_SETTINGS}
 * <b>NOTE:</b> Most methods on this API require the permission
 * android.permission.PACKAGE_USAGE_STATS. However, declaring the permission implies intention to
 * use the API and the user of the device still needs to grant permission through the Settings
 * application.
 * See {@link android.provider.Settings#ACTION_USAGE_ACCESS_SETTINGS}.
 * Methods which only return the information for the calling package do not require this permission.
 * E.g. {@link #getAppStandbyBucket()} and {@link #queryEventsForSelf(long, long)}.
 */
@SystemService(Context.USAGE_STATS_SERVICE)
public final class UsageStatsManager {
@@ -206,6 +209,8 @@ public final class UsageStatsManager {
     * 2014 - com.example.charlie
     * </pre>
     *
     * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
     *
     * @param intervalType The time interval by which the stats are aggregated.
     * @param beginTime The inclusive beginning of the range of stats to include in the results.
     * @param endTime The exclusive end of the range of stats to include in the results.
@@ -235,6 +240,7 @@ public final class UsageStatsManager {
     * Gets the hardware configurations the device was in for the given time range, aggregated by
     * the specified interval. The results are ordered as in
     * {@link #queryUsageStats(int, long, long)}.
     * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
     *
     * @param intervalType The time interval by which the stats are aggregated.
     * @param beginTime The inclusive beginning of the range of stats to include in the results.
@@ -259,6 +265,7 @@ public final class UsageStatsManager {
    /**
     * Query for events in the given time range. Events are only kept by the system for a few
     * days.
     * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
     *
     * @param beginTime The inclusive beginning of the range of events to include in the results.
     * @param endTime The exclusive end of the range of events to include in the results.
@@ -277,10 +284,33 @@ public final class UsageStatsManager {
        return sEmptyResults;
    }

    /**
     * Like {@link #queryEvents(long, long)}, but only returns events for the calling package.
     *
     * @param beginTime The inclusive beginning of the range of events to include in the results.
     * @param endTime The exclusive end of the range of events to include in the results.
     * @return A {@link UsageEvents} object.
     *
     * @see #queryEvents(long, long)
     */
    public UsageEvents queryEventsForSelf(long beginTime, long endTime) {
        try {
            final UsageEvents events = mService.queryEventsForPackage(beginTime, endTime,
                    mContext.getOpPackageName());
            if (events != null) {
                return events;
            }
        } catch (RemoteException e) {
            // fallthrough
        }
        return sEmptyResults;
    }

    /**
     * A convenience method that queries for all stats in the given range (using the best interval
     * for that range), merges the resulting data, and keys it by package name.
     * See {@link #queryUsageStats(int, long, long)}.
     * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
     *
     * @param beginTime The inclusive beginning of the range of stats to include in the results.
     * @param endTime The exclusive end of the range of stats to include in the results.
+37 −0
Original line number Diff line number Diff line
@@ -465,6 +465,23 @@ public class UsageStatsService extends SystemService implements
        }
    }

    /**
     * Called by the Binder stub.
     */
    UsageEvents queryEventsForPackage(int userId, long beginTime, long endTime,
            String packageName) {
        synchronized (mLock) {
            final long timeNow = checkAndGetTimeLocked();
            if (!validRange(timeNow, beginTime, endTime)) {
                return null;
            }

            final UserUsageStatsService service =
                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
            return service.queryEventsForPackage(beginTime, endTime, packageName);
        }
    }

    private static boolean validRange(long currentTime, long beginTime, long endTime) {
        return beginTime <= currentTime && beginTime < endTime;
    }
@@ -660,6 +677,26 @@ public class UsageStatsService extends SystemService implements
            }
        }

        @Override
        public UsageEvents queryEventsForPackage(long beginTime, long endTime,
                String callingPackage) {
            final int callingUid = Binder.getCallingUid();
            final int callingUserId = UserHandle.getUserId(callingUid);

            if (mPackageManagerInternal.getPackageUid(callingPackage, PackageManager.MATCH_ANY_USER,
                    callingUserId) != callingUid) {
                throw new SecurityException("Calling uid " + callingPackage + " cannot query events"
                        + "for package " + callingPackage);
            }
            final long token = Binder.clearCallingIdentity();
            try {
                return UsageStatsService.this.queryEventsForPackage(callingUserId, beginTime,
                        endTime, callingPackage);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

        @Override
        public boolean isAppInactive(String packageName, int userId) {
            try {
+41 −0
Original line number Diff line number Diff line
@@ -355,6 +355,47 @@ class UserUsageStatsService {
        return new UsageEvents(results, table);
    }

    UsageEvents queryEventsForPackage(final long beginTime, final long endTime,
            final String packageName) {
        final ArraySet<String> names = new ArraySet<>();
        names.add(packageName);
        final List<UsageEvents.Event> results = queryStats(UsageStatsManager.INTERVAL_DAILY,
                beginTime, endTime, (stats, mutable, accumulatedResult) -> {
                    if (stats.events == null) {
                        return;
                    }

                    final int startIndex = stats.events.closestIndexOnOrAfter(beginTime);
                    if (startIndex < 0) {
                        return;
                    }

                    final int size = stats.events.size();
                    for (int i = startIndex; i < size; i++) {
                        if (stats.events.keyAt(i) >= endTime) {
                            return;
                        }

                        final UsageEvents.Event event = stats.events.valueAt(i);
                        if (!packageName.equals(event.mPackage)) {
                            continue;
                        }
                        if (event.mClass != null) {
                            names.add(event.mClass);
                        }
                        accumulatedResult.add(event);
                    }
                });

        if (results == null || results.isEmpty()) {
            return null;
        }

        final String[] table = names.toArray(new String[names.size()]);
        Arrays.sort(table);
        return new UsageEvents(results, table);
    }

    void persistActiveStats() {
        if (mStatsChanged) {
            Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk");