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.os.Bundle;
     21 import android.os.Parcel;
     22 import android.os.Parcelable;
     23 import android.util.ArrayMap;
     24 
     25 /**
     26  * Contains usage statistics for an app package for a specific
     27  * time range.
     28  */
     29 public final class UsageStats implements Parcelable {
     30 
     31     /**
     32      * {@hide}
     33      */
     34     public String mPackageName;
     35 
     36     /**
     37      * {@hide}
     38      */
     39     public long mBeginTimeStamp;
     40 
     41     /**
     42      * {@hide}
     43      */
     44     public long mEndTimeStamp;
     45 
     46     /**
     47      * Last time used by the user with an explicit action (notification, activity launch).
     48      * {@hide}
     49      */
     50     public long mLastTimeUsed;
     51 
     52     /**
     53      * {@hide}
     54      */
     55     public long mTotalTimeInForeground;
     56 
     57     /**
     58      * {@hide}
     59      */
     60     public int mLaunchCount;
     61 
     62     /**
     63      * {@hide}
     64      */
     65     public int mAppLaunchCount;
     66 
     67     /**
     68      * {@hide}
     69      */
     70     public int mLastEvent;
     71 
     72     /**
     73      * {@hide}
     74      */
     75     public ArrayMap<String, ArrayMap<String, Integer>> mChooserCounts;
     76 
     77     /**
     78      * {@hide}
     79      */
     80     public UsageStats() {
     81     }
     82 
     83     public UsageStats(UsageStats stats) {
     84         mPackageName = stats.mPackageName;
     85         mBeginTimeStamp = stats.mBeginTimeStamp;
     86         mEndTimeStamp = stats.mEndTimeStamp;
     87         mLastTimeUsed = stats.mLastTimeUsed;
     88         mTotalTimeInForeground = stats.mTotalTimeInForeground;
     89         mLaunchCount = stats.mLaunchCount;
     90         mAppLaunchCount = stats.mAppLaunchCount;
     91         mLastEvent = stats.mLastEvent;
     92         mChooserCounts = stats.mChooserCounts;
     93     }
     94 
     95     /**
     96      * {@hide}
     97      */
     98     public UsageStats getObfuscatedForInstantApp() {
     99         final UsageStats ret = new UsageStats(this);
    100 
    101         ret.mPackageName = UsageEvents.INSTANT_APP_PACKAGE_NAME;
    102 
    103         return ret;
    104     }
    105 
    106     public String getPackageName() {
    107         return mPackageName;
    108     }
    109 
    110     /**
    111      * Get the beginning of the time range this {@link android.app.usage.UsageStats} represents,
    112      * measured in milliseconds since the epoch.
    113      * <p/>
    114      * See {@link System#currentTimeMillis()}.
    115      */
    116     public long getFirstTimeStamp() {
    117         return mBeginTimeStamp;
    118     }
    119 
    120     /**
    121      * Get the end of the time range this {@link android.app.usage.UsageStats} represents,
    122      * measured in milliseconds since the epoch.
    123      * <p/>
    124      * See {@link System#currentTimeMillis()}.
    125      */
    126     public long getLastTimeStamp() {
    127         return mEndTimeStamp;
    128     }
    129 
    130     /**
    131      * Get the last time this package was used, measured in milliseconds since the epoch.
    132      * <p/>
    133      * See {@link System#currentTimeMillis()}.
    134      */
    135     public long getLastTimeUsed() {
    136         return mLastTimeUsed;
    137     }
    138 
    139     /**
    140      * Get the total time this package spent in the foreground, measured in milliseconds.
    141      */
    142     public long getTotalTimeInForeground() {
    143         return mTotalTimeInForeground;
    144     }
    145 
    146     /**
    147      * Returns the number of times the app was launched as an activity from outside of the app.
    148      * Excludes intra-app activity transitions.
    149      * @hide
    150      */
    151     @SystemApi
    152     public int getAppLaunchCount() {
    153         return mAppLaunchCount;
    154     }
    155 
    156     /**
    157      * Add the statistics from the right {@link UsageStats} to the left. The package name for
    158      * both {@link UsageStats} objects must be the same.
    159      * @param right The {@link UsageStats} object to merge into this one.
    160      * @throws java.lang.IllegalArgumentException if the package names of the two
    161      *         {@link UsageStats} objects are different.
    162      */
    163     public void add(UsageStats right) {
    164         if (!mPackageName.equals(right.mPackageName)) {
    165             throw new IllegalArgumentException("Can't merge UsageStats for package '" +
    166                     mPackageName + "' with UsageStats for package '" + right.mPackageName + "'.");
    167         }
    168 
    169         // We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with
    170         // regards to their mEndTimeStamp.
    171         if (right.mBeginTimeStamp > mBeginTimeStamp) {
    172             // Even though incoming UsageStat begins after this one, its last time used fields
    173             // may somehow be empty or chronologically preceding the older UsageStat.
    174             mLastEvent = Math.max(mLastEvent, right.mLastEvent);
    175             mLastTimeUsed = Math.max(mLastTimeUsed, right.mLastTimeUsed);
    176         }
    177         mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
    178         mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
    179         mTotalTimeInForeground += right.mTotalTimeInForeground;
    180         mLaunchCount += right.mLaunchCount;
    181         mAppLaunchCount += right.mAppLaunchCount;
    182         if (mChooserCounts == null) {
    183             mChooserCounts = right.mChooserCounts;
    184         } else if (right.mChooserCounts != null) {
    185             final int chooserCountsSize = right.mChooserCounts.size();
    186             for (int i = 0; i < chooserCountsSize; i++) {
    187                 String action = right.mChooserCounts.keyAt(i);
    188                 ArrayMap<String, Integer> counts = right.mChooserCounts.valueAt(i);
    189                 if (!mChooserCounts.containsKey(action) || mChooserCounts.get(action) == null) {
    190                     mChooserCounts.put(action, counts);
    191                     continue;
    192                 }
    193                 final int annotationSize = counts.size();
    194                 for (int j = 0; j < annotationSize; j++) {
    195                     String key = counts.keyAt(j);
    196                     int rightValue = counts.valueAt(j);
    197                     int leftValue = mChooserCounts.get(action).getOrDefault(key, 0);
    198                     mChooserCounts.get(action).put(key, leftValue + rightValue);
    199                 }
    200             }
    201         }
    202     }
    203 
    204     @Override
    205     public int describeContents() {
    206         return 0;
    207     }
    208 
    209     @Override
    210     public void writeToParcel(Parcel dest, int flags) {
    211         dest.writeString(mPackageName);
    212         dest.writeLong(mBeginTimeStamp);
    213         dest.writeLong(mEndTimeStamp);
    214         dest.writeLong(mLastTimeUsed);
    215         dest.writeLong(mTotalTimeInForeground);
    216         dest.writeInt(mLaunchCount);
    217         dest.writeInt(mAppLaunchCount);
    218         dest.writeInt(mLastEvent);
    219         Bundle allCounts = new Bundle();
    220         if (mChooserCounts != null) {
    221             final int chooserCountSize = mChooserCounts.size();
    222             for (int i = 0; i < chooserCountSize; i++) {
    223                 String action = mChooserCounts.keyAt(i);
    224                 ArrayMap<String, Integer> counts = mChooserCounts.valueAt(i);
    225                 Bundle currentCounts = new Bundle();
    226                 final int annotationSize = counts.size();
    227                 for (int j = 0; j < annotationSize; j++) {
    228                     currentCounts.putInt(counts.keyAt(j), counts.valueAt(j));
    229                 }
    230                 allCounts.putBundle(action, currentCounts);
    231             }
    232         }
    233         dest.writeBundle(allCounts);
    234     }
    235 
    236     public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() {
    237         @Override
    238         public UsageStats createFromParcel(Parcel in) {
    239             UsageStats stats = new UsageStats();
    240             stats.mPackageName = in.readString();
    241             stats.mBeginTimeStamp = in.readLong();
    242             stats.mEndTimeStamp = in.readLong();
    243             stats.mLastTimeUsed = in.readLong();
    244             stats.mTotalTimeInForeground = in.readLong();
    245             stats.mLaunchCount = in.readInt();
    246             stats.mAppLaunchCount = in.readInt();
    247             stats.mLastEvent = in.readInt();
    248             Bundle allCounts = in.readBundle();
    249             if (allCounts != null) {
    250                 stats.mChooserCounts = new ArrayMap<>();
    251                 for (String action : allCounts.keySet()) {
    252                     if (!stats.mChooserCounts.containsKey(action)) {
    253                         ArrayMap<String, Integer> newCounts = new ArrayMap<>();
    254                         stats.mChooserCounts.put(action, newCounts);
    255                     }
    256                     Bundle currentCounts = allCounts.getBundle(action);
    257                     if (currentCounts != null) {
    258                         for (String key : currentCounts.keySet()) {
    259                             int value = currentCounts.getInt(key);
    260                             if (value > 0) {
    261                                 stats.mChooserCounts.get(action).put(key, value);
    262                             }
    263                         }
    264                     }
    265                 }
    266             }
    267             return stats;
    268         }
    269 
    270         @Override
    271         public UsageStats[] newArray(int size) {
    272             return new UsageStats[size];
    273         }
    274     };
    275 }
    276