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