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