OSDN Git Service

Finished the location settings
authorLifu Tang <lifu@google.com>
Tue, 6 Aug 2013 20:31:50 +0000 (13:31 -0700)
committerLifu Tang <lifu@google.com>
Thu, 8 Aug 2013 00:45:24 +0000 (17:45 -0700)
Change-Id: I333fcc74ad387ef6edaa558656d3eaa91feb8fe9

AndroidManifest.xml
res/values/strings.xml
res/xml/location_settings.xml
src/com/android/settings/location/LocationEnabler.java [deleted file]
src/com/android/settings/location/LocationMode.java
src/com/android/settings/location/LocationSettings.java
src/com/android/settings/location/LocationSettingsBase.java [new file with mode: 0644]
src/com/android/settings/location/RadioButtonPreference.java

index 2da0e4e..10c3adb 100644 (file)
         </activity>
 
         <activity android:name="Settings$LocationSettingsActivity"
+                android:uiOptions="splitActionBarWhenNarrow"
                 android:label="@string/location_settings_title"
                 android:configChanges="orientation|keyboardHidden|screenSize"
                 android:taskAffinity=""
index b797340..c96167c 100644 (file)
     <string name="location_mode_battery_saving_title">Battery saving</string>
     <!-- [CHAR LIMIT=30] Location settings screen, device sensors only location mode -->
     <string name="location_mode_sensors_only_title">Device sensors only</string>
+    <!-- [CHAR LIMIT=30] Location settings screen, location off mode -->
+    <string name="location_mode_location_off_title">Location off</string>
     <!-- [CHAR LIMIT=30] Location settings screen, sub category for recent location requests -->
     <string name="location_category_recent_location_requests">Recent location requests</string>
     <!-- [CHAR LIMIT=30] Location settings screen, sub category for location services -->
     <string name="location_category_location_services">Location services</string>
     <!-- [CHAR LIMIT=30] Location mode screen, screen title -->
     <string name="location_mode_screen_title">Location mode</string>
-    <!-- [CHAR LIMIT=30] Location mode screen, description for high accuracy mode -->
+    <!-- [CHAR LIMIT=130] Location mode screen, description for high accuracy mode -->
     <string name="location_mode_high_accuracy_description">Use GPS, Wi\u2011Fi and mobile networks to estimate location </string>
-    <!-- [CHAR LIMIT=30] Location mode screen, description for battery saving mode -->
+    <!-- [CHAR LIMIT=130] Location mode screen, description for battery saving mode -->
     <string name="location_mode_battery_saving_description">Use Wi\u2011Fi and mobile networks to estimate location</string>
-    <!-- [CHAR LIMIT=30] Location mode screen, description for sensors only mode -->
+    <!-- [CHAR LIMIT=130] Location mode screen, description for sensors only mode -->
     <string name="location_mode_sensors_only_description">Use GPS to pinpoint your location</string>
 
     <!-- [CHAR LIMIT=30] Security & location settings screen, setting check box label for Google location service (cell ID, wifi, etc.) -->
index 293b772..e646cab 100644 (file)
@@ -22,7 +22,7 @@
         <PreferenceScreen
             android:key="location_mode"
             android:title="@string/location_mode_title"
-            android:summary="@string/location_mode_high_accuracy_title" />
+            android:summary="@string/location_mode_location_off_title" />
 
         <PreferenceCategory
             android:key="recent_location_requests"
