Loading res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -2377,6 +2377,8 @@ <string name="location_mode_location_off_title">Location off</string> <!-- [CHAR LIMIT=30] Location settings screen, sub category for recent location requests --> <string name="location_category_recent_location_requests">Recent location requests</string> <!-- [CHAR LIMIT=30] Location settings screen, displayed when there's no recent app accessing location --> <string name="location_no_recent_apps">No recent apps</string> <!-- [CHAR LIMIT=30] Location settings screen, sub category for location services --> <string name="location_category_location_services">Location services</string> <!-- [CHAR LIMIT=30] Location settings screen, recent location requests high battery use--> Loading src/com/android/settings/fuelgauge/BatterySipper.java +8 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,14 @@ public class BatterySipper implements Comparable<BatterySipper> { return mPackages; } public int getUid() { // Bail out if the current sipper is not an App sipper. if (uidObj == null) { return 0; } return uidObj.getUid(); } void getQuickNameIconForUid(Uid uidObj) { final int uid = uidObj.getUid(); final String uidString = Integer.toString(uid); Loading src/com/android/settings/location/RecentLocationApps.java +140 −54 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.app.AppOpsManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceActivity; Loading @@ -33,9 +34,11 @@ import com.android.settings.applications.InstalledAppDetails; import com.android.settings.fuelgauge.BatterySipper; import com.android.settings.fuelgauge.BatteryStatsHelper; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Retrieves the information of applications which accessed location recently. Loading Loading @@ -93,12 +96,69 @@ public class RecentLocationApps { } } private PreferenceScreen createRecentLocationEntry( PreferenceManager preferenceManager, Drawable icon, CharSequence label, boolean isHighBattery, Preference.OnPreferenceClickListener listener) { PreferenceScreen screen = preferenceManager.createPreferenceScreen(mActivity); screen.setIcon(icon); screen.setTitle(label); if (isHighBattery) { screen.setSummary(R.string.location_high_battery_use); } else { screen.setSummary(R.string.location_low_battery_use); } screen.setOnPreferenceClickListener(listener); return screen; } /** * Stores a BatterySipper object and records whether the sipper has been used. */ private static final class BatterySipperWrapper { private BatterySipper mSipper; private boolean mUsed; public BatterySipperWrapper(BatterySipper sipper) { mSipper = sipper; mUsed = false; } public BatterySipper batterySipper() { return mSipper; } public boolean used() { return mUsed; } public void setUsed() { mUsed = true; } } /** * Fills a list of applications which queried location recently within * specified time. */ public void fillAppList(PreferenceCategory container) { HashMap<String, Boolean> packageMap = new HashMap<String, Boolean>(); // Retrieve Uid-based battery blaming info and generate a package to BatterySipper HashMap // for later faster looking up. mStatsHelper.refreshStats(); List<BatterySipper> usageList = mStatsHelper.getUsageList(); // Key: package Uid. Value: BatterySipperWrapper. HashMap<Integer, BatterySipperWrapper> sipperMap = new HashMap<Integer, BatterySipperWrapper>(usageList.size()); for (BatterySipper sipper: usageList) { int uid = sipper.getUid(); if (uid != 0) { sipperMap.put(uid, new BatterySipperWrapper(sipper)); } } // Retrieve a location usage list from AppOps AppOpsManager aoManager = (AppOpsManager) mActivity.getSystemService(Context.APP_OPS_SERVICE); List<AppOpsManager.PackageOps> appOps = aoManager.getPackagesForOps( Loading @@ -107,68 +167,56 @@ public class RecentLocationApps { AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, }); PreferenceManager preferenceManager = container.getPreferenceManager(); // Process the AppOps list and generate a preference list. ArrayList<PreferenceScreen> prefs = new ArrayList<PreferenceScreen>(); long now = System.currentTimeMillis(); for (AppOpsManager.PackageOps ops : appOps) { processPackageOps(now, container, preferenceManager, ops, packageMap); BatterySipperWrapper wrapper = sipperMap.get(ops.getUid()); PreferenceScreen screen = getScreenFromOps(preferenceManager, now, ops, wrapper); if (screen != null) { prefs.add(screen); } mStatsHelper.refreshStats(); List<BatterySipper> usageList = mStatsHelper.getUsageList(); for (BatterySipper sipper : usageList) { sipper.loadNameAndIcon(); String[] packages = sipper.getPackages(); if (packages == null) { continue; } for (String curPackage : packages) { if (packageMap.containsKey(curPackage)) { PreferenceScreen screen = preferenceManager.createPreferenceScreen(mActivity); screen.setIcon(sipper.getIcon()); screen.setTitle(sipper.getLabel()); if (packageMap.get(curPackage)) { screen.setSummary(R.string.location_high_battery_use); } else { screen.setSummary(R.string.location_low_battery_use); } container.addPreference(screen); screen.setOnPreferenceClickListener(new UidEntryClickedListener(sipper)); packageMap.remove(curPackage); break; } if (prefs.size() > 0) { // If there's some items to display, sort the items and add them to the container. Collections.sort(prefs, new Comparator<PreferenceScreen>() { @Override public int compare(PreferenceScreen lhs, PreferenceScreen rhs) { return lhs.getTitle().toString().compareTo(rhs.getTitle().toString()); } }); for (PreferenceScreen entry : prefs) { container.addPreference(entry); } // Typically there shouldn't be any entry left in the HashMap. But if there are any, add // them to the list and link them to the app info page. for (Map.Entry<String, Boolean> entry : packageMap.entrySet()) { try { PreferenceScreen screen = preferenceManager.createPreferenceScreen(mActivity); ApplicationInfo appInfo = mPackageManager.getApplicationInfo( entry.getKey(), PackageManager.GET_META_DATA); screen.setIcon(mPackageManager.getApplicationIcon(appInfo)); screen.setTitle(mPackageManager.getApplicationLabel(appInfo)); // if used both high and low battery within the time interval, show as "high // battery" if (entry.getValue()) { screen.setSummary(R.string.location_high_battery_use); } else { screen.setSummary(R.string.location_low_battery_use); } screen.setOnPreferenceClickListener( new PackageEntryClickedListener(entry.getKey())); // If there's no item to display, add a "No recent apps" item. PreferenceScreen screen = preferenceManager.createPreferenceScreen(mActivity); screen.setTitle(R.string.location_no_recent_apps); screen.setSelectable(false); screen.setEnabled(false); container.addPreference(screen); } catch (PackageManager.NameNotFoundException e) { // ignore the current app and move on to the next. } } } private void processPackageOps( long now, PreferenceCategory container, /** * Creates a PreferenceScreen entry for the given PackageOps. * * This method examines the time interval of the PackageOps first. If the PackageOps is older * than the designated interval, this method ignores the PackageOps object and returns null. * * When the PackageOps is fresh enough, if the package has a corresponding battery blaming entry * in the Uid-based battery sipper list, this method returns a PreferenceScreen pointing to the * Uid battery blaming page. If the package doesn't have a battery sipper entry (typically * shouldn't happen), this method returns a PreferenceScreen pointing to the App Info page for * that package. */ private PreferenceScreen getScreenFromOps( PreferenceManager preferenceManager, long now, AppOpsManager.PackageOps ops, HashMap<String, Boolean> packageMap) { BatterySipperWrapper wrapper) { String packageName = ops.getPackageName(); List<AppOpsManager.OpEntry> entries = ops.getOps(); boolean highBattery = false; Loading @@ -193,9 +241,47 @@ public class RecentLocationApps { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, packageName + " hadn't used location within the time interval."); } return; return null; } // The package is fresh enough, continue. PreferenceScreen screen = null; if (wrapper != null) { // Contains sipper. Link to Battery Blaming page. // We're listing by UID rather than package. Check whether the entry has been used // before to prevent the same UID from showing up twice. if (!wrapper.used()) { BatterySipper sipper = wrapper.batterySipper(); sipper.loadNameAndIcon(); screen = createRecentLocationEntry( preferenceManager, sipper.getIcon(), sipper.getLabel(), highBattery, new UidEntryClickedListener(sipper)); wrapper.setUsed(); } } else { // No corresponding sipper. Link to App Info page. // This is grouped by package rather than UID, but that's OK because this branch // shouldn't happen in practice. try { ApplicationInfo appInfo = mPackageManager.getApplicationInfo( packageName, PackageManager.GET_META_DATA); screen = createRecentLocationEntry( preferenceManager, mPackageManager.getApplicationIcon(appInfo), mPackageManager.getApplicationLabel(appInfo), highBattery, new PackageEntryClickedListener(packageName)); } catch (PackageManager.NameNotFoundException e) { Log.wtf(TAG, "Package not found: " + packageName); } } packageMap.put(packageName, highBattery); return screen; } } Loading
res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -2377,6 +2377,8 @@ <string name="location_mode_location_off_title">Location off</string> <!-- [CHAR LIMIT=30] Location settings screen, sub category for recent location requests --> <string name="location_category_recent_location_requests">Recent location requests</string> <!-- [CHAR LIMIT=30] Location settings screen, displayed when there's no recent app accessing location --> <string name="location_no_recent_apps">No recent apps</string> <!-- [CHAR LIMIT=30] Location settings screen, sub category for location services --> <string name="location_category_location_services">Location services</string> <!-- [CHAR LIMIT=30] Location settings screen, recent location requests high battery use--> Loading
src/com/android/settings/fuelgauge/BatterySipper.java +8 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,14 @@ public class BatterySipper implements Comparable<BatterySipper> { return mPackages; } public int getUid() { // Bail out if the current sipper is not an App sipper. if (uidObj == null) { return 0; } return uidObj.getUid(); } void getQuickNameIconForUid(Uid uidObj) { final int uid = uidObj.getUid(); final String uidString = Integer.toString(uid); Loading
src/com/android/settings/location/RecentLocationApps.java +140 −54 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.app.AppOpsManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceActivity; Loading @@ -33,9 +34,11 @@ import com.android.settings.applications.InstalledAppDetails; import com.android.settings.fuelgauge.BatterySipper; import com.android.settings.fuelgauge.BatteryStatsHelper; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Retrieves the information of applications which accessed location recently. Loading Loading @@ -93,12 +96,69 @@ public class RecentLocationApps { } } private PreferenceScreen createRecentLocationEntry( PreferenceManager preferenceManager, Drawable icon, CharSequence label, boolean isHighBattery, Preference.OnPreferenceClickListener listener) { PreferenceScreen screen = preferenceManager.createPreferenceScreen(mActivity); screen.setIcon(icon); screen.setTitle(label); if (isHighBattery) { screen.setSummary(R.string.location_high_battery_use); } else { screen.setSummary(R.string.location_low_battery_use); } screen.setOnPreferenceClickListener(listener); return screen; } /** * Stores a BatterySipper object and records whether the sipper has been used. */ private static final class BatterySipperWrapper { private BatterySipper mSipper; private boolean mUsed; public BatterySipperWrapper(BatterySipper sipper) { mSipper = sipper; mUsed = false; } public BatterySipper batterySipper() { return mSipper; } public boolean used() { return mUsed; } public void setUsed() { mUsed = true; } } /** * Fills a list of applications which queried location recently within * specified time. */ public void fillAppList(PreferenceCategory container) { HashMap<String, Boolean> packageMap = new HashMap<String, Boolean>(); // Retrieve Uid-based battery blaming info and generate a package to BatterySipper HashMap // for later faster looking up. mStatsHelper.refreshStats(); List<BatterySipper> usageList = mStatsHelper.getUsageList(); // Key: package Uid. Value: BatterySipperWrapper. HashMap<Integer, BatterySipperWrapper> sipperMap = new HashMap<Integer, BatterySipperWrapper>(usageList.size()); for (BatterySipper sipper: usageList) { int uid = sipper.getUid(); if (uid != 0) { sipperMap.put(uid, new BatterySipperWrapper(sipper)); } } // Retrieve a location usage list from AppOps AppOpsManager aoManager = (AppOpsManager) mActivity.getSystemService(Context.APP_OPS_SERVICE); List<AppOpsManager.PackageOps> appOps = aoManager.getPackagesForOps( Loading @@ -107,68 +167,56 @@ public class RecentLocationApps { AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, }); PreferenceManager preferenceManager = container.getPreferenceManager(); // Process the AppOps list and generate a preference list. ArrayList<PreferenceScreen> prefs = new ArrayList<PreferenceScreen>(); long now = System.currentTimeMillis(); for (AppOpsManager.PackageOps ops : appOps) { processPackageOps(now, container, preferenceManager, ops, packageMap); BatterySipperWrapper wrapper = sipperMap.get(ops.getUid()); PreferenceScreen screen = getScreenFromOps(preferenceManager, now, ops, wrapper); if (screen != null) { prefs.add(screen); } mStatsHelper.refreshStats(); List<BatterySipper> usageList = mStatsHelper.getUsageList(); for (BatterySipper sipper : usageList) { sipper.loadNameAndIcon(); String[] packages = sipper.getPackages(); if (packages == null) { continue; } for (String curPackage : packages) { if (packageMap.containsKey(curPackage)) { PreferenceScreen screen = preferenceManager.createPreferenceScreen(mActivity); screen.setIcon(sipper.getIcon()); screen.setTitle(sipper.getLabel()); if (packageMap.get(curPackage)) { screen.setSummary(R.string.location_high_battery_use); } else { screen.setSummary(R.string.location_low_battery_use); } container.addPreference(screen); screen.setOnPreferenceClickListener(new UidEntryClickedListener(sipper)); packageMap.remove(curPackage); break; } if (prefs.size() > 0) { // If there's some items to display, sort the items and add them to the container. Collections.sort(prefs, new Comparator<PreferenceScreen>() { @Override public int compare(PreferenceScreen lhs, PreferenceScreen rhs) { return lhs.getTitle().toString().compareTo(rhs.getTitle().toString()); } }); for (PreferenceScreen entry : prefs) { container.addPreference(entry); } // Typically there shouldn't be any entry left in the HashMap. But if there are any, add // them to the list and link them to the app info page. for (Map.Entry<String, Boolean> entry : packageMap.entrySet()) { try { PreferenceScreen screen = preferenceManager.createPreferenceScreen(mActivity); ApplicationInfo appInfo = mPackageManager.getApplicationInfo( entry.getKey(), PackageManager.GET_META_DATA); screen.setIcon(mPackageManager.getApplicationIcon(appInfo)); screen.setTitle(mPackageManager.getApplicationLabel(appInfo)); // if used both high and low battery within the time interval, show as "high // battery" if (entry.getValue()) { screen.setSummary(R.string.location_high_battery_use); } else { screen.setSummary(R.string.location_low_battery_use); } screen.setOnPreferenceClickListener( new PackageEntryClickedListener(entry.getKey())); // If there's no item to display, add a "No recent apps" item. PreferenceScreen screen = preferenceManager.createPreferenceScreen(mActivity); screen.setTitle(R.string.location_no_recent_apps); screen.setSelectable(false); screen.setEnabled(false); container.addPreference(screen); } catch (PackageManager.NameNotFoundException e) { // ignore the current app and move on to the next. } } } private void processPackageOps( long now, PreferenceCategory container, /** * Creates a PreferenceScreen entry for the given PackageOps. * * This method examines the time interval of the PackageOps first. If the PackageOps is older * than the designated interval, this method ignores the PackageOps object and returns null. * * When the PackageOps is fresh enough, if the package has a corresponding battery blaming entry * in the Uid-based battery sipper list, this method returns a PreferenceScreen pointing to the * Uid battery blaming page. If the package doesn't have a battery sipper entry (typically * shouldn't happen), this method returns a PreferenceScreen pointing to the App Info page for * that package. */ private PreferenceScreen getScreenFromOps( PreferenceManager preferenceManager, long now, AppOpsManager.PackageOps ops, HashMap<String, Boolean> packageMap) { BatterySipperWrapper wrapper) { String packageName = ops.getPackageName(); List<AppOpsManager.OpEntry> entries = ops.getOps(); boolean highBattery = false; Loading @@ -193,9 +241,47 @@ public class RecentLocationApps { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, packageName + " hadn't used location within the time interval."); } return; return null; } // The package is fresh enough, continue. PreferenceScreen screen = null; if (wrapper != null) { // Contains sipper. Link to Battery Blaming page. // We're listing by UID rather than package. Check whether the entry has been used // before to prevent the same UID from showing up twice. if (!wrapper.used()) { BatterySipper sipper = wrapper.batterySipper(); sipper.loadNameAndIcon(); screen = createRecentLocationEntry( preferenceManager, sipper.getIcon(), sipper.getLabel(), highBattery, new UidEntryClickedListener(sipper)); wrapper.setUsed(); } } else { // No corresponding sipper. Link to App Info page. // This is grouped by package rather than UID, but that's OK because this branch // shouldn't happen in practice. try { ApplicationInfo appInfo = mPackageManager.getApplicationInfo( packageName, PackageManager.GET_META_DATA); screen = createRecentLocationEntry( preferenceManager, mPackageManager.getApplicationIcon(appInfo), mPackageManager.getApplicationLabel(appInfo), highBattery, new PackageEntryClickedListener(packageName)); } catch (PackageManager.NameNotFoundException e) { Log.wtf(TAG, "Package not found: " + packageName); } } packageMap.put(packageName, highBattery); return screen; } }