Merge "Fixes for pin-restricted settings." into klp-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5fb7fe2..1cc6bfc 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4659,7 +4659,7 @@
<string name="global_font_change_title">Change font size</string>
<!-- NFC payment settings --><skip/>
- <string name="nfc_payment_settings_title">Tap and Pay</string>
+ <string name="nfc_payment_settings_title">Payments</string>
<!-- Option to tell Android to ask the user which payment app to use every time
a payment terminal is tapped -->
<string name="nfc_payment_ask">Ask every time</string>
diff --git a/src/com/android/settings/WirelessSettings.java b/src/com/android/settings/WirelessSettings.java
index 81c1794..ee4f018 100644
--- a/src/com/android/settings/WirelessSettings.java
+++ b/src/com/android/settings/WirelessSettings.java
@@ -28,7 +28,6 @@
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import android.net.Uri;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.os.SystemProperties;
@@ -104,21 +103,22 @@
}
private String mManageMobilePlanMessage;
-
+ private static final String MOBILE_PROVISIONING_ACTION
+ = "com.android.server.connectivityservice.MOBILE_PROVISIONING_ACTION";
public void onManageMobilePlanClick() {
log("onManageMobilePlanClick:");
mManageMobilePlanMessage = null;
Resources resources = getActivity().getResources();
- NetworkInfo ni = mCm.getActiveNetworkInfo();
+ NetworkInfo ni = mCm.getProvisioningOrActiveNetworkInfo();
if (mTm.hasIccCard() && (ni != null)) {
// Get provisioning URL
String url = mCm.getMobileProvisioningUrl();
if (!TextUtils.isEmpty(url)) {
- // Send user to provisioning webpage
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- startActivity(intent);
+ Intent intent = new Intent(MOBILE_PROVISIONING_ACTION);
+ intent.putExtra("EXTRA_URL", url);
+ Context context = getActivity().getBaseContext();
+ context.sendBroadcast(intent);
mManageMobilePlanMessage = null;
} else {
// No provisioning URL
diff --git a/src/com/android/settings/location/LocationSettingsBase.java b/src/com/android/settings/location/LocationSettingsBase.java
index 630e1e4..81e841a 100644
--- a/src/com/android/settings/location/LocationSettingsBase.java
+++ b/src/com/android/settings/location/LocationSettingsBase.java
@@ -16,58 +16,32 @@
package com.android.settings.location;
-import android.content.ContentQueryMap;
+import android.app.LoaderManager.LoaderCallbacks;
import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Loader;
import android.database.Cursor;
+import android.os.Bundle;
import android.os.UserManager;
import android.provider.Settings;
+import android.util.Log;
import com.android.settings.SettingsPreferenceFragment;
-import java.util.Observable;
-import java.util.Observer;
-
/**
* A base class that listens to location settings change and modifies location
* settings.
*/
-public abstract class LocationSettingsBase extends SettingsPreferenceFragment {
- private ContentQueryMap mContentQueryMap;
- private Observer mSettingsObserver;
+public abstract class LocationSettingsBase extends SettingsPreferenceFragment
+ implements LoaderCallbacks<Cursor> {
+ private static final String TAG = "LocationSettingsBase";
+
+ private static final int LOADER_ID_LOCATION_MODE = 1;
@Override
- public void onStart() {
- super.onStart();
- // listen for Location Manager settings changes
- Cursor settingsCursor = getContentResolver().query(Settings.Secure.CONTENT_URI, null,
- "(" + Settings.System.NAME + "=?)",
- new String[] { Settings.Secure.LOCATION_PROVIDERS_ALLOWED },
- null);
- mContentQueryMap = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, null);
- mSettingsObserver = new Observer() {
- @Override
- public void update(Observable o, Object arg) {
- refreshLocationMode();
- }
- };
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mContentQueryMap.addObserver(mSettingsObserver);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- mContentQueryMap.deleteObserver(mSettingsObserver);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- mContentQueryMap.close();
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ getLoaderManager().initLoader(LOADER_ID_LOCATION_MODE, null, this);
}
/** Called when location mode has changed. */
@@ -82,6 +56,9 @@
if (isRestricted()) {
// Location toggling disabled by user restriction. Read the current location mode to
// update the location master switch.
+ if (Log.isLoggable(TAG, Log.INFO)) {
+ Log.i(TAG, "Restricted user, not setting location mode");
+ }
mode = Settings.Secure.getInt(getContentResolver(), Settings.Secure.LOCATION_MODE,
Settings.Secure.LOCATION_MODE_OFF);
onModeChanged(mode, true);
@@ -96,4 +73,26 @@
Settings.Secure.LOCATION_MODE_OFF);
onModeChanged(mode, isRestricted());
}
+
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ switch (id) {
+ case LOADER_ID_LOCATION_MODE:
+ return new CursorLoader(getActivity(), Settings.Secure.CONTENT_URI, null,
+ "(" + Settings.System.NAME + "=?)",
+ new String[] { Settings.Secure.LOCATION_MODE }, null);
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ refreshLocationMode();
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ // Nothing to do here.
+ }
}
diff --git a/src/com/android/settings/location/SettingsInjector.java b/src/com/android/settings/location/SettingsInjector.java
index 22e2413..7bd190c 100644
--- a/src/com/android/settings/location/SettingsInjector.java
+++ b/src/com/android/settings/location/SettingsInjector.java
@@ -60,6 +60,10 @@
class SettingsInjector {
static final String TAG = "SettingsInjector";
+ /**
+ * If reading the status of a setting takes longer than this, we go ahead and start reading
+ * the next setting.
+ */
private static final long INJECTED_STATUS_UPDATE_TIMEOUT_MILLIS = 1000;
/**
@@ -219,9 +223,6 @@
/**
* 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 List<Preference> getInjectedSettings() {
Iterable<InjectedSetting> settings = getSettings();
@@ -273,62 +274,83 @@
private final class StatusLoadingHandler extends Handler {
/**
- * Settings whose status values need to be loaded. A set is used to prevent redundant loads
- * even if {@link #reloadStatusMessages()} is called many times in rapid succession (for
- * example, if we receive a lot of {@link
- * android.location.SettingInjectorService#ACTION_INJECTED_SETTING_CHANGED} broadcasts).
- * <p/>
- * We use a linked hash set to ensure that when {@link #reloadStatusMessages()} is called,
- * any settings that haven't been loaded yet will finish loading before any already-loaded
- * messages are loaded again.
+ * Settings whose status values need to be loaded. A set is used to prevent redundant loads.
*/
- private LinkedHashSet<Setting> mSettingsToLoad = new LinkedHashSet<Setting>();
+ private Set<Setting> mSettingsToLoad = new HashSet<Setting>();
/**
- * Whether we're in the middle of loading settings.
+ * Settings that are being loaded now and haven't timed out. In practice this should have
+ * zero or one elements.
*/
- private boolean mLoading;
+ private Set<Setting> mSettingsBeingLoaded = new HashSet<Setting>();
+
+ /**
+ * Settings that are being loaded but have timed out. If only one setting has timed out, we
+ * will go ahead and start loading the next setting so that one slow load won't delay the
+ * load of the other settings.
+ */
+ private Set<Setting> mTimedOutSettings = new HashSet<Setting>();
+
+ private boolean mReloadRequested;
@Override
public void handleMessage(Message msg) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "handleMessage start: " + msg + ", mSettingsToLoad: " + mSettingsToLoad);
+ Log.d(TAG, "handleMessage start: " + msg + ", " + this);
}
+ // Update state in response to message
switch (msg.what) {
case WHAT_RELOAD:
- mSettingsToLoad.addAll(mSettings);
- if (mLoading) {
- // Already waiting for a service to return its status, don't ask a new one
- return;
- }
- mLoading = true;
- break;
- case WHAT_TIMEOUT:
- if (Log.isLoggable(TAG, Log.WARN)) {
- final Setting setting = (Setting) msg.obj;
- setting.timedOut = true;
- Log.w(TAG, "Timed out trying to get status for: " + setting);
- }
+ mReloadRequested = true;
break;
case WHAT_RECEIVED_STATUS:
- final Setting setting = (Setting) msg.obj;
- if (setting.timedOut) {
- // We've already restarted retrieving the next setting, don't start another
- return;
+ final Setting receivedSetting = (Setting) msg.obj;
+ mSettingsBeingLoaded.remove(receivedSetting);
+ mTimedOutSettings.remove(receivedSetting);
+ removeMessages(WHAT_TIMEOUT, receivedSetting);
+ break;
+ case WHAT_TIMEOUT:
+ final Setting timedOutSetting = (Setting) msg.obj;
+ mSettingsBeingLoaded.remove(timedOutSetting);
+ mTimedOutSettings.add(timedOutSetting);
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Timed out trying to get status for: " + timedOutSetting);
}
-
- // Received the setting without timeout, clear any previous timed out status
- setting.timedOut = false;
break;
default:
- throw new IllegalArgumentException("Unexpected what: " + msg);
+ Log.wtf(TAG, "Unexpected what: " + msg);
+ }
+
+ // Decide whether to load additional settings based on the new state. Start by seeing
+ // if we have headroom to load another setting.
+ if (mSettingsBeingLoaded.size() > 0 || mTimedOutSettings.size() > 1) {
+ // Don't load any more settings until one of the pending settings has completed.
+ // To reduce memory pressure, we want to be loading at most one setting (plus at
+ // most one timed-out setting) at a time. This means we'll be responsible for
+ // bringing in at most two services.
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "too many services already live for " + msg + ", " + this);
+ }
+ return;
+ }
+
+ if (mReloadRequested && mSettingsToLoad.isEmpty() && mSettingsBeingLoaded.isEmpty()
+ && mTimedOutSettings.isEmpty()) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "reloading because idle and reload requesteed " + msg + ", " + this);
+ }
+ // Reload requested, so must reload all settings
+ mSettingsToLoad.addAll(mSettings);
+ mReloadRequested = false;
}
// Remove the next setting to load from the queue, if any
Iterator<Setting> iter = mSettingsToLoad.iterator();
if (!iter.hasNext()) {
- mLoading = false;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "nothing left to do for " + msg + ", " + this);
+ }
return;
}
Setting setting = iter.next();
@@ -337,17 +359,28 @@
// Request the status value
Intent intent = setting.createUpdatingIntent();
mContext.startService(intent);
+ mSettingsBeingLoaded.add(setting);
// Ensure that if receiving the status value takes too long, we start loading the
// next value anyway
Message timeoutMsg = obtainMessage(WHAT_TIMEOUT, setting);
- removeMessages(WHAT_TIMEOUT);
sendMessageDelayed(timeoutMsg, INJECTED_STATUS_UPDATE_TIMEOUT_MILLIS);
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "handleMessage end: " + msg + ", mSettingsToLoad: " + mSettingsToLoad);
+ Log.d(TAG, "handleMessage end " + msg + ", " + this
+ + ", started loading " + setting);
}
}
+
+ @Override
+ public String toString() {
+ return "StatusLoadingHandler{" +
+ "mSettingsToLoad=" + mSettingsToLoad +
+ ", mSettingsBeingLoaded=" + mSettingsBeingLoaded +
+ ", mTimedOutSettings=" + mTimedOutSettings +
+ ", mReloadRequested=" + mReloadRequested +
+ '}';
+ }
}
/**
@@ -357,7 +390,6 @@
public final InjectedSetting setting;
public final Preference preference;
- public boolean timedOut = false;
private Setting(InjectedSetting setting, Preference preference) {
this.setting = setting;
@@ -369,11 +401,24 @@
return "Setting{" +
"setting=" + setting +
", preference=" + preference +
- ", timedOut=" + timedOut +
'}';
}
/**
+ * Returns true if they both have the same {@link #setting} value. Ignores mutable
+ * preference so that it's safe to use in sets.
+ */
+ @Override
+ public boolean equals(Object o) {
+ return this == o || o instanceof Setting && setting.equals(((Setting) o).setting);
+ }
+
+ @Override
+ public int hashCode() {
+ return setting.hashCode();
+ }
+
+ /**
* Creates an Intent to ask the receiver for the current status for the setting, and display
* it when it replies.
*/
diff --git a/src/com/android/settings/nfc/PaymentBackend.java b/src/com/android/settings/nfc/PaymentBackend.java
index fc0f4a3..3c2c3ce 100644
--- a/src/com/android/settings/nfc/PaymentBackend.java
+++ b/src/com/android/settings/nfc/PaymentBackend.java
@@ -86,17 +86,4 @@
Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
app != null ? app.flattenToString() : null);
}
-
- public boolean isAutoPaymentMode() {
- String mode = Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.NFC_PAYMENT_MODE);
- return (!CardEmulationManager.PAYMENT_MODE_MANUAL.equals(mode));
- }
-
- public void setAutoPaymentMode(boolean enable) {
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.NFC_PAYMENT_MODE,
- enable ? CardEmulationManager.PAYMENT_MODE_AUTO
- : CardEmulationManager.PAYMENT_MODE_MANUAL);
- }
}
\ No newline at end of file
diff --git a/src/com/android/settings/nfc/PaymentDefaultDialog.java b/src/com/android/settings/nfc/PaymentDefaultDialog.java
index 2dd465a..a6887a3 100644
--- a/src/com/android/settings/nfc/PaymentDefaultDialog.java
+++ b/src/com/android/settings/nfc/PaymentDefaultDialog.java
@@ -62,7 +62,6 @@
switch (which) {
case BUTTON_POSITIVE:
mBackend.setDefaultPaymentApp(mNewDefault);
- mBackend.setAutoPaymentMode(true);
setResult(RESULT_OK);
break;
case BUTTON_NEGATIVE:
@@ -98,7 +97,6 @@
}
// Get current mode and default component
- boolean isAuto = mBackend.isAutoPaymentMode();
ComponentName defaultComponent = mBackend.getDefaultPaymentApp();
if (defaultComponent != null && defaultComponent.equals(component)) {
Log.e(TAG, "Component " + component + " is already default.");
@@ -128,7 +126,7 @@
// Compose dialog; get
final AlertController.AlertParams p = mAlertParams;
p.mTitle = getString(R.string.nfc_payment_set_default);
- if (defaultAppInfo == null || !isAuto) {
+ if (defaultAppInfo == null) {
p.mMessage = "Always use " + newAppInfo.loadLabel(pm) + " when you tap and pay?";
} else {
p.mMessage = "Always use " + newAppInfo.loadLabel(pm) + " instead of " +
diff --git a/src/com/android/settings/nfc/PaymentSettings.java b/src/com/android/settings/nfc/PaymentSettings.java
index a1ed883..41bcc2c 100644
--- a/src/com/android/settings/nfc/PaymentSettings.java
+++ b/src/com/android/settings/nfc/PaymentSettings.java
@@ -48,8 +48,6 @@
PreferenceManager manager = getPreferenceManager();
PreferenceScreen screen = manager.createPreferenceScreen(getActivity());
- boolean isAuto = mPaymentBackend.isAutoPaymentMode();
-
// Get all payment services
List<PaymentAppInfo> appInfos = mPaymentBackend.getPaymentAppInfos();
if (appInfos != null && appInfos.size() > 0) {
@@ -58,7 +56,6 @@
PaymentAppPreference preference =
new PaymentAppPreference(getActivity(), appInfo, this);
// If for some reason isAuto gets out of sync, clear out app default
- appInfo.isDefault &= isAuto;
preference.setIcon(appInfo.icon);
preference.setTitle(appInfo.caption);
screen.addPreference(preference);
@@ -67,7 +64,7 @@
PaymentAppInfo appInfo = new PaymentAppInfo();
appInfo.icon = null;
appInfo.componentName = null;
- appInfo.isDefault = !isAuto;
+ appInfo.isDefault = !(mPaymentBackend.getDefaultPaymentApp() != null);
// Add "Ask every time" option
PaymentAppPreference preference =
new PaymentAppPreference(getActivity(), appInfo, this);
@@ -85,10 +82,8 @@
PaymentAppInfo appInfo = (PaymentAppInfo) v.getTag();
if (appInfo.componentName != null) {
mPaymentBackend.setDefaultPaymentApp(appInfo.componentName);
- mPaymentBackend.setAutoPaymentMode(true);
} else {
mPaymentBackend.setDefaultPaymentApp(null);
- mPaymentBackend.setAutoPaymentMode(false);
}
refresh();
}
diff --git a/src/com/android/settings/widget/SettingsAppWidgetProvider.java b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
index da085f7..bf3f497 100644
--- a/src/com/android/settings/widget/SettingsAppWidgetProvider.java
+++ b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
@@ -548,9 +548,23 @@
final UserManager um =
(UserManager) context.getSystemService(Context.USER_SERVICE);
if (!um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION)) {
- int mode = desiredState
- ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
- : Settings.Secure.LOCATION_MODE_BATTERY_SAVING;
+ int currentMode = Settings.Secure.getInt(resolver,
+ Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
+ int mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
+ switch (currentMode) {
+ case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
+ mode = Settings.Secure.LOCATION_MODE_BATTERY_SAVING;
+ break;
+ case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
+ mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
+ break;
+ case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
+ mode = Settings.Secure.LOCATION_MODE_OFF;
+ break;
+ case Settings.Secure.LOCATION_MODE_OFF:
+ mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
+ break;
+ }
Settings.Secure.putInt(resolver, Settings.Secure.LOCATION_MODE, mode);
return desiredState;
}