1/** 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 19import android.app.Activity; 20import android.app.usage.UsageStats; 21import android.app.usage.UsageStatsManager; 22import android.content.Context; 23import android.content.pm.ApplicationInfo; 24import android.content.pm.PackageManager; 25import android.content.pm.PackageManager.NameNotFoundException; 26import android.os.Bundle; 27 28import java.text.DateFormat; 29import java.util.ArrayList; 30import java.util.Calendar; 31import java.util.Collections; 32import java.util.Comparator; 33import java.util.List; 34import java.util.Map; 35 36import android.text.format.DateUtils; 37import android.util.ArrayMap; 38import android.util.Log; 39import android.view.LayoutInflater; 40import android.view.View; 41import android.view.ViewGroup; 42import android.widget.AdapterView; 43import android.widget.BaseAdapter; 44import android.widget.ListView; 45import android.widget.Spinner; 46import android.widget.TextView; 47import android.widget.AdapterView.OnItemSelectedListener; 48 49/** 50 * Activity to display package usage statistics. 51 */ 52public class UsageStatsActivity extends Activity implements OnItemSelectedListener { 53 private static final String TAG = "UsageStatsActivity"; 54 private static final boolean localLOGV = false; 55 private UsageStatsManager mUsageStatsManager; 56 private LayoutInflater mInflater; 57 private UsageStatsAdapter mAdapter; 58 private PackageManager mPm; 59 60 public static class AppNameComparator implements Comparator<UsageStats> { 61 private Map<String, String> mAppLabelList; 62 63 AppNameComparator(Map<String, String> appList) { 64 mAppLabelList = appList; 65 } 66 67 @Override 68 public final int compare(UsageStats a, UsageStats b) { 69 String alabel = mAppLabelList.get(a.getPackageName()); 70 String blabel = mAppLabelList.get(b.getPackageName()); 71 return alabel.compareTo(blabel); 72 } 73 } 74 75 public static class LastTimeUsedComparator implements Comparator<UsageStats> { 76 @Override 77 public final int compare(UsageStats a, UsageStats b) { 78 // return by descending order 79 return (int)(b.getLastTimeUsed() - a.getLastTimeUsed()); 80 } 81 } 82 83 public static class UsageTimeComparator implements Comparator<UsageStats> { 84 @Override 85 public final int compare(UsageStats a, UsageStats b) { 86 return (int)(b.getTotalTimeInForeground() - a.getTotalTimeInForeground()); 87 } 88 } 89 90 // View Holder used when displaying views 91 static class AppViewHolder { 92 TextView pkgName; 93 TextView lastTimeUsed; 94 TextView usageTime; 95 } 96 97 class UsageStatsAdapter extends BaseAdapter { 98 // Constants defining order for display order 99 private static final int _DISPLAY_ORDER_USAGE_TIME = 0; 100 private static final int _DISPLAY_ORDER_LAST_TIME_USED = 1; 101 private static final int _DISPLAY_ORDER_APP_NAME = 2; 102 103 private int mDisplayOrder = _DISPLAY_ORDER_USAGE_TIME; 104 private LastTimeUsedComparator mLastTimeUsedComparator = new LastTimeUsedComparator(); 105 private UsageTimeComparator mUsageTimeComparator = new UsageTimeComparator(); 106 private AppNameComparator mAppLabelComparator; 107 private final ArrayMap<String, String> mAppLabelMap = new ArrayMap<>(); 108 private final ArrayList<UsageStats> mPackageStats = new ArrayList<>(); 109 110 UsageStatsAdapter() { 111 Calendar cal = Calendar.getInstance(); 112 cal.add(Calendar.DAY_OF_YEAR, -5); 113 114 final List<UsageStats> stats = 115 mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, 116 cal.getTimeInMillis(), System.currentTimeMillis()); 117 if (stats == null) { 118 return; 119 } 120 121 ArrayMap<String, UsageStats> map = new ArrayMap<>(); 122 final int statCount = stats.size(); 123 for (int i = 0; i < statCount; i++) { 124 final android.app.usage.UsageStats pkgStats = stats.get(i); 125 126 // load application labels for each application 127 try { 128 ApplicationInfo appInfo = mPm.getApplicationInfo(pkgStats.getPackageName(), 0); 129 String label = appInfo.loadLabel(mPm).toString(); 130 mAppLabelMap.put(pkgStats.getPackageName(), label); 131 132 UsageStats existingStats = 133 map.get(pkgStats.getPackageName()); 134 if (existingStats == null) { 135 map.put(pkgStats.getPackageName(), pkgStats); 136 } else { 137 existingStats.add(pkgStats); 138 } 139 140 } catch (NameNotFoundException e) { 141 // This package may be gone. 142 } 143 } 144 mPackageStats.addAll(map.values()); 145 146 // Sort list 147 mAppLabelComparator = new AppNameComparator(mAppLabelMap); 148 sortList(); 149 } 150 151 @Override 152 public int getCount() { 153 return mPackageStats.size(); 154 } 155 156 @Override 157 public Object getItem(int position) { 158 return mPackageStats.get(position); 159 } 160 161 @Override 162 public long getItemId(int position) { 163 return position; 164 } 165 166 @Override 167 public View getView(int position, View convertView, ViewGroup parent) { 168 // A ViewHolder keeps references to children views to avoid unneccessary calls 169 // to findViewById() on each row. 170 AppViewHolder holder; 171 172 // When convertView is not null, we can reuse it directly, there is no need 173 // to reinflate it. We only inflate a new View when the convertView supplied 174 // by ListView is null. 175 if (convertView == null) { 176 convertView = mInflater.inflate(R.layout.usage_stats_item, null); 177 178 // Creates a ViewHolder and store references to the two children views 179 // we want to bind data to. 180 holder = new AppViewHolder(); 181 holder.pkgName = (TextView) convertView.findViewById(R.id.package_name); 182 holder.lastTimeUsed = (TextView) convertView.findViewById(R.id.last_time_used); 183 holder.usageTime = (TextView) convertView.findViewById(R.id.usage_time); 184 convertView.setTag(holder); 185 } else { 186 // Get the ViewHolder back to get fast access to the TextView 187 // and the ImageView. 188 holder = (AppViewHolder) convertView.getTag(); 189 } 190 191 // Bind the data efficiently with the holder 192 UsageStats pkgStats = mPackageStats.get(position); 193 if (pkgStats != null) { 194 String label = mAppLabelMap.get(pkgStats.getPackageName()); 195 holder.pkgName.setText(label); 196 holder.lastTimeUsed.setText(DateUtils.formatSameDayTime(pkgStats.getLastTimeUsed(), 197 System.currentTimeMillis(), DateFormat.MEDIUM, DateFormat.MEDIUM)); 198 holder.usageTime.setText( 199 DateUtils.formatElapsedTime(pkgStats.getTotalTimeInForeground() / 1000)); 200 } else { 201 Log.w(TAG, "No usage stats info for package:" + position); 202 } 203 return convertView; 204 } 205 206 void sortList(int sortOrder) { 207 if (mDisplayOrder == sortOrder) { 208 // do nothing 209 return; 210 } 211 mDisplayOrder= sortOrder; 212 sortList(); 213 } 214 private void sortList() { 215 if (mDisplayOrder == _DISPLAY_ORDER_USAGE_TIME) { 216 if (localLOGV) Log.i(TAG, "Sorting by usage time"); 217 Collections.sort(mPackageStats, mUsageTimeComparator); 218 } else if (mDisplayOrder == _DISPLAY_ORDER_LAST_TIME_USED) { 219 if (localLOGV) Log.i(TAG, "Sorting by last time used"); 220 Collections.sort(mPackageStats, mLastTimeUsedComparator); 221 } else if (mDisplayOrder == _DISPLAY_ORDER_APP_NAME) { 222 if (localLOGV) Log.i(TAG, "Sorting by application name"); 223 Collections.sort(mPackageStats, mAppLabelComparator); 224 } 225 notifyDataSetChanged(); 226 } 227 } 228 229 /** Called when the activity is first created. */ 230 @Override 231 protected void onCreate(Bundle icicle) { 232 super.onCreate(icicle); 233 setContentView(R.layout.usage_stats); 234 235 mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); 236 mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 237 mPm = getPackageManager(); 238 239 Spinner typeSpinner = (Spinner) findViewById(R.id.typeSpinner); 240 typeSpinner.setOnItemSelectedListener(this); 241 242 ListView listView = (ListView) findViewById(R.id.pkg_list); 243 mAdapter = new UsageStatsAdapter(); 244 listView.setAdapter(mAdapter); 245 } 246 247 @Override 248 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 249 mAdapter.sortList(position); 250 } 251 252 @Override 253 public void onNothingSelected(AdapterView<?> parent) { 254 // do nothing 255 } 256} 257