diff options
Diffstat (limited to 'src/com/android/settings/location')
4 files changed, 102 insertions, 68 deletions
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java index 815be41..6dceea9 100644 --- a/src/com/android/settings/location/LocationSettings.java +++ b/src/com/android/settings/location/LocationSettings.java @@ -55,7 +55,7 @@ public class LocationSettings extends LocationSettingsBase /** Key for preference category "Recent location requests" */ private static final String KEY_RECENT_LOCATION_REQUESTS = "recent_location_requests"; /** Key for preference category "Location services" */ - private static final String KEY_LOCATION_SERVICES = "location_services"; + private static final String KEY_APP_SETTINGS = "app_settings"; private Switch mSwitch; private boolean mValidListener; @@ -165,10 +165,10 @@ public class LocationSettings extends LocationSettingsBase categoryRecentLocationRequests.addPreference(banner); } - PreferenceCategory categoryLocationServices = - (PreferenceCategory) root.findPreference(KEY_LOCATION_SERVICES); + PreferenceCategory categoryAppSettings = + (PreferenceCategory) root.findPreference(KEY_APP_SETTINGS); final SettingsInjector injector = new SettingsInjector(activity); - List<Preference> locationServices = injector.getInjectedSettings(); + List<Preference> appSettings = injector.getInjectedSettings(); mReceiver = new BroadcastReceiver() { @Override @@ -182,11 +182,11 @@ public class LocationSettings extends LocationSettingsBase activity.registerReceiver(mReceiver, new IntentFilter(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED)); - if (locationServices.size() > 0) { - addPreferencesSorted(locationServices, categoryLocationServices); + if (appSettings.size() > 0) { + addPreferencesSorted(appSettings, categoryAppSettings); } else { // If there's no item to display, remove the whole category. - root.removePreference(categoryLocationServices); + root.removePreference(categoryAppSettings); } // Only show the master switch when we're not in multi-pane mode, and not being used as @@ -233,9 +233,12 @@ public class LocationSettings extends LocationSettingsBase break; } - boolean enabled = (mode != Settings.Secure.LOCATION_MODE_OFF) && !restricted; + // Restricted user can't change the location mode, so disable the master switch. But in some + // corner cases, the location might still be enabled. In such case the master switch should + // be disabled but checked. + boolean enabled = (mode != Settings.Secure.LOCATION_MODE_OFF); mSwitch.setEnabled(!restricted); - mLocationMode.setEnabled(enabled); + mLocationMode.setEnabled(enabled && !restricted); if (enabled != mSwitch.isChecked()) { // set listener to null so that that code below doesn't trigger onCheckedChanged() diff --git a/src/com/android/settings/location/LocationSettingsBase.java b/src/com/android/settings/location/LocationSettingsBase.java index 81e841a..9ceefe7 100644 --- a/src/com/android/settings/location/LocationSettingsBase.java +++ b/src/com/android/settings/location/LocationSettingsBase.java @@ -38,12 +38,29 @@ public abstract class LocationSettingsBase extends SettingsPreferenceFragment private static final int LOADER_ID_LOCATION_MODE = 1; + /** + * Whether the fragment is actively running. + */ + private boolean mActive = false; + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); getLoaderManager().initLoader(LOADER_ID_LOCATION_MODE, null, this); } + @Override + public void onResume() { + super.onResume(); + mActive = true; + } + + @Override + public void onPause() { + super.onPause(); + mActive = false; + } + /** Called when location mode has changed. */ public abstract void onModeChanged(int mode, boolean restricted); @@ -61,7 +78,9 @@ public abstract class LocationSettingsBase extends SettingsPreferenceFragment } mode = Settings.Secure.getInt(getContentResolver(), Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); - onModeChanged(mode, true); + if (mActive) { + onModeChanged(mode, true); + } return; } Settings.Secure.putInt(getContentResolver(), Settings.Secure.LOCATION_MODE, mode); @@ -69,9 +88,11 @@ public abstract class LocationSettingsBase extends SettingsPreferenceFragment } public void refreshLocationMode() { - int mode = Settings.Secure.getInt(getContentResolver(), Settings.Secure.LOCATION_MODE, - Settings.Secure.LOCATION_MODE_OFF); - onModeChanged(mode, isRestricted()); + if (mActive) { + int mode = Settings.Secure.getInt(getContentResolver(), Settings.Secure.LOCATION_MODE, + Settings.Secure.LOCATION_MODE_OFF); + onModeChanged(mode, isRestricted()); + } } @Override diff --git a/src/com/android/settings/location/RecentLocationApps.java b/src/com/android/settings/location/RecentLocationApps.java index 23e6dcf..1fa8aac 100644 --- a/src/com/android/settings/location/RecentLocationApps.java +++ b/src/com/android/settings/location/RecentLocationApps.java @@ -140,7 +140,7 @@ public class RecentLocationApps { public List<Preference> getAppList() { // Retrieve Uid-based battery blaming info and generate a package to BatterySipper HashMap // for later faster looking up. - mStatsHelper.refreshStats(); + mStatsHelper.refreshStats(true); List<BatterySipper> usageList = mStatsHelper.getUsageList(); // Key: package Uid. Value: BatterySipperWrapper. HashMap<Integer, BatterySipperWrapper> sipperMap = @@ -243,11 +243,22 @@ public class RecentLocationApps { try { ApplicationInfo appInfo = mPackageManager.getApplicationInfo( packageName, PackageManager.GET_META_DATA); - pref = createRecentLocationEntry( - mPackageManager.getApplicationIcon(appInfo), - mPackageManager.getApplicationLabel(appInfo), - highBattery, - new PackageEntryClickedListener(packageName)); + // Multiple users can install the same package. Each user gets a different Uid for + // the same package. + // + // Here we retrieve the Uid with package name, that will be the Uid for that package + // associated with the current active user. If the Uid differs from the Uid in ops, + // that means this entry belongs to another inactive user and we should ignore that. + if (appInfo.uid == ops.getUid()) { + pref = createRecentLocationEntry( + mPackageManager.getApplicationIcon(appInfo), + mPackageManager.getApplicationLabel(appInfo), + highBattery, + new PackageEntryClickedListener(packageName)); + } else if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "package " + packageName + " with Uid " + ops.getUid() + + " belongs to another inactive account, ignored."); + } } catch (PackageManager.NameNotFoundException e) { Log.wtf(TAG, "Package not found: " + packageName); } diff --git a/src/com/android/settings/location/SettingsInjector.java b/src/com/android/settings/location/SettingsInjector.java index 7bd190c..5929466 100644 --- a/src/com/android/settings/location/SettingsInjector.java +++ b/src/com/android/settings/location/SettingsInjector.java @@ -30,6 +30,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Messenger; +import android.os.SystemClock; import android.preference.Preference; import android.util.AttributeSet; import android.util.Log; @@ -42,7 +43,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -67,22 +67,6 @@ class SettingsInjector { private static final long INJECTED_STATUS_UPDATE_TIMEOUT_MILLIS = 1000; /** - * Intent action marking the receiver as injecting a setting - */ - public static final String RECEIVER_INTENT = "com.android.settings.InjectedLocationSetting"; - - /** - * Name of the meta-data tag used to specify the resource file that includes the settings - * attributes. - */ - public static final String META_DATA_NAME = "com.android.settings.InjectedLocationSetting"; - - /** - * Name of the XML tag that includes the attributes for the setting. - */ - public static final String ATTRIBUTES_NAME = "injected-location-setting"; - - /** * {@link Message#what} value for starting to load status values * in case we aren't already in the process of loading them. */ @@ -115,7 +99,8 @@ class SettingsInjector { /** * Returns a list with one {@link InjectedSetting} object for each {@link android.app.Service} - * that responds to {@link #RECEIVER_INTENT} and provides the expected setting metadata. + * that responds to {@link SettingInjectorService#ACTION_SERVICE_INTENT} and provides the + * expected setting metadata. * * Duplicates some code from {@link android.content.pm.RegisteredServicesCache}. * @@ -123,37 +108,38 @@ class SettingsInjector { */ private List<InjectedSetting> getSettings() { PackageManager pm = mContext.getPackageManager(); - Intent receiverIntent = new Intent(RECEIVER_INTENT); + Intent intent = new Intent(SettingInjectorService.ACTION_SERVICE_INTENT); List<ResolveInfo> resolveInfos = - pm.queryIntentServices(receiverIntent, PackageManager.GET_META_DATA); + pm.queryIntentServices(intent, PackageManager.GET_META_DATA); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Found services: " + resolveInfos); } List<InjectedSetting> settings = new ArrayList<InjectedSetting>(resolveInfos.size()); - for (ResolveInfo receiver : resolveInfos) { + for (ResolveInfo resolveInfo : resolveInfos) { try { - InjectedSetting info = parseServiceInfo(receiver, pm); - if (info == null) { - Log.w(TAG, "Unable to load service info " + receiver); + InjectedSetting setting = parseServiceInfo(resolveInfo, pm); + if (setting == null) { + Log.w(TAG, "Unable to load service info " + resolveInfo); } else { - if (Log.isLoggable(TAG, Log.INFO)) { - Log.i(TAG, "Loaded service info: " + info); - } - settings.add(info); + settings.add(setting); } } catch (XmlPullParserException e) { - Log.w(TAG, "Unable to load service info " + receiver, e); + Log.w(TAG, "Unable to load service info " + resolveInfo, e); } catch (IOException e) { - Log.w(TAG, "Unable to load service info " + receiver, e); + Log.w(TAG, "Unable to load service info " + resolveInfo, e); } } + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Loaded settings: " + settings); + } return settings; } /** - * Parses {@link InjectedSetting} from the attributes of the {@link #META_DATA_NAME} tag. + * Parses {@link InjectedSetting} from the attributes of the + * {@link SettingInjectorService#META_DATA_NAME} tag. * * Duplicates some code from {@link android.content.pm.RegisteredServicesCache}. */ @@ -164,9 +150,9 @@ class SettingsInjector { XmlResourceParser parser = null; try { - parser = si.loadXmlMetaData(pm, META_DATA_NAME); + parser = si.loadXmlMetaData(pm, SettingInjectorService.META_DATA_NAME); if (parser == null) { - throw new XmlPullParserException("No " + META_DATA_NAME + throw new XmlPullParserException("No " + SettingInjectorService.META_DATA_NAME + " meta-data for " + service + ": " + si); } @@ -178,9 +164,9 @@ class SettingsInjector { } String nodeName = parser.getName(); - if (!ATTRIBUTES_NAME.equals(nodeName)) { + if (!SettingInjectorService.ATTRIBUTES_NAME.equals(nodeName)) { throw new XmlPullParserException("Meta-data does not start with " - + ATTRIBUTES_NAME + " tag"); + + SettingInjectorService.ATTRIBUTES_NAME + " tag"); } Resources res = pm.getResourcesForApplication(si.applicationInfo); @@ -201,15 +187,15 @@ class SettingsInjector { private static InjectedSetting parseAttributes( String packageName, String className, Resources res, AttributeSet attrs) { - TypedArray sa = res.obtainAttributes(attrs, android.R.styleable.InjectedLocationSetting); + TypedArray sa = res.obtainAttributes(attrs, android.R.styleable.SettingInjectorService); try { // Note that to help guard against malicious string injection, we do not allow dynamic // specification of the label (setting title) - final String label = sa.getString(android.R.styleable.InjectedLocationSetting_label); + final String label = sa.getString(android.R.styleable.SettingInjectorService_title); final int iconId = sa.getResourceId( - android.R.styleable.InjectedLocationSetting_icon, 0); + android.R.styleable.SettingInjectorService_icon, 0); final String settingsActivity = - sa.getString(android.R.styleable.InjectedLocationSetting_settingsActivity); + sa.getString(android.R.styleable.SettingInjectorService_settingsActivity); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "parsed label: " + label + ", iconId: " + iconId + ", settingsActivity: " + settingsActivity); @@ -306,6 +292,7 @@ class SettingsInjector { break; case WHAT_RECEIVED_STATUS: final Setting receivedSetting = (Setting) msg.obj; + receivedSetting.maybeLogElapsedTime(); mSettingsBeingLoaded.remove(receivedSetting); mTimedOutSettings.remove(receivedSetting); removeMessages(WHAT_TIMEOUT, receivedSetting); @@ -357,8 +344,7 @@ class SettingsInjector { iter.remove(); // Request the status value - Intent intent = setting.createUpdatingIntent(); - mContext.startService(intent); + setting.startService(); mSettingsBeingLoaded.add(setting); // Ensure that if receiving the status value takes too long, we start loading the @@ -390,6 +376,7 @@ class SettingsInjector { public final InjectedSetting setting; public final Preference preference; + public long startMillis; private Setting(InjectedSetting setting, Preference preference) { this.setting = setting; @@ -406,7 +393,7 @@ class SettingsInjector { /** * Returns true if they both have the same {@link #setting} value. Ignores mutable - * preference so that it's safe to use in sets. + * {@link #preference} and {@link #startMillis} so that it's safe to use in sets. */ @Override public boolean equals(Object o) { @@ -419,11 +406,10 @@ class SettingsInjector { } /** - * Creates an Intent to ask the receiver for the current status for the setting, and display - * it when it replies. + * Starts the service to fetch for the current status for the setting, and updates the + * preference when the service replies. */ - public Intent createUpdatingIntent() { - final Intent receiverIntent = setting.getServiceIntent(); + public void startService() { Handler handler = new Handler() { @Override public void handleMessage(Message msg) { @@ -440,12 +426,25 @@ class SettingsInjector { } }; Messenger messenger = new Messenger(handler); - receiverIntent.putExtra(SettingInjectorService.MESSENGER_KEY, messenger); + + Intent intent = setting.getServiceIntent(); + intent.putExtra(SettingInjectorService.MESSENGER_KEY, messenger); + if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, setting + ": sending rcv-intent: " + receiverIntent + Log.d(TAG, setting + ": sending update intent: " + intent + ", handler: " + handler); + startMillis = SystemClock.elapsedRealtime(); + } else { + startMillis = 0; + } + mContext.startService(intent); + } + + public void maybeLogElapsedTime() { + if (Log.isLoggable(TAG, Log.DEBUG) && startMillis != 0) { + long end = SystemClock.elapsedRealtime(); + Log.d(TAG, this + " update took " + (end - startMillis) + " millis"); } - return receiverIntent; } } } |