diff --git a/src/com/android/settings/location/LocationEnabler.java b/src/com/android/settings/location/LocationEnabler.java
deleted file mode 100644 (file)
index 61816a1..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2013 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.location;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.widget.CompoundButton;
-import android.widget.Switch;
-
-/**
- * LocationEnabler is a helper to manage the Location on/off master switch
- * preference. It turns on/off Location master switch and ensures the summary
- * of the preference reflects the current state.
- */
-public final class LocationEnabler implements CompoundButton.OnCheckedChangeListener {
-    private final Context mContext;
-    private Switch mSwitch;
-    private boolean mValidListener;
-
-    // TODO(lifu): listens to the system configuration change, and modify the switch state whenever
-    // necessary.
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-        }
-    };
-
-    public LocationEnabler(Context context, Switch switch_) {
-        mContext = context;
-        mSwitch = switch_;
-        mValidListener = false;
-    }
-
-    public void resume() {
-        mSwitch.setOnCheckedChangeListener(this);
-        mValidListener = true;
-    }
-
-    public void pause() {
-        mSwitch.setOnCheckedChangeListener(null);
-        mValidListener = false;
-    }
-
-    @Override
-    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-        // TODO(lifu): modify the actual location settings when the user flip the master switch.
-    }
-
-    private void setChecked(boolean isChecked) {
-        if (isChecked != mSwitch.isChecked()) {
-            // set listener to null so that that code below doesn't trigger onCheckedChanged()
-            if (mValidListener) {
-                mSwitch.setOnCheckedChangeListener(null);
-            }
-            mSwitch.setChecked(isChecked);
-            if (mValidListener) {
-                mSwitch.setOnCheckedChangeListener(this);
-            }
-        }
-    }
-}
index 3422b1a..4cb3a5e 100644 (file)
 
 package com.android.settings.location;
 
+import android.app.Activity;
 import android.content.Intent;
-import android.preference.Preference;
+import android.preference.PreferenceActivity;
 import android.preference.PreferenceScreen;
 
 import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
 
 /**
  * A page with 3 radio buttons to choose the location mode.
@@ -34,8 +34,15 @@ import com.android.settings.SettingsPreferenceFragment;
  *
  * Sensors only: use GPS location only.
  */
