1 2 3/** 4 * Copyright (C) 2007 The Android Open Source Project 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 7 * use this file except in compliance with the License. You may obtain a copy 8 * of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 * License for the specific language governing permissions and limitations 16 * under the License. 17 */ 18 19package com.android.settings; 20 21import com.android.internal.app.IUsageStats; 22import com.android.settings.R; 23import android.app.Activity; 24import android.content.Context; 25import android.content.pm.ApplicationInfo; 26import android.content.pm.PackageManager; 27import android.content.pm.PackageManager.NameNotFoundException; 28import android.os.Bundle; 29import android.os.RemoteException; 30import android.os.ServiceManager; 31import com.android.internal.os.PkgUsageStats; 32import java.util.ArrayList; 33import java.util.Collections; 34import java.util.Comparator; 35import java.util.HashMap; 36import java.util.List; 37import java.util.Map; 38 39import android.util.Log; 40import android.view.LayoutInflater; 41import android.view.View; 42import android.view.ViewGroup; 43import android.widget.AdapterView; 44import android.widget.BaseAdapter; 45import android.widget.ListView; 46import android.widget.Spinner; 47import android.widget.TextView; 48import android.widget.AdapterView.OnItemSelectedListener; 49 50/** 51 * Activity to display package usage statistics. 52 */ 53public class UsageStats extends Activity implements OnItemSelectedListener { 54 private static final String TAG="UsageStatsActivity"; 55 private static final boolean localLOGV = true; 56 private Spinner mTypeSpinner; 57 private ListView mListView; 58 private IUsageStats mUsageStatsService; 59 private LayoutInflater mInflater; 60 private UsageStatsAdapter mAdapter; 61 private PackageManager mPm; 62 63 public static class AppNameComparator implements Comparator<PkgUsageStats> { 64 Map<String, CharSequence> mAppLabelList; 65 AppNameComparator(Map<String, CharSequence> appList) { 66 mAppLabelList = appList; 67 } 68 public final int compare(PkgUsageStats a, PkgUsageStats b) { 69 String alabel = mAppLabelList.get(a.packageName).toString(); 70 String blabel = mAppLabelList.get(b.packageName).toString(); 71 return alabel.compareTo(blabel); 72 } 73 } 74 75 public static class LaunchCountComparator implements Comparator<PkgUsageStats> { 76 public final int compare(PkgUsageStats a, PkgUsageStats b) { 77 // return by descending order 78 return b.launchCount - a.launchCount; 79 } 80 } 81 82 public static class UsageTimeComparator implements Comparator<PkgUsageStats> { 83 public final int compare(PkgUsageStats a, PkgUsageStats b) { 84 long ret = a.usageTime-b.usageTime; 85 if (ret == 0) { 86 return 0; 87 } 88 if (ret < 0) { 89 return 1; 90 } 91 return -1; 92 } 93 } 94 95 // View Holder used when displaying views 96 static class AppViewHolder { 97 TextView pkgName; 98 TextView launchCount; 99 TextView usageTime; 100 } 101 102 class UsageStatsAdapter extends BaseAdapter { 103 // Constants defining order for display order 104 private static final int _DISPLAY_ORDER_USAGE_TIME = 0; 105 private static final int _DISPLAY_ORDER_LAUNCH_COUNT = 1; 106 private static final int _DISPLAY_ORDER_APP_NAME = 2; 107 108 private int mDisplayOrder = _DISPLAY_ORDER_USAGE_TIME; 109 private List<PkgUsageStats> mUsageStats; 110 private LaunchCountComparator mLaunchCountComparator; 111 private UsageTimeComparator mUsageTimeComparator; 112 private AppNameComparator mAppLabelComparator; 113 private HashMap<String, CharSequence> mAppLabelMap; 114 115 UsageStatsAdapter() { 116 mUsageStats = new ArrayList<PkgUsageStats>(); 117 mAppLabelMap = new HashMap<String, CharSequence>(); 118 PkgUsageStats[] stats; 119 try { 120 stats = mUsageStatsService.getAllPkgUsageStats(); 121 } catch (RemoteException e) { 122 Log.e(TAG, "Failed initializing usage stats service"); 123 return; 124 } 125 if (stats == null) { 126 return; 127 } 128 for (PkgUsageStats ps : stats) { 129 mUsageStats.add(ps); 130 // load application labels for each application 131 CharSequence label; 132 try { 133 ApplicationInfo appInfo = mPm.getApplicationInfo(ps.packageName, 0); 134 label = appInfo.loadLabel(mPm); 135 } catch (NameNotFoundException e) { 136 label = ps.packageName; 137 } 138 mAppLabelMap.put(ps.packageName, label); 139 } 140 // Sort list 141 mLaunchCountComparator = new LaunchCountComparator(); 142 mUsageTimeComparator = new UsageTimeComparator(); 143 mAppLabelComparator = new AppNameComparator(mAppLabelMap); 144 sortList(); 145 } 146 public int getCount() { 147 return mUsageStats.size(); 148 } 149 150 public Object getItem(int position) { 151 return mUsageStats.get(position); 152 } 153 154 public long getItemId(int position) { 155 return position; 156 } 157 158 public View getView(int position, View convertView, ViewGroup parent) { 159 // A ViewHolder keeps references to children views to avoid unneccessary calls 160 // to findViewById() on each row. 161 AppViewHolder holder; 162 163 // When convertView is not null, we can reuse it directly, there is no need 164 // to reinflate it. We only inflate a new View when the convertView supplied 165 // by ListView is null. 166 if (convertView == null) { 167 convertView = mInflater.inflate(R.layout.usage_stats_item, null); 168 169 // Creates a ViewHolder and store references to the two children views 170 // we want to bind data to. 171 holder = new AppViewHolder(); 172 holder.pkgName = (TextView) convertView.findViewById(R.id.package_name); 173 holder.launchCount = (TextView) convertView.findViewById(R.id.launch_count); 174 holder.usageTime = (TextView) convertView.findViewById(R.id.usage_time); 175 convertView.setTag(holder); 176 } else { 177 // Get the ViewHolder back to get fast access to the TextView 178 // and the ImageView. 179 holder = (AppViewHolder) convertView.getTag(); 180 } 181 182 // Bind the data efficiently with the holder 183 PkgUsageStats pkgStats = mUsageStats.get(position); 184 if (pkgStats != null) { 185 CharSequence label = mAppLabelMap.get(pkgStats.packageName); 186 holder.pkgName.setText(label); 187 holder.launchCount.setText(String.valueOf(pkgStats.launchCount)); 188 holder.usageTime.setText(String.valueOf(pkgStats.usageTime)+" ms"); 189 } else { 190 Log.w(TAG, "No usage stats info for package:" + position); 191 } 192 return convertView; 193 } 194 195 void sortList(int sortOrder) { 196 if (mDisplayOrder == sortOrder) { 197 // do nothing 198 return; 199 } 200 mDisplayOrder= sortOrder; 201 sortList(); 202 } 203 private void sortList() { 204 if (mDisplayOrder == _DISPLAY_ORDER_USAGE_TIME) { 205 if (localLOGV) Log.i(TAG, "Sorting by usage time"); 206 Collections.sort(mUsageStats, mUsageTimeComparator); 207 } else if (mDisplayOrder == _DISPLAY_ORDER_LAUNCH_COUNT) { 208 if (localLOGV) Log.i(TAG, "Sorting launch count"); 209 Collections.sort(mUsageStats, mLaunchCountComparator); 210 } else if (mDisplayOrder == _DISPLAY_ORDER_APP_NAME) { 211 if (localLOGV) Log.i(TAG, "Sorting by application name"); 212 Collections.sort(mUsageStats, mAppLabelComparator); 213 } 214 notifyDataSetChanged(); 215 } 216 } 217 218 /** Called when the activity is first created. */ 219 protected void onCreate(Bundle icicle) { 220 super.onCreate(icicle); 221 mUsageStatsService = IUsageStats.Stub.asInterface(ServiceManager.getService("usagestats")); 222 if (mUsageStatsService == null) { 223 Log.e(TAG, "Failed to retrieve usagestats service"); 224 return; 225 } 226 mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 227 mPm = getPackageManager(); 228 229 setContentView(R.layout.usage_stats); 230 mTypeSpinner = (Spinner) findViewById(R.id.typeSpinner); 231 mTypeSpinner.setOnItemSelectedListener(this); 232 233 mListView = (ListView) findViewById(R.id.pkg_list); 234 // Initialize the inflater 235 236 mAdapter = new UsageStatsAdapter(); 237 mListView.setAdapter(mAdapter); 238 } 239 240 public void onItemSelected(AdapterView<?> parent, View view, int position, 241 long id) { 242 mAdapter.sortList(position); 243 } 244 245 public void onNothingSelected(AdapterView<?> parent) { 246 // do nothing 247 } 248} 249 250