Sort "Location services" alphabetically
* Sort "Location services" items by title * Throttle the rate of loading status messages Change-Id: Iecb039a4ab94a810e11ef3e426e4a4b5c8c75c37
This commit is contained in:
@@ -23,6 +23,8 @@ import android.os.Bundle;
|
|||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
import android.preference.PreferenceCategory;
|
import android.preference.PreferenceCategory;
|
||||||
|
import android.preference.PreferenceGroup;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
@@ -32,6 +34,10 @@ import android.widget.Switch;
|
|||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.fuelgauge.BatteryStatsHelper;
|
import com.android.settings.fuelgauge.BatteryStatsHelper;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Location access settings.
|
* Location access settings.
|
||||||
*/
|
*/
|
||||||
@@ -97,7 +103,21 @@ public class LocationSettings extends LocationSettingsBase
|
|||||||
mStatsHelper.destroy();
|
mStatsHelper.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addPreferencesSorted(List<Preference> prefs, PreferenceGroup container) {
|
||||||
|
// If there's some items to display, sort the items and add them to the container.
|
||||||
|
Collections.sort(prefs, new Comparator<Preference>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Preference lhs, Preference rhs) {
|
||||||
|
return lhs.getTitle().toString().compareTo(rhs.getTitle().toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (Preference entry : prefs) {
|
||||||
|
container.addPreference(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private PreferenceScreen createPreferenceHierarchy() {
|
private PreferenceScreen createPreferenceHierarchy() {
|
||||||
|
final PreferenceActivity activity = (PreferenceActivity) getActivity();
|
||||||
PreferenceScreen root = getPreferenceScreen();
|
PreferenceScreen root = getPreferenceScreen();
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
root.removeAll();
|
root.removeAll();
|
||||||
@@ -110,7 +130,6 @@ public class LocationSettings extends LocationSettingsBase
|
|||||||
new Preference.OnPreferenceClickListener() {
|
new Preference.OnPreferenceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
PreferenceActivity activity = (PreferenceActivity) getActivity();
|
|
||||||
activity.startPreferencePanel(
|
activity.startPreferencePanel(
|
||||||
LocationMode.class.getName(), null,
|
LocationMode.class.getName(), null,
|
||||||
R.string.location_mode_screen_title, null, LocationSettings.this,
|
R.string.location_mode_screen_title, null, LocationSettings.this,
|
||||||
@@ -118,15 +137,28 @@ public class LocationSettings extends LocationSettingsBase
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final PreferenceManager preferenceManager = getPreferenceManager();
|
||||||
|
|
||||||
mRecentLocationRequests =
|
mRecentLocationRequests =
|
||||||
(PreferenceCategory) root.findPreference(KEY_RECENT_LOCATION_REQUESTS);
|
(PreferenceCategory) root.findPreference(KEY_RECENT_LOCATION_REQUESTS);
|
||||||
mLocationServices = (PreferenceCategory) root.findPreference(KEY_LOCATION_SERVICES);
|
|
||||||
|
|
||||||
PreferenceActivity activity = (PreferenceActivity) getActivity();
|
|
||||||
RecentLocationApps recentApps = new RecentLocationApps(activity, mStatsHelper);
|
RecentLocationApps recentApps = new RecentLocationApps(activity, mStatsHelper);
|
||||||
recentApps.fillAppList(mRecentLocationRequests);
|
List<Preference> recentLocationRequests = recentApps.getAppList(preferenceManager);
|
||||||
|
if (recentLocationRequests.size() > 0) {
|
||||||
|
addPreferencesSorted(recentLocationRequests, mRecentLocationRequests);
|
||||||
|
} else {
|
||||||
|
// If there's no item to display, add a "No recent apps" item.
|
||||||
|
PreferenceScreen screen = preferenceManager.createPreferenceScreen(activity);
|
||||||
|
screen.setTitle(R.string.location_no_recent_apps);
|
||||||
|
screen.setSelectable(false);
|
||||||
|
screen.setEnabled(false);
|
||||||
|
mRecentLocationRequests.addPreference(screen);
|
||||||
|
}
|
||||||
|
|
||||||
SettingsInjector.addInjectedSettings(mLocationServices, activity, getPreferenceManager());
|
mLocationServices = (PreferenceCategory) root.findPreference(KEY_LOCATION_SERVICES);
|
||||||
|
List<Preference> locationServices = SettingsInjector.getInjectedSettings(
|
||||||
|
activity, preferenceManager);
|
||||||
|
addPreferencesSorted(locationServices, mLocationServices);
|
||||||
|
|
||||||
// Only show the master switch when we're not in multi-pane mode, and not being used as
|
// Only show the master switch when we're not in multi-pane mode, and not being used as
|
||||||
// Setup Wizard.
|
// Setup Wizard.
|
||||||
@@ -174,7 +206,6 @@ public class LocationSettings extends LocationSettingsBase
|
|||||||
|
|
||||||
boolean enabled = (mode != Settings.Secure.LOCATION_MODE_OFF);
|
boolean enabled = (mode != Settings.Secure.LOCATION_MODE_OFF);
|
||||||
mLocationMode.setEnabled(enabled);
|
mLocationMode.setEnabled(enabled);
|
||||||
mRecentLocationRequests.setEnabled(enabled);
|
|
||||||
mLocationServices.setEnabled(enabled);
|
mLocationServices.setEnabled(enabled);
|
||||||
|
|
||||||
if (enabled != mSwitch.isChecked()) {
|
if (enabled != mSwitch.isChecked()) {
|
||||||
|
@@ -24,7 +24,6 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
import android.preference.PreferenceCategory;
|
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -35,8 +34,6 @@ import com.android.settings.fuelgauge.BatterySipper;
|
|||||||
import com.android.settings.fuelgauge.BatteryStatsHelper;
|
import com.android.settings.fuelgauge.BatteryStatsHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -143,7 +140,7 @@ public class RecentLocationApps {
|
|||||||
* Fills a list of applications which queried location recently within
|
* Fills a list of applications which queried location recently within
|
||||||
* specified time.
|
* specified time.
|
||||||
*/
|
*/
|
||||||
public void fillAppList(PreferenceCategory container) {
|
public List<Preference> getAppList(PreferenceManager preferenceManager) {
|
||||||
// Retrieve Uid-based battery blaming info and generate a package to BatterySipper HashMap
|
// Retrieve Uid-based battery blaming info and generate a package to BatterySipper HashMap
|
||||||
// for later faster looking up.
|
// for later faster looking up.
|
||||||
mStatsHelper.refreshStats();
|
mStatsHelper.refreshStats();
|
||||||
@@ -166,10 +163,9 @@ public class RecentLocationApps {
|
|||||||
AppOpsManager.OP_MONITOR_LOCATION,
|
AppOpsManager.OP_MONITOR_LOCATION,
|
||||||
AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION,
|
AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION,
|
||||||
});
|
});
|
||||||
PreferenceManager preferenceManager = container.getPreferenceManager();
|
|
||||||
|
|
||||||
// Process the AppOps list and generate a preference list.
|
// Process the AppOps list and generate a preference list.
|
||||||
ArrayList<PreferenceScreen> prefs = new ArrayList<PreferenceScreen>();
|
ArrayList<Preference> prefs = new ArrayList<Preference>();
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
for (AppOpsManager.PackageOps ops : appOps) {
|
for (AppOpsManager.PackageOps ops : appOps) {
|
||||||
BatterySipperWrapper wrapper = sipperMap.get(ops.getUid());
|
BatterySipperWrapper wrapper = sipperMap.get(ops.getUid());
|
||||||
@@ -179,25 +175,7 @@ public class RecentLocationApps {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefs.size() > 0) {
|
return prefs;
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.android.settings.location;
|
package com.android.settings.location;
|
||||||
|
|
||||||
import android.R;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
@@ -32,7 +31,6 @@ import android.os.Handler;
|
|||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceGroup;
|
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -42,6 +40,8 @@ import android.util.Xml;
|
|||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -61,9 +61,10 @@ import java.util.List;
|
|||||||
* {@link SettingInjectorService#UPDATE_INTENT}.
|
* {@link SettingInjectorService#UPDATE_INTENT}.
|
||||||
*/
|
*/
|
||||||
class SettingsInjector {
|
class SettingsInjector {
|
||||||
|
|
||||||
private static final String TAG = "SettingsInjector";
|
private static final String TAG = "SettingsInjector";
|
||||||
|
|
||||||
|
private static final long INJECTED_STATUS_UPDATE_TIMEOUT_MILLIS = 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intent action marking the receiver as injecting a setting
|
* Intent action marking the receiver as injecting a setting
|
||||||
*/
|
*/
|
||||||
@@ -86,8 +87,6 @@ class SettingsInjector {
|
|||||||
*
|
*
|
||||||
* Duplicates some code from {@link android.content.pm.RegisteredServicesCache}.
|
* Duplicates some code from {@link android.content.pm.RegisteredServicesCache}.
|
||||||
*
|
*
|
||||||
* TODO: sort alphabetically
|
|
||||||
*
|
|
||||||
* TODO: unit test
|
* TODO: unit test
|
||||||
*/
|
*/
|
||||||
public static List<InjectedSetting> getSettings(Context context) {
|
public static List<InjectedSetting> getSettings(Context context) {
|
||||||
@@ -167,15 +166,17 @@ class SettingsInjector {
|
|||||||
private static InjectedSetting parseAttributes(
|
private static InjectedSetting parseAttributes(
|
||||||
String packageName, String className, Resources res, AttributeSet attrs) {
|
String packageName, String className, Resources res, AttributeSet attrs) {
|
||||||
|
|
||||||
TypedArray sa = res.obtainAttributes(attrs, R.styleable.InjectedLocationSetting);
|
TypedArray sa = res.obtainAttributes(attrs, android.R.styleable.InjectedLocationSetting);
|
||||||
try {
|
try {
|
||||||
// Note that to help guard against malicious string injection, we do not allow dynamic
|
// Note that to help guard against malicious string injection, we do not allow dynamic
|
||||||
// specification of the label (setting title)
|
// specification of the label (setting title)
|
||||||
final int labelId = sa.getResourceId(R.styleable.InjectedLocationSetting_label, 0);
|
final int labelId = sa.getResourceId(
|
||||||
final String label = sa.getString(R.styleable.InjectedLocationSetting_label);
|
android.R.styleable.InjectedLocationSetting_label, 0);
|
||||||
final int iconId = sa.getResourceId(R.styleable.InjectedLocationSetting_icon, 0);
|
final String label = sa.getString(android.R.styleable.InjectedLocationSetting_label);
|
||||||
|
final int iconId = sa.getResourceId(
|
||||||
|
android.R.styleable.InjectedLocationSetting_icon, 0);
|
||||||
final String settingsActivity =
|
final String settingsActivity =
|
||||||
sa.getString(R.styleable.InjectedLocationSetting_settingsActivity);
|
sa.getString(android.R.styleable.InjectedLocationSetting_settingsActivity);
|
||||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||||
Log.d(TAG, "parsed labelId: " + labelId + ", label: " + label
|
Log.d(TAG, "parsed labelId: " + labelId + ", label: " + label
|
||||||
+ ", iconId: " + iconId);
|
+ ", iconId: " + iconId);
|
||||||
@@ -190,32 +191,84 @@ class SettingsInjector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class StatusLoader {
|
||||||
|
private final Context mContext;
|
||||||
|
private final Intent mIntent;
|
||||||
|
private final StatusLoader mPrev;
|
||||||
|
|
||||||
|
private boolean mLoaded = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a loader and chains with the previous loader.
|
||||||
|
*/
|
||||||
|
public StatusLoader(Context context, Intent intent, StatusLoader prev) {
|
||||||
|
mContext = context;
|
||||||
|
mIntent = intent;
|
||||||
|
mPrev = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the current message hasn't been loaded, loads the status messages
|
||||||
|
* and set time out for the next message.
|
||||||
|
*/
|
||||||
|
public void loadIfNotLoaded() {
|
||||||
|
if (mLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mContext.startService(mIntent);
|
||||||
|
if (mPrev != null) {
|
||||||
|
Handler handler = new Handler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
// Continue with the next item in the chain.
|
||||||
|
mPrev.loadIfNotLoaded();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Ensure that we start loading the previous setting in the chain if the current
|
||||||
|
// setting hasn't loaded before the timeout
|
||||||
|
handler.sendMessageDelayed(
|
||||||
|
Message.obtain(handler), INJECTED_STATUS_UPDATE_TIMEOUT_MILLIS);
|
||||||
|
}
|
||||||
|
mLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add settings that other apps have injected.
|
* Gets a list of preferences that other apps have injected.
|
||||||
|
*
|
||||||
|
* TODO: extract InjectedLocationSettingGetter that returns an iterable over
|
||||||
|
* InjectedSetting objects, so that this class can focus on UI
|
||||||
*/
|
*/
|
||||||
public static void addInjectedSettings(PreferenceGroup group, Context context,
|
public static List<Preference> getInjectedSettings(Context context,
|
||||||
PreferenceManager preferenceManager) {
|
PreferenceManager preferenceManager) {
|
||||||
|
|
||||||
Iterable<InjectedSetting> settings = getSettings(context);
|
Iterable<InjectedSetting> settings = getSettings(context);
|
||||||
|
ArrayList<Preference> prefs = new ArrayList<Preference>();
|
||||||
|
StatusLoader loader = null;
|
||||||
for (InjectedSetting setting : settings) {
|
for (InjectedSetting setting : settings) {
|
||||||
Preference pref = addServiceSetting(context, group, setting, preferenceManager);
|
Preference pref = addServiceSetting(context, prefs, setting, preferenceManager);
|
||||||
|
Intent intent = createUpdatingIntent(context, pref, setting, loader);
|
||||||
// TODO: to prevent churn from multiple live broadcast receivers, don't trigger
|
loader = new StatusLoader(context, intent, loader);
|
||||||
// the next update until the sooner of: the current update completes or 1-2 seconds
|
|
||||||
// after the current update was started.
|
|
||||||
updateSetting(context, pref, setting);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start a thread to load each list item status.
|
||||||
|
if (loader != null) {
|
||||||
|
loader.loadIfNotLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an injected setting to the root with status "Loading...".
|
* Adds an injected setting to the root with status "Loading...".
|
||||||
*/
|
*/
|
||||||
private static PreferenceScreen addServiceSetting(Context context,
|
private static PreferenceScreen addServiceSetting(Context context,
|
||||||
PreferenceGroup group, InjectedSetting info, PreferenceManager preferenceManager) {
|
List<Preference> prefs, InjectedSetting info, PreferenceManager preferenceManager) {
|
||||||
|
|
||||||
PreferenceScreen screen = preferenceManager.createPreferenceScreen(context);
|
PreferenceScreen screen = preferenceManager.createPreferenceScreen(context);
|
||||||
screen.setTitle(info.title);
|
screen.setTitle(info.title);
|
||||||
screen.setSummary("Loading...");
|
screen.setSummary(R.string.location_loading_injected_setting);
|
||||||
PackageManager pm = context.getPackageManager();
|
PackageManager pm = context.getPackageManager();
|
||||||
Drawable icon = pm.getDrawable(info.packageName, info.iconId, null);
|
Drawable icon = pm.getDrawable(info.packageName, info.iconId, null);
|
||||||
screen.setIcon(icon);
|
screen.setIcon(icon);
|
||||||
@@ -224,15 +277,17 @@ class SettingsInjector {
|
|||||||
settingIntent.setClassName(info.packageName, info.settingsActivity);
|
settingIntent.setClassName(info.packageName, info.settingsActivity);
|
||||||
screen.setIntent(settingIntent);
|
screen.setIntent(settingIntent);
|
||||||
|
|
||||||
group.addPreference(screen);
|
prefs.add(screen);
|
||||||
return screen;
|
return screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ask the receiver for the current status for the setting, and display it when it replies.
|
* Creates an Intent to ask the receiver for the current status for the setting, and display it
|
||||||
|
* when it replies.
|
||||||
*/
|
*/
|
||||||
private static void updateSetting(Context context,
|
private static Intent createUpdatingIntent(Context context,
|
||||||
final Preference pref, final InjectedSetting info) {
|
final Preference pref, final InjectedSetting info, final StatusLoader prev) {
|
||||||
|
final Intent receiverIntent = info.getServiceIntent();
|
||||||
Handler handler = new Handler() {
|
Handler handler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
@@ -244,14 +299,16 @@ class SettingsInjector {
|
|||||||
}
|
}
|
||||||
pref.setSummary(status);
|
pref.setSummary(status);
|
||||||
pref.setEnabled(enabled);
|
pref.setEnabled(enabled);
|
||||||
|
if (prev != null) {
|
||||||
|
prev.loadIfNotLoaded();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Messenger messenger = new Messenger(handler);
|
Messenger messenger = new Messenger(handler);
|
||||||
Intent receiverIntent = info.getServiceIntent();
|
|
||||||
receiverIntent.putExtra(SettingInjectorService.MESSENGER_KEY, messenger);
|
receiverIntent.putExtra(SettingInjectorService.MESSENGER_KEY, messenger);
|
||||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||||
Log.d(TAG, info + ": sending rcv-intent: " + receiverIntent + ", handler: " + handler);
|
Log.d(TAG, info + ": sending rcv-intent: " + receiverIntent + ", handler: " + handler);
|
||||||
}
|
}
|
||||||
context.startService(receiverIntent);
|
return receiverIntent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user