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.content.Context;
     20 import android.content.pm.ParceledListSlice;
     21 import android.os.RemoteException;
     22 import android.util.ArrayMap;
     23 
     24 import java.util.Collections;
     25 import java.util.List;
     26 import java.util.Map;
     27 
     28 /**
     29  * Provides access to device usage history and statistics. Usage data is aggregated into
     30  * time intervals: days, weeks, months, and years.
     31  * <p />
     32  * When requesting usage data since a particular time, the request might look something like this:
     33  * <pre>
     34  * PAST                   REQUEST_TIME                    TODAY                   FUTURE
     35  * ||-----------------------|
     36  *                        YEAR ||                                                  |
     37  * ||-----------------------|
     38  *  MONTH            |         ||                MONTH                             |
     39  * |||-----------------------|
     40  *   |      WEEK     |     WEEK||    |     WEEK     |     WEEK     |      WEEK     |
     41  * |||-----------------------|
     42  *                             ||           |DAY|DAY|DAY|DAYDAY|DAY|DAY|DAY|DAY|DAY|
     43  * ||-----------------------|
     44  * </pre>
     45  * A request for data in the middle of a time interval will include that interval.
     46  * <p/>
     47  * <b>NOTE:</b> This API requires the permission android.permission.PACKAGE_USAGE_STATS, which
     48  * is a system-level permission and will not be granted to third-party apps. However, declaring
     49  * the permission implies intention to use the API and the user of the device can grant permission
     50  * through the Settings application.
     51  */
     52 public final class UsageStatsManager {
     53 
     54     /**
     55      * An interval type that spans a day. See {@link #queryUsageStats(int, long, long)}.
     56      */
     57     public static final int INTERVAL_DAILY = 0;
     58 
     59     /**
     60      * An interval type that spans a week. See {@link #queryUsageStats(int, long, long)}.
     61      */
     62     public static final int INTERVAL_WEEKLY = 1;
     63 
     64     /**
     65      * An interval type that spans a month. See {@link #queryUsageStats(int, long, long)}.
     66      */
     67     public static final int INTERVAL_MONTHLY = 2;
     68 
     69     /**
     70      * An interval type that spans a year. See {@link #queryUsageStats(int, long, long)}.
     71      */
     72     public static final int INTERVAL_YEARLY = 3;
     73 
     74     /**
     75      * An interval type that will use the best fit interval for the given time range.
     76      * See {@link #queryUsageStats(int, long, long)}.
     77      */
     78     public static final int INTERVAL_BEST = 4;
     79 
     80     /**
     81      * The number of available intervals. Does not include {@link #INTERVAL_BEST}, since it
     82      * is a pseudo interval (it actually selects a real interval).
     83      * {@hide}
     84      */
     85     public static final int INTERVAL_COUNT = 4;
     86 
     87     private static final UsageEvents sEmptyResults = new UsageEvents();
     88 
     89     private final Context mContext;
     90     private final IUsageStatsManager mService;
     91 
     92     /**
     93      * {@hide}
     94      */
     95     public UsageStatsManager(Context context, IUsageStatsManager service) {
     96         mContext = context;
     97         mService = service;
     98     }
     99 
    100     /**
    101      * Gets application usage stats for the given time range, aggregated by the specified interval.
    102      * <p>The returned list will contain a {@link UsageStats} object for each package that
    103      * has data for an interval that is a subset of the time range given. To illustrate:</p>
    104      * <pre>
    105      * intervalType = INTERVAL_YEARLY
    106      * beginTime = 2013
    107      * endTime = 2015 (exclusive)
    108      *
    109      * Results:
    110      * 2013 - com.example.alpha
    111      * 2013 - com.example.beta
    112      * 2014 - com.example.alpha
    113      * 2014 - com.example.beta
    114      * 2014 - com.example.charlie
    115      * </pre>
    116      *
    117      * @param intervalType The time interval by which the stats are aggregated.
    118      * @param beginTime The inclusive beginning of the range of stats to include in the results.
    119      * @param endTime The exclusive end of the range of stats to include in the results.
    120      * @return A list of {@link UsageStats} or null if none are available.
    121      *
    122      * @see #INTERVAL_DAILY
    123      * @see #INTERVAL_WEEKLY
    124      * @see #INTERVAL_MONTHLY
    125      * @see #INTERVAL_YEARLY
    126      * @see #INTERVAL_BEST
    127      */
    128     public List<UsageStats> queryUsageStats(int intervalType, long beginTime, long endTime) {
    129         try {
    130             @SuppressWarnings("unchecked")
    131             ParceledListSlice<UsageStats> slice = mService.queryUsageStats(intervalType, beginTime,
    132                     endTime, mContext.getOpPackageName());
    133             if (slice != null) {
    134                 return slice.getList();
    135             }
    136         } catch (RemoteException e) {
    137             // fallthrough and return null.
    138         }
    139         return Collections.emptyList();
    140     }
    141 
    142     /**
    143      * Gets the hardware configurations the device was in for the given time range, aggregated by
    144      * the specified interval. The results are ordered as in
    145      * {@link #queryUsageStats(int, long, long)}.
    146      *
    147      * @param intervalType The time interval by which the stats are aggregated.
    148      * @param beginTime The inclusive beginning of the range of stats to include in the results.
    149      * @param endTime The exclusive end of the range of stats to include in the results.
    150      * @return A list of {@link ConfigurationStats} or null if none are available.
    151      */
    152     public List<ConfigurationStats> queryConfigurations(int intervalType, long beginTime,
    153             long endTime) {
    154         try {
    155             @SuppressWarnings("unchecked")
    156             ParceledListSlice<ConfigurationStats> slice = mService.queryConfigurationStats(
    157                     intervalType, beginTime, endTime, mContext.getOpPackageName());
    158             if (slice != null) {
    159                 return slice.getList();
    160             }
    161         } catch (RemoteException e) {
    162             // fallthrough and return the empty list.
    163         }
    164         return Collections.emptyList();
    165     }
    166 
    167     /**
    168      * Query for events in the given time range. Events are only kept by the system for a few
    169      * days.
    170      * <p />
    171      * <b>NOTE:</b> The last few minutes of the event log will be truncated to prevent abuse
    172      * by applications.
    173      *
    174      * @param beginTime The inclusive beginning of the range of events to include in the results.
    175      * @param endTime The exclusive end of the range of events to include in the results.
    176      * @return A {@link UsageEvents}.
    177      */
    178     public UsageEvents queryEvents(long beginTime, long endTime) {
    179         try {
    180             UsageEvents iter = mService.queryEvents(beginTime, endTime,
    181                     mContext.getOpPackageName());
    182             if (iter != null) {
    183                 return iter;
    184             }
    185         } catch (RemoteException e) {
    186             // fallthrough and return null
    187         }
    188         return sEmptyResults;
    189     }
    190 
    191     /**
    192      * A convenience method that queries for all stats in the given range (using the best interval
    193      * for that range), merges the resulting data, and keys it by package name.
    194      * See {@link #queryUsageStats(int, long, long)}.
    195      *
    196      * @param beginTime The inclusive beginning of the range of stats to include in the results.
    197      * @param endTime The exclusive end of the range of stats to include in the results.
    198      * @return A {@link java.util.Map} keyed by package name, or null if no stats are
    199      *         available.
    200      */
    201     public Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) {
    202         List<UsageStats> stats = queryUsageStats(INTERVAL_BEST, beginTime, endTime);
    203         if (stats.isEmpty()) {
    204             return Collections.emptyMap();
    205         }
    206 
    207         ArrayMap<String, UsageStats> aggregatedStats = new ArrayMap<>();
    208         final int statCount = stats.size();
    209         for (int i = 0; i < statCount; i++) {
    210             UsageStats newStat = stats.get(i);
    211             UsageStats existingStat = aggregatedStats.get(newStat.getPackageName());
    212             if (existingStat == null) {
    213                 aggregatedStats.put(newStat.mPackageName, newStat);
    214             } else {
    215                 existingStat.add(newStat);
    216             }
    217         }
    218         return aggregatedStats;
    219     }
    220 }
    221