-public class LocationMode extends SettingsPreferenceFragment
-        implements Preference.OnPreferenceChangeListener {
+public class LocationMode extends LocationSettingsBase
+        implements RadioButtonPreference.OnClickListener {
+    private static final String KEY_HIGH_ACCURACY = "high_accuracy";
+    private RadioButtonPreference mHighAccuracy;
+    private static final String KEY_BATTERY_SAVING = "battery_saving";
+    private RadioButtonPreference mBatterySaving;
+    private static final String KEY_SENSORS_ONLY = "sensors_only";
+    private RadioButtonPreference mSensorsOnly;
+
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
@@ -45,10 +52,18 @@ public class LocationMode extends SettingsPreferenceFragment
     @Override
     public void onResume() {
         super.onResume();
-
-        // Make sure we reload the preference hierarchy since some of these settings
-        // depend on others...
         createPreferenceHierarchy();
+        mHighAccuracy.resume();
+        mBatterySaving.resume();
+        mSensorsOnly.resume();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mHighAccuracy.pause();
+        mBatterySaving.pause();
+        mSensorsOnly.pause();
     }
 
     private PreferenceScreen createPreferenceHierarchy() {
@@ -59,16 +74,74 @@ public class LocationMode extends SettingsPreferenceFragment
         addPreferencesFromResource(R.xml.location_mode);
         root = getPreferenceScreen();
 
+        mHighAccuracy = (RadioButtonPreference) root.findPreference(KEY_HIGH_ACCURACY);
+        mBatterySaving = (RadioButtonPreference) root.findPreference(KEY_BATTERY_SAVING);
+        mSensorsOnly = (RadioButtonPreference) root.findPreference(KEY_SENSORS_ONLY);
+        mHighAccuracy.setOnClickListener(this);
+        mBatterySaving.setOnClickListener(this);
+        mSensorsOnly.setOnClickListener(this);
+
+        refreshLocationMode();
         return root;
     }
 
+    private void updateRadioButtons(RadioButtonPreference activated) {
+        if (activated == mHighAccuracy) {
+            mHighAccuracy.setChecked(true);
+            mBatterySaving.setChecked(false);
+            mSensorsOnly.setChecked(false);
+        } else if (activated == mBatterySaving) {
+            mHighAccuracy.setChecked(false);
+            mBatterySaving.setChecked(true);
+            mSensorsOnly.setChecked(false);
+        } else if (activated == mSensorsOnly) {
+            mHighAccuracy.setChecked(false);
+            mBatterySaving.setChecked(false);
+            mSensorsOnly.setChecked(true);
+        }
+    }
+
     @Override
-    public int getHelpResource() {
-        return R.string.help_url_location_access;
+    public void onRadioButtonClicked(RadioButtonPreference emiter) {
+        int mode = LocationSettingsBase.MODE_LOCATION_OFF;
+        if (emiter == mHighAccuracy) {
+            mode = LocationSettingsBase.MODE_HIGH_ACCURACY;
+        } else if (emiter == mBatterySaving) {
+            mode = LocationSettingsBase.MODE_BATTERY_SAVING;
+        } else if (emiter == mSensorsOnly) {
+            mode = LocationSettingsBase.MODE_SENSORS_ONLY;
+        }
+        setLocationMode(mode);
     }
 
     @Override
-    public boolean onPreferenceChange(Preference preference, Object newValue) {
-      return true;
+    public void onModeChanged(int mode) {
+        switch (mode) {
+            case MODE_LOCATION_OFF:
+                Intent intent = new Intent();
+                PreferenceActivity pa = (PreferenceActivity) getActivity();
+                pa.finishPreferencePanel(LocationMode.this, Activity.RESULT_OK, intent);
+                break;
+            case MODE_SENSORS_ONLY:
+                updateRadioButtons(mSensorsOnly);
+                break;
+            case MODE_BATTERY_SAVING:
+                updateRadioButtons(mBatterySaving);
+                break;
+            case MODE_HIGH_ACCURACY:
+                updateRadioButtons(mHighAccuracy);
+                break;
+            default:
+                break;
+        }
+        boolean enabled = (mode != MODE_LOCATION_OFF);
+        mHighAccuracy.setEnabled(enabled);
+        mBatterySaving.setEnabled(enabled);
+        mSensorsOnly.setEnabled(enabled);
+    }
+
+    @Override
+    public int getHelpResource() {
+        return R.string.help_url_location_access;
     }
 }
index 8d0baae..1f012e4 100644 (file)
@@ -21,24 +21,34 @@ import android.app.Activity;
 import android.content.Intent;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
+import android.preference.PreferenceCategory;
 import android.preference.PreferenceScreen;
 import android.util.Log;
 import android.view.Gravity;
+import android.widget.CompoundButton;
 import android.widget.Switch;
 
 import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
 
 /**
  * Location access settings.
  */
-public class LocationSettings extends SettingsPreferenceFragment
-        implements Preference.OnPreferenceChangeListener {
+public class LocationSettings extends LocationSettingsBase
+        implements CompoundButton.OnCheckedChangeListener {
     private static final String TAG = LocationSettings.class.getSimpleName();
     private static final String KEY_LOCATION_MODE = "location_mode";
+    private static final String KEY_RECENT_LOCATION_REQUESTS = "recent_location_requests";
+    private static final String KEY_LOCATION_SERVICES = "location_services";
 
+    private Switch mSwitch;
+    private boolean mValidListener;
     private PreferenceScreen mLocationMode;
-    private LocationEnabler mLocationEnabler;
+    private PreferenceCategory mRecentLocationRequests;
+    private PreferenceCategory mLocationServices;
+
+    public LocationSettings() {
+        mValidListener = false;
+    }
 
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
@@ -49,12 +59,19 @@ public class LocationSettings extends SettingsPreferenceFragment
     @Override
     public void onResume() {
         super.onResume();
-
-        // Make sure we reload the preference hierarchy since some of these settings
-        // depend on others...
+        mSwitch = new Switch(getActivity());
+        mSwitch.setOnCheckedChangeListener(this);
+        mValidListener = true;
         createPreferenceHierarchy();
     }
 
+    @Override
+    public void onPause() {
+        super.onPause();
+        mValidListener = false;
+        mSwitch.setOnCheckedChangeListener(null);
+    }
+
     private PreferenceScreen createPreferenceHierarchy() {
         PreferenceScreen root = getPreferenceScreen();
         if (root != null) {
@@ -63,7 +80,7 @@ public class LocationSettings extends SettingsPreferenceFragment
         addPreferencesFromResource(R.xml.location_settings);
         root = getPreferenceScreen();
 
-        mLocationMode = (PreferenceScreen) root.findPreference((KEY_LOCATION_MODE));
+        mLocationMode = (PreferenceScreen) root.findPreference(KEY_LOCATION_MODE);
         mLocationMode.setOnPreferenceClickListener(
                 new Preference.OnPreferenceClickListener() {
                     @Override
@@ -77,9 +94,11 @@ public class LocationSettings extends SettingsPreferenceFragment
                         return true;
                     }
                 });
+        mRecentLocationRequests =
+                (PreferenceCategory) root.findPreference(KEY_RECENT_LOCATION_REQUESTS);
+        mLocationServices = (PreferenceCategory) root.findPreference(KEY_LOCATION_SERVICES);
 
         Activity activity = getActivity();
-        Switch actionBarSwitch = new Switch(activity);
 
         if (activity instanceof PreferenceActivity) {
             PreferenceActivity preferenceActivity = (PreferenceActivity) activity;
@@ -88,10 +107,10 @@ public class LocationSettings extends SettingsPreferenceFragment
             if (preferenceActivity.onIsHidingHeaders() || !preferenceActivity.onIsMultiPane()) {
                 final int padding = activity.getResources().getDimensionPixelSize(
                         R.dimen.action_bar_switch_padding);
-                actionBarSwitch.setPaddingRelative(0, 0, padding, 0);
+                mSwitch.setPaddingRelative(0, 0, padding, 0);
                 activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
                         ActionBar.DISPLAY_SHOW_CUSTOM);
-                activity.getActionBar().setCustomView(actionBarSwitch, new ActionBar.LayoutParams(
+                activity.getActionBar().setCustomView(mSwitch, new ActionBar.LayoutParams(
                         ActionBar.LayoutParams.WRAP_CONTENT,
                         ActionBar.LayoutParams.WRAP_CONTENT,
                         Gravity.CENTER_VERTICAL | Gravity.END));
@@ -100,9 +119,9 @@ public class LocationSettings extends SettingsPreferenceFragment
             Log.wtf(TAG, "Current activity is not an instance of PreferenceActivity!");
         }
 
-        mLocationEnabler = new LocationEnabler(activity, actionBarSwitch);
         setHasOptionsMenu(true);
 
+        refreshLocationMode();
         return root;
     }
 
@@ -112,7 +131,50 @@ public class LocationSettings extends SettingsPreferenceFragment
     }
 
     @Override
-    public boolean onPreferenceChange(Preference preference, Object newValue) {
-      return true;
+    public void onModeChanged(int mode) {
+        switch (mode) {
+            case MODE_LOCATION_OFF:
+                mLocationMode.setSummary(R.string.location_mode_location_off_title);
+                break;
+            case MODE_SENSORS_ONLY:
+                mLocationMode.setSummary(R.string.location_mode_sensors_only_title);
+                break;
+            case MODE_BATTERY_SAVING:
+                mLocationMode.setSummary(R.string.location_mode_battery_saving_title);
+                break;
+            case MODE_HIGH_ACCURACY:
+                mLocationMode.setSummary(R.string.location_mode_high_accuracy_title);
+                break;
+            default:
+                break;
+        }
+
+        boolean enabled = (mode != MODE_LOCATION_OFF);
+        mLocationMode.setEnabled(enabled);
+        mRecentLocationRequests.setEnabled(enabled);
+        mLocationServices.setEnabled(enabled);
+
+        if (enabled != mSwitch.isChecked()) {
+            // set listener to null so that that code below doesn't trigger onCheckedChanged()
+            if (mValidListener) {
+                mSwitch.setOnCheckedChangeListener(null);
+            }
+            mSwitch.setChecked(enabled);
+            if (mValidListener) {
+                mSwitch.setOnCheckedChangeListener(this);
+            }
+        }
+    }
+
+    /**
+     * Listens to the state change of the location master switch.
+     */
+    @Override
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (isChecked) {
+            setLocationMode(MODE_HIGH_ACCURACY);
+        } else {
+            setLocationMode(MODE_LOCATION_OFF);
+        }
     }
 }
diff --git a/src/com/android/settings/location/LocationSettingsBase.java b/src/com/android/settings/location/LocationSettingsBase.java
new file mode 100644 (file)
index 0000000..b3c6f70
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2011 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.location;
+
+import android.content.ContentQueryMap;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.location.LocationManager;
+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 static final String TAG = LocationSettingsBase.class.getSimpleName();
+
+    /** Location disabled */
+    public static final int MODE_LOCATION_OFF = 0;
+    /** GPS-only */
+    public static final int MODE_SENSORS_ONLY = 1;
+    /** Network location only */
+    public static final int MODE_BATTERY_SAVING = 2;
+    /** GPS and network location */
+    public static final int MODE_HIGH_ACCURACY = 3;
+
+    private ContentQueryMap mContentQueryMap;
+    private Observer mSettingsObserver;
+
+    @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();
+    }
+
+    /** Called when location mode has changed. */
+    public abstract void onModeChanged(int mode);
+
+    public void setLocationMode(int mode) {
+        boolean gps = false;
+        boolean network = false;
+        switch (mode) {
+            case MODE_LOCATION_OFF:
+                break;
+            case MODE_SENSORS_ONLY:
+                gps = true;
+                break;
+            case MODE_BATTERY_SAVING:
+                network = true;
+                break;
+            case MODE_HIGH_ACCURACY:
+                gps = true;
+                network = true;
+                break;
+            default:
+                Log.wtf(TAG, "Invalid location mode: " + mode);
+        }
+        final UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
+        if (um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION)) {
+            return;
+        }
+        // TODO(lifu): use new atomic API to change location mode.
+        Settings.Secure.setLocationProviderEnabled(
+                getContentResolver(), LocationManager.GPS_PROVIDER, gps);
+        Settings.Secure.setLocationProviderEnabled(
+                getContentResolver(), LocationManager.NETWORK_PROVIDER, network);
+        refreshLocationMode();
+    }
+
+    public void refreshLocationMode() {
+        ContentResolver res = getContentResolver();
+        boolean gpsEnabled = Settings.Secure.isLocationProviderEnabled(
+                res, LocationManager.GPS_PROVIDER);
+        boolean networkEnabled = Settings.Secure.isLocationProviderEnabled(
+                res, LocationManager.NETWORK_PROVIDER);
+        boolean enabled = gpsEnabled || networkEnabled;
+        if (!enabled) {
+            onModeChanged(MODE_LOCATION_OFF);
+        } else if (gpsEnabled && !networkEnabled) {
+            onModeChanged(MODE_SENSORS_ONLY);
+        } else if (!gpsEnabled && networkEnabled) {
+            onModeChanged(MODE_BATTERY_SAVING);
+        } else {
+            onModeChanged(MODE_HIGH_ACCURACY);
+        }
+    }
+}
index 452dc36..f87bd22 100644 (file)
@@ -37,9 +37,18 @@ import com.android.settings.R;
  * uncheck all the other preferences, you should do that by code yourself.
  */
 public class RadioButtonPreference extends CheckBoxPreference {
+    private boolean mValidListener;
+
+    public interface OnClickListener {
+        public abstract void onRadioButtonClicked(RadioButtonPreference emiter);
+    }
+
+    private OnClickListener mListener = null;
+
     public RadioButtonPreference(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
+        mValidListener = false;
     }
 
     public RadioButtonPreference(Context context, AttributeSet attrs) {
@@ -50,6 +59,25 @@ public class RadioButtonPreference extends CheckBoxPreference {
         this(context, null);
     }
 
+    void setOnClickListener(OnClickListener listener) {
+        mListener = listener;
+    }
+
+    public void pause() {
+        mValidListener = false;
+    }
+
+    public void resume() {
+        mValidListener = true;
+    }
+
+    @Override
+    public void onClick() {
+        if (mListener != null) {
+            mListener.onRadioButtonClicked(this);
+        }
+    }
+
     @Override
     protected void onBindView(View view) {
         super.onBindView(view);