diff options
5 files changed, 138 insertions, 22 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 993e4dc..d7d7c2e 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2113,6 +2113,46 @@ public final class Settings { * @hide */ public static final String TTY_MODE_ENABLED = "tty_mode_enabled"; + + /** + * Helper method for determining if a location provider is enabled. + * @param cr the content resolver to use + * @param provider the location provider to query + * @return true if the provider is enabled + * + * @hide + */ + public static final boolean isLocationProviderEnabled(ContentResolver cr, String provider) { + String allowedProviders = Settings.Secure.getString(cr, LOCATION_PROVIDERS_ALLOWED); + if (allowedProviders != null) { + return (allowedProviders.equals(provider) || + allowedProviders.contains("," + provider + ",") || + allowedProviders.startsWith(provider + ",") || + allowedProviders.endsWith("," + provider)); + } + return false; + } + + /** + * Thread-safe method for enabling or disabling a single location provider. + * @param cr the content resolver to use + * @param provider the location provider to enable or disable + * @param enabled true if the provider should be enabled + * + * @hide + */ + public static final void setLocationProviderEnabled(ContentResolver cr, + String provider, boolean enabled) { + // to ensure thread safety, we write the provider name with a '+' or '-' + // and let the SettingsProvider handle it rather than reading and modifying + // the list of enabled providers. + if (enabled) { + provider = "+" + provider; + } else { + provider = "-" + provider; + } + putString(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider); + } } /** diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 69c404a..d0f9877 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -33,8 +33,6 @@ interface ILocationManager List getAllProviders(); List getProviders(boolean enabledOnly); - void updateProviders(); - void requestLocationUpdates(String provider, long minTime, float minDistance, in ILocationListener listener); void requestLocationUpdatesPI(String provider, long minTime, float minDistance, diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 022ee25..0c7254e 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -313,20 +313,6 @@ public class LocationManager { } /** - * Propagates the enabled/disabled state of the providers from the system - * settings to the providers themselves. - * - * {@hide} - */ - public void updateProviders() { - try { - mService.updateProviders(); - } catch (RemoteException ex) { - Log.e(TAG, "updateProviders: RemoteException", ex); - } - } - - /** * Returns the next looser power requirement, in the sequence: * * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 333a450..6f430c4 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -244,6 +244,72 @@ public class SettingsProvider extends ContentProvider { return values.length; } + /* + * Used to parse changes to the value of Settings.Secure.LOCATION_PROVIDERS_ALLOWED. + * This setting contains a list of the currently enabled location providers. + * But helper functions in android.providers.Settings can enable or disable + * a single provider by using a "+" or "-" prefix before the provider name. + */ + private boolean parseProviderList(Uri url, ContentValues initialValues) { + String value = initialValues.getAsString(Settings.Secure.VALUE); + String newProviders = null; + if (value != null && value.length() > 1) { + char prefix = value.charAt(0); + if (prefix == '+' || prefix == '-') { + // skip prefix + value = value.substring(1); + + // read list of enabled providers into "providers" + String providers = ""; + String[] columns = {Settings.Secure.VALUE}; + String where = Settings.Secure.NAME + "=\'" + Settings.Secure.LOCATION_PROVIDERS_ALLOWED + "\'"; + Cursor cursor = query(url, columns, where, null, null); + if (cursor != null && cursor.getCount() == 1) { + try { + cursor.moveToFirst(); + providers = cursor.getString(0); + } finally { + cursor.close(); + } + } + + int index = providers.indexOf(value); + int end = index + value.length(); + // check for commas to avoid matching on partial string + if (index > 0 && providers.charAt(index - 1) != ',') index = -1; + if (end < providers.length() && providers.charAt(end) != ',') index = -1; + + if (prefix == '+' && index < 0) { + // append the provider to the list if not present + if (providers.length() == 0) { + newProviders = value; + } else { + newProviders = providers + ',' + value; + } + } else if (prefix == '-' && index >= 0) { + // remove the provider from the list if present + // remove leading and trailing commas + if (index > 0) index--; + if (end < providers.length()) end++; + + newProviders = providers.substring(0, index); + if (end < providers.length()) { + newProviders += providers.substring(end); + } + } else { + // nothing changed, so no need to update the database + return false; + } + + if (newProviders != null) { + initialValues.put(Settings.Secure.VALUE, newProviders); + } + } + } + + return true; + } + @Override public Uri insert(Uri url, ContentValues initialValues) { SqlArguments args = new SqlArguments(url); @@ -252,6 +318,13 @@ public class SettingsProvider extends ContentProvider { } checkWritePermissions(args); + // Special case LOCATION_PROVIDERS_ALLOWED. + // Support enabling/disabling a single provider (using "+" or "-" prefix) + String name = initialValues.getAsString(Settings.Secure.NAME); + if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) { + if (!parseProviderList(url, initialValues)) return null; + } + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final long rowId = db.insert(args.table, null, initialValues); if (rowId <= 0) return null; diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index edee5f8..f3187d7 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -28,17 +28,21 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Observable; +import java.util.Observer; import java.util.Set; import java.util.regex.Pattern; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; +import android.content.ContentQueryMap; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.database.Cursor; import android.location.Address; import android.location.IGpsStatusListener; import android.location.ILocationListener; @@ -222,6 +226,9 @@ public class LocationManagerService extends ILocationManager.Stub private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; private boolean mWifiEnabled = false; + // for Settings change notification + private ContentQueryMap mSettings; + /** * A wrapper class holding either an ILocationListener or a PendingIntent to receive * location updates. @@ -345,6 +352,14 @@ public class LocationManagerService extends ILocationManager.Stub } } + private final class SettingsObserver implements Observer { + public void update(Observable o, Object arg) { + synchronized (mLocationListeners) { + updateProvidersLocked(); + } + } + } + private Location readLastKnownLocationLocked(String provider) { Location location = null; String s = null; @@ -593,6 +608,16 @@ public class LocationManagerService extends ILocationManager.Stub intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); context.registerReceiver(powerStateReceiver, intentFilter); + // listen for settings changes + ContentResolver resolver = mContext.getContentResolver(); + Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null, + "(" + Settings.System.NAME + "=?)", + new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, + null); + mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler); + SettingsObserver settingsObserver = new SettingsObserver(); + mSettings.addObserver(settingsObserver); + // Get the wifi manager mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); @@ -773,12 +798,6 @@ public class LocationManagerService extends ILocationManager.Stub return out; } - public void updateProviders() { - synchronized (mLocationListeners) { - updateProvidersLocked(); - } - } - private void updateProvidersLocked() { for (LocationProviderImpl p : LocationProviderImpl.getProviders()) { boolean isEnabled = p.isEnabled(); |