RecentLocationApps.java revision bfa96c3b10f53a969406755eed36ba98fc1de549
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.settings.location; 18 19import android.app.AppOpsManager; 20import android.content.Context; 21import android.content.pm.ApplicationInfo; 22import android.content.pm.PackageManager; 23import android.os.Bundle; 24import android.preference.Preference; 25import android.preference.PreferenceActivity; 26import android.preference.PreferenceCategory; 27import android.preference.PreferenceManager; 28import android.preference.PreferenceScreen; 29import android.util.Log; 30 31import com.android.settings.R; 32import com.android.settings.applications.InstalledAppDetails; 33import com.android.settings.fuelgauge.BatterySipper; 34import com.android.settings.fuelgauge.BatteryStatsHelper; 35 36import java.util.HashMap; 37import java.util.List; 38import java.util.Map; 39 40/** 41 * Retrieves the information of applications which accessed location recently. 42 */ 43public class RecentLocationApps { 44 private static final String TAG = RecentLocationApps.class.getSimpleName(); 45 46 private static final int RECENT_TIME_INTERVAL_MILLIS = 15 * 60 * 1000; 47 48 private final PreferenceActivity mActivity; 49 private final BatteryStatsHelper mStatsHelper; 50 private final PackageManager mPackageManager; 51 52 // Stores all the packages that requested location within the designated interval 53 // key - package name of the app 54 // value - whether the app has requested high power location 55 56 public RecentLocationApps(PreferenceActivity activity, BatteryStatsHelper sipperUtil) { 57 mActivity = activity; 58 mPackageManager = activity.getPackageManager(); 59 mStatsHelper = sipperUtil; 60 } 61 62 private class UidEntryClickedListener 63 implements Preference.OnPreferenceClickListener { 64 private BatterySipper mSipper; 65 66 public UidEntryClickedListener(BatterySipper sipper) { 67 mSipper = sipper; 68 } 69 70 @Override 71 public boolean onPreferenceClick(Preference preference) { 72 mStatsHelper.startBatteryDetailPage(mActivity, mSipper, false); 73 return true; 74 } 75 } 76 77 private class PackageEntryClickedListener 78 implements Preference.OnPreferenceClickListener { 79 private String mPackage; 80 81 public PackageEntryClickedListener(String packageName) { 82 mPackage = packageName; 83 } 84 85 @Override 86 public boolean onPreferenceClick(Preference preference) { 87 // start new fragment to display extended information 88 Bundle args = new Bundle(); 89 args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mPackage); 90 mActivity.startPreferencePanel(InstalledAppDetails.class.getName(), args, 91 R.string.application_info_label, null, null, 0); 92 return true; 93 } 94 } 95 96 /** 97 * Fills a list of applications which queried location recently within 98 * specified time. 99 */ 100 public void fillAppList(PreferenceCategory container) { 101 HashMap<String, Boolean> packageMap = new HashMap<String, Boolean>(); 102 AppOpsManager aoManager = 103 (AppOpsManager) mActivity.getSystemService(Context.APP_OPS_SERVICE); 104 List<AppOpsManager.PackageOps> appOps = aoManager.getPackagesForOps( 105 new int[] { 106 AppOpsManager.OP_MONITOR_LOCATION, 107 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 108 }); 109 PreferenceManager preferenceManager = container.getPreferenceManager(); 110 long now = System.currentTimeMillis(); 111 for (AppOpsManager.PackageOps ops : appOps) { 112 processPackageOps(now, container, preferenceManager, ops, packageMap); 113 } 114 115 mStatsHelper.refreshStats(); 116 List<BatterySipper> usageList = mStatsHelper.getUsageList(); 117 for (BatterySipper sipper : usageList) { 118 sipper.loadNameAndIcon(); 119 String[] packages = sipper.getPackages(); 120 if (packages == null) { 121 continue; 122 } 123 for (String curPackage : packages) { 124 if (packageMap.containsKey(curPackage)) { 125 PreferenceScreen screen = preferenceManager.createPreferenceScreen(mActivity); 126 screen.setIcon(sipper.getIcon()); 127 screen.setTitle(sipper.getLabel()); 128 if (packageMap.get(curPackage)) { 129 screen.setSummary(R.string.location_high_battery_use); 130 } else { 131 screen.setSummary(R.string.location_low_battery_use); 132 } 133 container.addPreference(screen); 134 screen.setOnPreferenceClickListener(new UidEntryClickedListener(sipper)); 135 packageMap.remove(curPackage); 136 break; 137 } 138 } 139 } 140 141 // Typically there shouldn't be any entry left in the HashMap. But if there are any, add 142 // them to the list and link them to the app info page. 143 for (Map.Entry<String, Boolean> entry : packageMap.entrySet()) { 144 try { 145 PreferenceScreen screen = preferenceManager.createPreferenceScreen(mActivity); 146 ApplicationInfo appInfo = mPackageManager.getApplicationInfo( 147 entry.getKey(), PackageManager.GET_META_DATA); 148 screen.setIcon(mPackageManager.getApplicationIcon(appInfo)); 149 screen.setTitle(mPackageManager.getApplicationLabel(appInfo)); 150 // if used both high and low battery within the time interval, show as "high 151 // battery" 152 if (entry.getValue()) { 153 screen.setSummary(R.string.location_high_battery_use); 154 } else { 155 screen.setSummary(R.string.location_low_battery_use); 156 } 157 screen.setOnPreferenceClickListener( 158 new PackageEntryClickedListener(entry.getKey())); 159 container.addPreference(screen); 160 } catch (PackageManager.NameNotFoundException e) { 161 // ignore the current app and move on to the next. 162 } 163 } 164 } 165 166 private void processPackageOps( 167 long now, 168 PreferenceCategory container, 169 PreferenceManager preferenceManager, 170 AppOpsManager.PackageOps ops, 171 HashMap<String, Boolean> packageMap) { 172 String packageName = ops.getPackageName(); 173 List<AppOpsManager.OpEntry> entries = ops.getOps(); 174 boolean highBattery = false; 175 boolean normalBattery = false; 176 for (AppOpsManager.OpEntry entry : entries) { 177 // If previous location activity is older than designated interval, ignore this app. 178 if (now - entry.getTime() <= RECENT_TIME_INTERVAL_MILLIS) { 179 switch (entry.getOp()) { 180 case AppOpsManager.OP_MONITOR_LOCATION: 181 normalBattery = true; 182 break; 183 case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION: 184 highBattery = true; 185 break; 186 default: 187 break; 188 } 189 } 190 } 191 192 if (!highBattery && !normalBattery) { 193 if (Log.isLoggable(TAG, Log.VERBOSE)) { 194 Log.v(TAG, packageName + " hadn't used location within the time interval."); 195 } 196 return; 197 } 198 199 packageMap.put(packageName, highBattery); 200 } 201} 202