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 import android.text.format.DateUtils;
     28 import android.util.ArrayMap;
     29 import android.util.Log;
     30 import android.view.LayoutInflater;
     31 import android.view.View;
     32 import android.view.ViewGroup;
     33 import android.widget.AdapterView;
     34 import android.widget.AdapterView.OnItemSelectedListener;
     35 import android.widget.BaseAdapter;
     36 import android.widget.ListView;
     37 import android.widget.Spinner;
     38 import android.widget.TextView;
     39 
     40 import java.text.DateFormat;
     41 import java.util.ArrayList;
     42 import java.util.Calendar;
     43 import java.util.Collections;
     44 import java.util.Comparator;
     45 import java.util.List;
     46 import java.util.Map;
     47 
     48 /**
     49  * Activity to display package usage statistics.
     50  */
     51 public class UsageStatsActivity extends Activity implements OnItemSelectedListener {
     52     private static final String TAG = "UsageStatsActivity";
     53     private static final boolean localLOGV = false;
     54     private UsageStatsManager mUsageStatsManager;
     55     private LayoutInflater mInflater;
     56     private UsageStatsAdapter mAdapter;
     57     private PackageManager mPm;
     58 
     59     public static class AppNameComparator implements Comparator<UsageStats> {
     60         private Map<String, String> mAppLabelList;
     61 
     62         AppNameComparator(Map<String, String> appList) {
     63             mAppLabelList = appList;
     64         }
     65 
     66         @Override
     67         public final int compare(UsageStats a, UsageStats b) {
     68             String alabel = mAppLabelList.get(a.getPackageName());
     69             String blabel = mAppLabelList.get(b.getPackageName());
     70             return alabel.compareTo(blabel);
     71         }
     72     }
     73 
     74     public static class LastTimeUsedComparator implements Comparator<UsageStats> {
     75         @Override
     76         public final int compare(UsageStats a, UsageStats b) {
     77             // return by descending order
     78             return Long.compare(b.getLastTimeUsed(), a.getLastTimeUsed());
     79         }
     80     }
     81 
     82     public static class UsageTimeComparator implements Comparator<UsageStats> {
     83         @Override
     84         public final int compare(UsageStats a, UsageStats b) {
     85             return Long.compare(b.getTotalTimeInForeground(), a.getTotalTimeInForeground());
     86         }
     87     }
     88 
     89     // View Holder used when displaying views
     90     static class AppViewHolder {
     91         TextView pkgName;
     92         TextView lastTimeUsed;
     93         TextView usageTime;
     94     }
     95 
     96     class UsageStatsAdapter extends BaseAdapter {
     97          // Constants defining order for display order
     98         private static final int _DISPLAY_ORDER_USAGE_TIME = 0;
     99         private static final int _DISPLAY_ORDER_LAST_TIME_USED = 1;
    100         private static final int _DISPLAY_ORDER_APP_NAME = 2;
    101 
    102         private int mDisplayOrder = _DISPLAY_ORDER_USAGE_TIME;
    103         private LastTimeUsedComparator mLastTimeUsedComparator = new LastTimeUsedComparator();
    104         private UsageTimeComparator mUsageTimeComparator = new UsageTimeComparator();
    105         private AppNameComparator mAppLabelComparator;
    106         private final ArrayMap<String, String> mAppLabelMap = new ArrayMap<>();
    107         private final ArrayList<UsageStats> mPackageStats = new ArrayList<>();
    108 
    109         UsageStatsAdapter() {
    110             Calendar cal = Calendar.getInstance();
    111             cal.add(Calendar.DAY_OF_YEAR, -5);
    112 
    113             final List<UsageStats> stats =
    114                     mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST,
    115                             cal.getTimeInMillis(), System.currentTimeMillis());
    116             if (stats == null) {
    117                 return;
    118             }
    119 
    120             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);
    124 
    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);
    130 
    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 
    139                 } catch (NameNotFoundException e) {
    140                     // This package may be gone.
    141                 }
    142             }
    143             mPackageStats.addAll(map.values());
    144 
    145             // Sort list
    146             mAppLabelComparator = new AppNameComparator(mAppLabelMap);
    147             sortList();
    148         }
    149 
    150         @Override
    151         public int getCount() {
    152             return mPackageStats.size();
    153         }
    154 
    155         @Override
    156         public Object getItem(int position) {
    157             return mPackageStats.get(position);
    158         }
    159 
    160         @Override
    161         public long getItemId(int position) {
    162             return position;
    163         }
    164 
    165         @Override
    166         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);
    181                 holder.lastTimeUsed = (TextView) convertView.findViewById(R.id.last_time_used);
    182                 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
    191             UsageStats pkgStats = mPackageStats.get(position);
    192             if (pkgStats != null) {
    193                 String label = mAppLabelMap.get(pkgStats.getPackageName());
    194                 holder.pkgName.setText(label);
    195                 holder.lastTimeUsed.setText(DateUtils.formatSameDayTime(pkgStats.getLastTimeUsed(),
    196                         System.currentTimeMillis(), DateFormat.MEDIUM, DateFormat.MEDIUM));
    197                 holder.usageTime.setText(
    198                         DateUtils.formatElapsedTime(pkgStats.getTotalTimeInForeground() / 1000));
    199             } else {
    200                 Log.w(TAG, "No usage stats info for package:" + position);
    201             }
    202             return convertView;
    203         }
    204 
    205         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");
    216                 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);
    220             } else if (mDisplayOrder == _DISPLAY_ORDER_APP_NAME) {
    221                 if (localLOGV) Log.i(TAG, "Sorting by application name");
    222                 Collections.sort(mPackageStats, mAppLabelComparator);
    223             }
    224             notifyDataSetChanged();
    225         }
    226     }
    227 
    228     /** Called when the activity is first created. */
    229     @Override
    230     protected void onCreate(Bundle icicle) {
    231         super.onCreate(icicle);
    232         setContentView(R.layout.usage_stats);
    233 
    234         mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
    235         mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    236         mPm = getPackageManager();
    237 
    238         Spinner typeSpinner = (Spinner) findViewById(R.id.typeSpinner);
    239         typeSpinner.setOnItemSelectedListener(this);
    240 
    241         ListView listView = (ListView) findViewById(R.id.pkg_list);
    242         mAdapter = new UsageStatsAdapter();
    243         listView.setAdapter(mAdapter);
    244     }
    245 
    246     @Override
    247     public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    248         mAdapter.sortList(position);
    249     }
    250 
    251     @Override
    252     public void onNothingSelected(AdapterView<?> parent) {
    253         // do nothing
    254     }
    255 }
    256