Home | History | Annotate | Download | only in settings
      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 
     17 package com.android.settings;
     18 
     19 import android.app.Activity;
     20 import android.app.usage.UsageStats;
     21 import android.app.usage.UsageStatsManager;
     22 import android.content.Context;
     23 import android.content.pm.ApplicationInfo;
     24 import android.content.pm.PackageManager;
     25 import android.content.pm.PackageManager.NameNotFoundException;
     26 import android.os.Bundle;
     27 
     28 import java.text.DateFormat;
     29 import java.util.ArrayList;
     30 import java.util.Calendar;
     31 import java.util.Collections;
     32 import java.util.Comparator;
     33 import java.util.List;
     34 import java.util.Map;
     35 
     36 import android.text.format.DateUtils;
     37 import android.util.ArrayMap;
     38 import android.util.Log;
     39 import android.view.LayoutInflater;
     40 import android.view.View;
     41 import android.view.ViewGroup;
     42 import android.widget.AdapterView;
     43 import android.widget.BaseAdapter;
     44 import android.widget.ListView;
     45 import android.widget.Spinner;
     46 import android.widget.TextView;
     47 import android.widget.AdapterView.OnItemSelectedListener;
     48 
     49 /**
     50  * Activity to display package usage statistics.
     51  */
     52 public 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