Home | History | Annotate | Download | only in usage
      1 /**
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy
      6  * of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations
     14  * under the License.
     15  */
     16 
     17 package android.app.usage;
     18 
     19 import android.annotation.RequiresPermission;
     20 import android.annotation.SystemApi;
     21 import android.annotation.SystemService;
     22 import android.content.Context;
     23 import android.content.pm.ParceledListSlice;
     24 import android.os.RemoteException;
     25 import android.os.UserHandle;
     26 import android.util.ArrayMap;
     27 
     28 import java.util.Collections;
     29 import java.util.List;
     30 import java.util.Map;
     31 
     32 /**
     33  * Provides access to device usage history and statistics. Usage data is aggregated into
     34  * time intervals: days, weeks, months, and years.
     35  * <p />
     36  * When requesting usage data since a particular time, the request might look something like this:
     37  * <pre>
     38  * PAST                   REQUEST_TIME                    TODAY                   FUTURE
     39  * ||-----------------------|
     40  *                        YEAR ||                                                  |
     41  * ||-----------------------|
     42  *  MONTH            |         ||                MONTH                             |
     43  * |||-----------------------|
     44  *   |      WEEK     |     WEEK||    |     WEEK     |     WEEK     |      WEEK     |
     45  * |||-----------------------|
     46  *                             ||           |DAY|DAY|DAY|DAYDAY|DAY|DAY|DAY|DAY|DAY|
     47  * ||-----------------------|
     48  * </pre>
     49  * A request for data in the middle of a time interval will include that interval.
     50  * <p/>
     51  * <b>NOTE:</b> This API requires the permission android.permission.PACKAGE_USAGE_STATS, which
     52  * is a system-level permission and will not be granted to third-party apps. However, declaring
     53  * the permission implies intention to use the API and the user of the device can grant permission
     54  * through the Settings application.
     55  */
     56 @SystemService(Context.USAGE_STATS_SERVICE)
     57 public final class UsageStatsManager {
     58 
     59     /**
     60      * An interval type that spans a day. See {@link #queryUsageStats(int, long, long)}.
     61      */
     62     public static final int INTERVAL_DAILY = 0;
     63 
     64     /**
     65      * An interval type that spans a week. See {@link #queryUsageStats(int, long, long)}.
     66      */
     67     public static final int INTERVAL_WEEKLY = 1;
     68 
     69     /**
     70      * An interval type that spans a month. See {@link #queryUsageStats(int, long, long)}.
     71      */
     72     public static final int INTERVAL_MONTHLY = 2;
     73 
     74     /**
     75      * An interval type that spans a year. See {@link #queryUsageStats(int, long, long)}.
     76      */
     77     public static final int INTERVAL_YEARLY = 3;
     78 
     79     /**
     80      * An interval type that will use the best fit interval for the given time range.
     81      * See {@link #queryUsageStats(int, long, long)}.
     82      */
     83     public static final int INTERVAL_BEST = 4;
     84 
     85     /**
     86      * The number of available intervals. Does not include {@link #INTERVAL_BEST}, since it
     87      * is a pseudo interval (it actually selects a real interval).
     88      * {@hide}
     89      */
     90     public static final int INTERVAL_COUNT = 4;
     91 
     92     private static final UsageEvents sEmptyResults = new UsageEvents();
     93 
     94     private final Context mContext;
     95     private final IUsageStatsManager mService;
     96 
     97     /**
     98      * {@hide}
     99      */
    100     public UsageStatsManager(Context context, IUsageStatsManager service) {
    101         mContext = context;
    102         mService = service;
    103     }
    104 
    105     /**
    106      * Gets application usage stats for the given time range, aggregated by the specified interval.
    107      * <p>The returned list will contain a {@link UsageStats} object for each package that
    108      * has data for an interval that is a subset of the time range given. To illustrate:</p>
    109      * <pre>
    110      * intervalType = INTERVAL_YEARLY
    111      * beginTime = 2013
    112      * endTime = 2015 (exclusive)
    113      *
    114      * Results:
    115      * 2013 - com.example.alpha
    116      * 2013 - com.example.beta
    117      * 2014 - com.example.alpha
    118      * 2014 - com.example.beta
    119      * 2014 - com.example.charlie
    120      * </pre>
    121      *
    122      * @param intervalType The time interval by which the stats are aggregated.
    123      * @param beginTime The inclusive beginning of the range of stats to include in the results.
    124      * @param endTime The exclusive end of the range of stats to include in the results.
    125      * @return A list of {@link UsageStats} or null if none are available.
    126      *
    127      * @see #INTERVAL_DAILY
    128      * @see #INTERVAL_WEEKLY
    129      * @see #INTERVAL_MONTHLY
    130      * @see #INTERVAL_YEARLY
    131      * @see #INTERVAL_BEST
    132      */
    133     public List<UsageStats> queryUsageStats(int intervalType, long beginTime, long endTime) {
    134         try {
    135             @SuppressWarnings("unchecked")
    136             ParceledListSlice<UsageStats> slice = mService.queryUsageStats(intervalType, beginTime,
    137                     endTime, mContext.getOpPackageName());
    138             if (slice != null) {
    139                 return slice.getList();
    140             }
    141         } catch (RemoteException e) {
    142             // fallthrough and return null.
    143         }
    144         return Collections.emptyList();
    145     }
    146 
    147     /**
    148      * Gets the hardware configurations the device was in for the given time range, aggregated by
    149      * the specified interval. The results are ordered as in
    150      * {@link #queryUsageStats(int, long, long)}.
    151      *
    152      * @param intervalType The time interval by which the stats are aggregated.
    153      * @param beginTime The inclusive beginning of the range of stats to include in the results.
    154      * @param endTime The exclusive end of the range of stats to include in the results.
    155      * @return A list of {@link ConfigurationStats} or null if none are available.
    156      */
    157     public List<ConfigurationStats> queryConfigurations(int intervalType, long beginTime,
    158             long endTime) {
    159         try {
    160             @SuppressWarnings("unchecked")
    161             ParceledListSlice<ConfigurationStats> slice = mService.queryConfigurationStats(
    162                     intervalType, beginTime, endTime, mContext.getOpPackageName());
    163             if (slice != null) {
    164                 return slice.getList();
    165             }
    166         } catch (RemoteException e) {
    167             // fallthrough and return the empty list.
    168         }
    169         return Collections.emptyList();
    170     }
    171 
    172     /**
    173      * Query for events in the given time range. Events are only kept by the system for a few
    174      * days.
    175      * <p />
    176      * <b>NOTE:</b> The last few minutes of the event log will be truncated to prevent abuse
    177      * by applications.
    178      *
    179      * @param beginTime The inclusive beginning of the range of events to include in the results.
    180      * @param endTime The exclusive end of the range of events to include in the results.
    181      * @return A {@link UsageEvents}.
    182      */
    183     public UsageEvents queryEvents(long beginTime, long endTime) {
    184         try {
    185             UsageEvents iter = mService.queryEvents(beginTime, endTime,
    186                     mContext.getOpPackageName());
    187             if (iter != null) {
    188                 return iter;
    189             }
    190         } catch (RemoteException e) {
    191             // fallthrough and return null
    192         }
    193         return sEmptyResults;
    194     }
    195 
    196     /**
    197      * A convenience method that queries for all stats in the given range (using the best interval
    198      * for that range), merges the resulting data, and keys it by package name.
    199      * See {@link #queryUsageStats(int, long, long)}.
    200      *
    201      * @param beginTime The inclusive beginning of the range of stats to include in the results.
    202      * @param endTime The exclusive end of the range of stats to include in the results.
    203      * @return A {@link java.util.Map} keyed by package name, or null if no stats are
    204      *         available.
    205      */
    206     public Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) {
    207         List<UsageStats> stats = queryUsageStats(INTERVAL_BEST, beginTime, endTime);
    208         if (stats.isEmpty()) {
    209             return Collections.emptyMap();
    210         }
    211 
    212         ArrayMap<String, UsageStats> aggregatedStats = new ArrayMap<>();
    213         final int statCount = stats.size();
    214         for (int i = 0; i < statCount; i++) {
    215             UsageStats newStat = stats.get(i);
    216             UsageStats existingStat = aggregatedStats.get(newStat.getPackageName());
    217             if (existingStat == null) {
    218                 aggregatedStats.put(newStat.mPackageName, newStat);
    219             } else {
    220                 existingStat.add(newStat);
    221             }
    222         }
    223         return aggregatedStats;
    224     }
    225 
    226     /**
    227      * Returns whether the specified app is currently considered inactive. This will be true if the
    228      * app hasn't been used directly or indirectly for a period of time defined by the system. This
    229      * could be of the order of several hours or days.
    230      * @param packageName The package name of the app to query
    231      * @return whether the app is currently considered inactive
    232      */
    233     public boolean isAppInactive(String packageName) {
    234         try {
    235             return mService.isAppInactive(packageName, UserHandle.myUserId());
    236         } catch (RemoteException e) {
    237             // fall through and return default
    238         }
    239         return false;
    240     }
    241 
    242     /**
    243      * @hide
    244      */
    245     public void setAppInactive(String packageName, boolean inactive) {
    246         try {
    247             mService.setAppInactive(packageName, inactive, UserHandle.myUserId());
    248         } catch (RemoteException e) {
    249             // fall through
    250         }
    251     }
    252 
    253     /**
    254      * {@hide}
    255      * Temporarily whitelist the specified app for a short duration. This is to allow an app
    256      * receiving a high priority message to be able to access the network and acquire wakelocks
    257      * even if the device is in power-save mode or the app is currently considered inactive.
    258      * @param packageName The package name of the app to whitelist.
    259      * @param duration Duration to whitelist the app for, in milliseconds. It is recommended that
    260      * this be limited to 10s of seconds. Requested duration will be clamped to a few minutes.
    261      * @param user The user for whom the package should be whitelisted. Passing in a user that is
    262      * not the same as the caller's process will require the INTERACT_ACROSS_USERS permission.
    263      * @see #isAppInactive(String)
    264      */
    265     @SystemApi
    266     @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
    267     public void whitelistAppTemporarily(String packageName, long duration, UserHandle user) {
    268         try {
    269             mService.whitelistAppTemporarily(packageName, duration, user.getIdentifier());
    270         } catch (RemoteException re) {
    271         }
    272     }
    273 
    274     /**
    275      * Inform usage stats that the carrier privileged apps access rules have changed.
    276      * @hide
    277      */
    278     public void onCarrierPrivilegedAppsChanged() {
    279         try {
    280             mService.onCarrierPrivilegedAppsChanged();
    281         } catch (RemoteException re) {
    282         }
    283     }
    284 
    285     /**
    286      * Reports a Chooser action to the UsageStatsManager.
    287      *
    288      * @param packageName The package name of the app that is selected.
    289      * @param userId The user id of who makes the selection.
    290      * @param contentType The type of the content, e.g., Image, Video, App.
    291      * @param annotations The annotations of the content, e.g., Game, Selfie.
    292      * @param action The action type of Intent that invokes ChooserActivity.
    293      * {@link UsageEvents}
    294      * @hide
    295      */
    296     public void reportChooserSelection(String packageName, int userId, String contentType,
    297                                        String[] annotations, String action) {
    298         try {
    299             mService.reportChooserSelection(packageName, userId, contentType, annotations, action);
    300         } catch (RemoteException re) {
    301         }
    302     }
    303 }
    304