blob: d9803ddfb9353554bfe508770e10f6096d9cb0b7 [file] [log] [blame]
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001/**
2 * Copyright (C) 2007 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
17package com.android.settings;
18
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080019import android.app.Activity;
Adam Lesinski1789f7d2014-08-06 17:53:38 -070020import android.app.usage.UsageStats;
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070021import android.app.usage.UsageStatsManager;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080022import android.content.Context;
23import android.content.pm.ApplicationInfo;
24import android.content.pm.PackageManager;
25import android.content.pm.PackageManager.NameNotFoundException;
26import android.os.Bundle;
Jason Monk39b46742015-09-10 15:52:51 -040027import android.text.format.DateUtils;
28import android.util.ArrayMap;
29import android.util.Log;
30import android.view.LayoutInflater;
31import android.view.View;
32import android.view.ViewGroup;
33import android.widget.AdapterView;
34import android.widget.AdapterView.OnItemSelectedListener;
35import android.widget.BaseAdapter;
36import android.widget.ListView;
37import android.widget.Spinner;
38import android.widget.TextView;
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070039
40import java.text.DateFormat;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080041import java.util.ArrayList;
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070042import java.util.Calendar;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080043import java.util.Collections;
44import java.util.Comparator;
Adam Lesinski1789f7d2014-08-06 17:53:38 -070045import java.util.List;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080046import java.util.Map;
47
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080048/**
49 * Activity to display package usage statistics.
50 */
Adam Lesinski1789f7d2014-08-06 17:53:38 -070051public class UsageStatsActivity extends Activity implements OnItemSelectedListener {
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070052 private static final String TAG = "UsageStatsActivity";
Christian Mehlmauerb8eb4742010-06-05 14:42:00 +020053 private static final boolean localLOGV = false;
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070054 private UsageStatsManager mUsageStatsManager;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080055 private LayoutInflater mInflater;
56 private UsageStatsAdapter mAdapter;
57 private PackageManager mPm;
Adam Lesinski1789f7d2014-08-06 17:53:38 -070058
59 public static class AppNameComparator implements Comparator<UsageStats> {
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070060 private Map<String, String> mAppLabelList;
61
62 AppNameComparator(Map<String, String> appList) {
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080063 mAppLabelList = appList;
64 }
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070065
66 @Override
Adam Lesinski1789f7d2014-08-06 17:53:38 -070067 public final int compare(UsageStats a, UsageStats b) {
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070068 String alabel = mAppLabelList.get(a.getPackageName());
69 String blabel = mAppLabelList.get(b.getPackageName());
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080070 return alabel.compareTo(blabel);
71 }
72 }
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070073
Adam Lesinski1789f7d2014-08-06 17:53:38 -070074 public static class LastTimeUsedComparator implements Comparator<UsageStats> {
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070075 @Override
Adam Lesinski1789f7d2014-08-06 17:53:38 -070076 public final int compare(UsageStats a, UsageStats b) {
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080077 // return by descending order
Ian Rogers03936ce2016-06-07 00:02:42 -070078 return Long.compare(b.getLastTimeUsed(), a.getLastTimeUsed());
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080079 }
80 }
Adam Lesinski1789f7d2014-08-06 17:53:38 -070081
82 public static class UsageTimeComparator implements Comparator<UsageStats> {
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070083 @Override
Adam Lesinski1789f7d2014-08-06 17:53:38 -070084 public final int compare(UsageStats a, UsageStats b) {
Ian Rogers03936ce2016-06-07 00:02:42 -070085 return Long.compare(b.getTotalTimeInForeground(), a.getTotalTimeInForeground());
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080086 }
87 }
Adam Lesinski1789f7d2014-08-06 17:53:38 -070088
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070089 // View Holder used when displaying views
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080090 static class AppViewHolder {
91 TextView pkgName;
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070092 TextView lastTimeUsed;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080093 TextView usageTime;
94 }
Adam Lesinski1789f7d2014-08-06 17:53:38 -070095
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080096 class UsageStatsAdapter extends BaseAdapter {
97 // Constants defining order for display order
98 private static final int _DISPLAY_ORDER_USAGE_TIME = 0;
Adam Lesinski8d7be7b2014-07-17 18:30:03 -070099 private static final int _DISPLAY_ORDER_LAST_TIME_USED = 1;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800100 private static final int _DISPLAY_ORDER_APP_NAME = 2;
Adam Lesinski1789f7d2014-08-06 17:53:38 -0700101
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800102 private int mDisplayOrder = _DISPLAY_ORDER_USAGE_TIME;
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700103 private LastTimeUsedComparator mLastTimeUsedComparator = new LastTimeUsedComparator();
104 private UsageTimeComparator mUsageTimeComparator = new UsageTimeComparator();
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800105 private AppNameComparator mAppLabelComparator;
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700106 private final ArrayMap<String, String> mAppLabelMap = new ArrayMap<>();
Adam Lesinski1789f7d2014-08-06 17:53:38 -0700107 private final ArrayList<UsageStats> mPackageStats = new ArrayList<>();
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700108
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800109 UsageStatsAdapter() {
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700110 Calendar cal = Calendar.getInstance();
111 cal.add(Calendar.DAY_OF_YEAR, -5);
112
Adam Lesinski1789f7d2014-08-06 17:53:38 -0700113 final List<UsageStats> stats =
114 mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST,
115 cal.getTimeInMillis(), System.currentTimeMillis());
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700116 if (stats == null) {
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800117 return;
118 }
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700119
Adam Lesinski1789f7d2014-08-06 17:53:38 -0700120 ArrayMap<String, UsageStats> map = new ArrayMap<>();
121 final int statCount = stats.size();
122 for (int i = 0; i < statCount; i++) {
123 final android.app.usage.UsageStats pkgStats = stats.get(i);
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700124
125 // load application labels for each application
126 try {
127 ApplicationInfo appInfo = mPm.getApplicationInfo(pkgStats.getPackageName(), 0);
128 String label = appInfo.loadLabel(mPm).toString();
129 mAppLabelMap.put(pkgStats.getPackageName(), label);
Adam Lesinski1789f7d2014-08-06 17:53:38 -0700130
131 UsageStats existingStats =
132 map.get(pkgStats.getPackageName());
133 if (existingStats == null) {
134 map.put(pkgStats.getPackageName(), pkgStats);
135 } else {
136 existingStats.add(pkgStats);
137 }
138
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800139 } catch (NameNotFoundException e) {
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700140 // This package may be gone.
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800141 }
Adam Lesinski1789f7d2014-08-06 17:53:38 -0700142 }
143 mPackageStats.addAll(map.values());
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700144
Adam Lesinski1789f7d2014-08-06 17:53:38 -0700145 // Sort list
146 mAppLabelComparator = new AppNameComparator(mAppLabelMap);
147 sortList();
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800148 }
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700149
150 @Override
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800151 public int getCount() {
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700152 return mPackageStats.size();
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800153 }
154
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700155 @Override
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800156 public Object getItem(int position) {
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700157 return mPackageStats.get(position);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800158 }
159
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700160 @Override
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800161 public long getItemId(int position) {
162 return position;
163 }
164
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700165 @Override
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800166 public View getView(int position, View convertView, ViewGroup parent) {
167 // A ViewHolder keeps references to children views to avoid unneccessary calls
168 // to findViewById() on each row.
169 AppViewHolder holder;
170
171 // When convertView is not null, we can reuse it directly, there is no need
172 // to reinflate it. We only inflate a new View when the convertView supplied
173 // by ListView is null.
174 if (convertView == null) {
175 convertView = mInflater.inflate(R.layout.usage_stats_item, null);
176
177 // Creates a ViewHolder and store references to the two children views
178 // we want to bind data to.
179 holder = new AppViewHolder();
180 holder.pkgName = (TextView) convertView.findViewById(R.id.package_name);
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700181 holder.lastTimeUsed = (TextView) convertView.findViewById(R.id.last_time_used);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800182 holder.usageTime = (TextView) convertView.findViewById(R.id.usage_time);
183 convertView.setTag(holder);
184 } else {
185 // Get the ViewHolder back to get fast access to the TextView
186 // and the ImageView.
187 holder = (AppViewHolder) convertView.getTag();
188 }
189
190 // Bind the data efficiently with the holder
Adam Lesinski1789f7d2014-08-06 17:53:38 -0700191 UsageStats pkgStats = mPackageStats.get(position);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800192 if (pkgStats != null) {
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700193 String label = mAppLabelMap.get(pkgStats.getPackageName());
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800194 holder.pkgName.setText(label);
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700195 holder.lastTimeUsed.setText(DateUtils.formatSameDayTime(pkgStats.getLastTimeUsed(),
196 System.currentTimeMillis(), DateFormat.MEDIUM, DateFormat.MEDIUM));
197 holder.usageTime.setText(
Adam Lesinski1789f7d2014-08-06 17:53:38 -0700198 DateUtils.formatElapsedTime(pkgStats.getTotalTimeInForeground() / 1000));
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800199 } else {
Michael Chan87620932009-05-14 17:47:02 -0700200 Log.w(TAG, "No usage stats info for package:" + position);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800201 }
202 return convertView;
203 }
Adam Lesinski1789f7d2014-08-06 17:53:38 -0700204
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800205 void sortList(int sortOrder) {
206 if (mDisplayOrder == sortOrder) {
207 // do nothing
208 return;
209 }
210 mDisplayOrder= sortOrder;
211 sortList();
212 }
213 private void sortList() {
214 if (mDisplayOrder == _DISPLAY_ORDER_USAGE_TIME) {
215 if (localLOGV) Log.i(TAG, "Sorting by usage time");
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700216 Collections.sort(mPackageStats, mUsageTimeComparator);
217 } else if (mDisplayOrder == _DISPLAY_ORDER_LAST_TIME_USED) {
218 if (localLOGV) Log.i(TAG, "Sorting by last time used");
219 Collections.sort(mPackageStats, mLastTimeUsedComparator);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800220 } else if (mDisplayOrder == _DISPLAY_ORDER_APP_NAME) {
221 if (localLOGV) Log.i(TAG, "Sorting by application name");
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700222 Collections.sort(mPackageStats, mAppLabelComparator);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800223 }
224 notifyDataSetChanged();
225 }
226 }
227
228 /** Called when the activity is first created. */
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700229 @Override
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800230 protected void onCreate(Bundle icicle) {
231 super.onCreate(icicle);
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700232 setContentView(R.layout.usage_stats);
233
234 mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800235 mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
236 mPm = getPackageManager();
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700237
238 Spinner typeSpinner = (Spinner) findViewById(R.id.typeSpinner);
239 typeSpinner.setOnItemSelectedListener(this);
Adam Lesinski1789f7d2014-08-06 17:53:38 -0700240
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700241 ListView listView = (ListView) findViewById(R.id.pkg_list);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800242 mAdapter = new UsageStatsAdapter();
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700243 listView.setAdapter(mAdapter);
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800244 }
245
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700246 @Override
247 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800248 mAdapter.sortList(position);
249 }
250
Adam Lesinski8d7be7b2014-07-17 18:30:03 -0700251 @Override
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800252 public void onNothingSelected(AdapterView<?> parent) {
253 // do nothing
254 }
255}