Add 'Use My Location for Google services'.
This interfaces to GSF to actually change the setting as Settings doesn't
have the permissions to do it directly. When GSF is not present on the device,
the setting will be hidden.
Depending on change: Ib3809571fe22f40ba34468d39fedfff70f0742ef
Bug: 3093036
Change-Id: I98596cce118f0fa5ebae45a7f8ab9c9f8a3bf2bc
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d4acfd6..1d763ee 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1680,6 +1680,12 @@
<string name="assisted_gps_enabled">Use server to assist GPS (uncheck to reduce network usage)</string>
<!-- Security & location settings screen, setting summary when Assisted GPS check box is clear -->
<string name="assisted_gps_disabled">Use server to assist GPS (uncheck to improve GPS performance)</string>
+ <!-- [CHAR_LIMIT=100] Security & location settings screen, setting check box label if the user wants to use their location for Google Search & other Google services -->
+ <string name="use_location_title">Use location for Google search</string>
+ <!-- [CHAR_LIMIT=100] Security & location settings screen, setting summary when Use My Location for Google services is clear -->
+ <string name="use_location_summary_disabled">Use location for Google search and other Google services</string>
+ <!-- [CHAR_LIMIT=100] Security & location settings screen, setting summary when Use My Location for Google services is checked -->
+ <string name="use_location_summary_enabled">Location used to improve Google search results and other Google services</string>
<!-- About --> <skip />
<!-- Main settings screen, setting title for the user to go into the About phone screen -->
diff --git a/src/com/android/settings/GoogleLocationSettingHelper.java b/src/com/android/settings/GoogleLocationSettingHelper.java
new file mode 100644
index 0000000..0d4861e
--- /dev/null
+++ b/src/com/android/settings/GoogleLocationSettingHelper.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings;
+
+import android.content.ActivityNotFoundException;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.database.Cursor;
+import android.net.Uri;
+import android.util.Log;
+
+/**
+ * Helper class to read and write the 'Use My Location' setting used by Google Apps (e.g. GoogleQSB,
+ * VoiceSearch).
+ *
+ * This class duplicates a small amount of functionality from GSF (Google Services Framework) to
+ * allow the open source Settings app to interface to the 'Use My Location' setting owned by GSF.
+ */
+public class GoogleLocationSettingHelper {
+
+ private static final String TAG = "GoogleLocationSettingHelper";
+
+ /**
+ * User has disagreed to use location for Google services.
+ */
+ public static final int USE_LOCATION_FOR_SERVICES_OFF = 0;
+
+ /**
+ * User has agreed to use location for Google services.
+ */
+ public static final int USE_LOCATION_FOR_SERVICES_ON = 1;
+
+ /**
+ * The user has neither agreed nor disagreed to use location for Google services yet.
+ */
+ public static final int USE_LOCATION_FOR_SERVICES_NOT_SET = 2;
+
+ private static final String GOOGLE_SETTINGS_AUTHORITY = "com.google.settings";
+ private static final Uri GOOGLE_SETTINGS_CONTENT_URI =
+ Uri.parse("content://" + GOOGLE_SETTINGS_AUTHORITY + "/partner");
+ private static final String NAME = "name";
+ private static final String VALUE = "value";
+ private static final String USE_LOCATION_FOR_SERVICES = "use_location_for_services";
+
+ private static final String ACTION_SET_USE_LOCATION_FOR_SERVICES =
+ "com.google.android.gsf.action.SET_USE_LOCATION_FOR_SERVICES";
+ public static final String EXTRA_DISABLE_USE_LOCATION_FOR_SERVICES = "disable";
+
+ /**
+ * Determine if the 'Use My Location' setting is applicable on this device, i.e. if the
+ * activity used to enabled/disable it is present.
+ */
+ public static boolean isAvailable(Context context) {
+ ResolveInfo ri = context.getPackageManager().resolveActivity(getSetUseLocationIntent(),
+ PackageManager.MATCH_DEFAULT_ONLY);
+ return ri != null;
+ }
+
+ private static Intent getSetUseLocationIntent() {
+ Intent i = new Intent(ACTION_SET_USE_LOCATION_FOR_SERVICES);
+ return i;
+ }
+
+ /**
+ * Get the current value for the 'Use value for location' setting.
+ * @return One of {@link #USE_LOCATION_FOR_SERVICES_NOT_SET},
+ * {@link #USE_LOCATION_FOR_SERVICES_OFF} or {@link #USE_LOCATION_FOR_SERVICES_ON}.
+ */
+ public static int getUseLocationForServices(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ Cursor c = null;
+ String stringValue = null;
+ try {
+ c = resolver.query(GOOGLE_SETTINGS_CONTENT_URI, new String[] { VALUE }, NAME + "=?",
+ new String[] { USE_LOCATION_FOR_SERVICES }, null);
+ if (c != null && c.moveToNext()) {
+ stringValue = c.getString(0);
+ }
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Failed to get 'Use My Location' setting", e);
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ if (stringValue == null) {
+ return USE_LOCATION_FOR_SERVICES_NOT_SET;
+ }
+ int value;
+ try {
+ value = Integer.parseInt(stringValue);
+ } catch (NumberFormatException nfe) {
+ value = USE_LOCATION_FOR_SERVICES_NOT_SET;
+ }
+ return value;
+ }
+
+ /**
+ * Change the value of the 'Use My Location' setting. This launches a GSF activity which has
+ * the permissions to actually make the change, prompting the user if necessary.
+ */
+ public static void setUseLocationForServices(Context context, boolean use) {
+ Intent i = getSetUseLocationIntent();
+ i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ i.putExtra(EXTRA_DISABLE_USE_LOCATION_FOR_SERVICES, !use);
+ try {
+ context.startActivity(i);
+ } catch (ActivityNotFoundException e) {
+ }
+ }
+
+}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index dacc19f..dd51295 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -36,10 +36,11 @@
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceCategory;
+import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
-import android.preference.Preference.OnPreferenceChangeListener;
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyStore;
@@ -78,15 +79,17 @@
private CheckBoxPreference mShowPassword;
// Location Settings
+ private static final String LOCATION_CATEGORY = "location_category";
private static final String LOCATION_NETWORK = "location_network";
private static final String LOCATION_GPS = "location_gps";
private static final String ASSISTED_GPS = "assisted_gps";
+ private static final String USE_LOCATION = "location_use_for_services";
private static final String LOCK_AFTER_TIMEOUT_KEY = "lock_after_timeout";
private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
private static final int FALLBACK_LOCK_AFTER_TIMEOUT_VALUE = 5000; // compatible with pre-Froyo
// Credential storage
- private CredentialStorage mCredentialStorage = new CredentialStorage();
+ private final CredentialStorage mCredentialStorage = new CredentialStorage();
// Encrypted file system
private CheckBoxPreference mEncryptedFSEnabled;
@@ -94,6 +97,7 @@
private CheckBoxPreference mNetwork;
private CheckBoxPreference mGps;
private CheckBoxPreference mAssistedGps;
+ private CheckBoxPreference mUseLocation;
DevicePolicyManager mDPM;
@@ -158,6 +162,22 @@
mNetwork = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_NETWORK);
mGps = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_GPS);
mAssistedGps = (CheckBoxPreference) getPreferenceScreen().findPreference(ASSISTED_GPS);
+ if (GoogleLocationSettingHelper.isAvailable(getActivity())) {
+ // GSF present, Add setting for 'Use My Location'
+ PreferenceGroup locationCat = (PreferenceGroup) root.findPreference(LOCATION_CATEGORY);
+ CheckBoxPreference useLocation = new CheckBoxPreference(getActivity());
+ useLocation.setKey(USE_LOCATION);
+ useLocation.setTitle(R.string.use_location_title);
+ useLocation.setSummaryOn(R.string.use_location_summary_enabled);
+ useLocation.setSummaryOff(R.string.use_location_summary_disabled);
+ useLocation.setChecked(
+ GoogleLocationSettingHelper.getUseLocationForServices(getActivity())
+ == GoogleLocationSettingHelper.USE_LOCATION_FOR_SERVICES_ON);
+ useLocation.setPersistent(false);
+ useLocation.setOnPreferenceChangeListener(this);
+ locationCat.addPreference(useLocation);
+ mUseLocation = useLocation;
+ }
PreferenceManager pm = getPreferenceManager();
@@ -398,7 +418,7 @@
private static final int DLG_RESET = DLG_PASSWORD + 1;
private static final int DLG_ENABLE_EFS = DLG_RESET + 1;
- private KeyStore mKeyStore = KeyStore.getInstance();
+ private final KeyStore mKeyStore = KeyStore.getInstance();
private int mState;
private boolean mSubmit = false;
private boolean mExternal = false;
@@ -748,6 +768,14 @@
} catch (NumberFormatException e) {
Log.e("SecuritySettings", "could not persist lockAfter timeout setting", e);
}
+ } else if (preference == mUseLocation) {
+ boolean newValue = value == null ? false : (Boolean) value;
+ GoogleLocationSettingHelper.setUseLocationForServices(getActivity(), newValue);
+ // We don't want to change the value immediately here, since the user may click
+ // disagree in the dialog that pops up. When the activity we just launched exits, this
+ // activity will be restated and the new value re-read, so the checkbox will get its
+ // new value then.
+ return false;
}
return true;
}