2 * Copyright (C) 2011 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.settings.location;
19 import android.app.ActionBar;
20 import android.app.Activity;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.location.LocationManager;
26 import android.location.SettingInjectorService;
27 import android.os.Bundle;
28 import android.preference.Preference;
29 import android.preference.PreferenceActivity;
30 import android.preference.PreferenceCategory;
31 import android.preference.PreferenceGroup;
32 import android.preference.PreferenceScreen;
33 import android.provider.Settings;
34 import android.util.Log;
35 import android.view.Gravity;
36 import android.widget.CompoundButton;
37 import android.widget.Switch;
39 import com.android.settings.R;
41 import java.util.Collections;
42 import java.util.Comparator;
43 import java.util.List;
46 * Location access settings.
48 public class LocationSettings extends LocationSettingsBase
49 implements CompoundButton.OnCheckedChangeListener {
51 private static final String TAG = "LocationSettings";
53 /** Key for preference screen "Mode" */
54 private static final String KEY_LOCATION_MODE = "location_mode";
55 /** Key for preference category "Recent location requests" */
56 private static final String KEY_RECENT_LOCATION_REQUESTS = "recent_location_requests";
57 /** Key for preference category "Location services" */
58 private static final String KEY_APP_SETTINGS = "app_settings";
60 private Switch mSwitch;
61 private boolean mValidListener;
62 private Preference mLocationMode;
63 private PreferenceCategory mCategoryRecentLocationRequests;
64 /** Receives UPDATE_INTENT */
65 private BroadcastReceiver mReceiver;
67 public LocationSettings() {
68 mValidListener = false;
72 public void onActivityResult(int requestCode, int resultCode, Intent data) {
73 super.onActivityResult(requestCode, resultCode, data);
74 createPreferenceHierarchy();
78 public void onResume() {
80 mSwitch = new Switch(getActivity());
81 mSwitch.setOnCheckedChangeListener(this);
82 mValidListener = true;
83 createPreferenceHierarchy();
87 public void onPause() {
89 getActivity().unregisterReceiver(mReceiver);
90 } catch (RuntimeException e) {
91 // Ignore exceptions caused by race condition
94 mValidListener = false;
95 mSwitch.setOnCheckedChangeListener(null);
98 private void addPreferencesSorted(List<Preference> prefs, PreferenceGroup container) {
99 // If there's some items to display, sort the items and add them to the container.
100 Collections.sort(prefs, new Comparator<Preference>() {
102 public int compare(Preference lhs, Preference rhs) {
103 return lhs.getTitle().toString().compareTo(rhs.getTitle().toString());
106 for (Preference entry : prefs) {
107 container.addPreference(entry);
111 private PreferenceScreen createPreferenceHierarchy() {
112 final PreferenceActivity activity = (PreferenceActivity) getActivity();
113 PreferenceScreen root = getPreferenceScreen();
117 addPreferencesFromResource(R.xml.location_settings);
118 root = getPreferenceScreen();
120 mLocationMode = root.findPreference(KEY_LOCATION_MODE);
121 mLocationMode.setOnPreferenceClickListener(
122 new Preference.OnPreferenceClickListener() {
124 public boolean onPreferenceClick(Preference preference) {
125 activity.startPreferencePanel(
126 LocationMode.class.getName(), null,
127 R.string.location_mode_screen_title, null, LocationSettings.this,
133 mCategoryRecentLocationRequests =
134 (PreferenceCategory) root.findPreference(KEY_RECENT_LOCATION_REQUESTS);
135 RecentLocationApps recentApps = new RecentLocationApps(activity);
136 List<Preference> recentLocationRequests = recentApps.getAppList();
137 if (recentLocationRequests.size() > 0) {
138 addPreferencesSorted(recentLocationRequests, mCategoryRecentLocationRequests);
140 // If there's no item to display, add a "No recent apps" item.
141 Preference banner = new Preference(activity);
142 banner.setLayoutResource(R.layout.location_list_no_item);
143 banner.setTitle(R.string.location_no_recent_apps);
144 banner.setSelectable(false);
145 mCategoryRecentLocationRequests.addPreference(banner);
148 addAppSettings(activity, root);
150 // Only show the master switch when we're not in multi-pane mode, and not being used as
152 if (activity.onIsHidingHeaders() || !activity.onIsMultiPane()) {
153 final int padding = activity.getResources().getDimensionPixelSize(
154 R.dimen.action_bar_switch_padding);
155 mSwitch.setPaddingRelative(0, 0, padding, 0);
156 activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
157 ActionBar.DISPLAY_SHOW_CUSTOM);
158 activity.getActionBar().setCustomView(mSwitch, new ActionBar.LayoutParams(
159 ActionBar.LayoutParams.WRAP_CONTENT,
160 ActionBar.LayoutParams.WRAP_CONTENT,
161 Gravity.CENTER_VERTICAL | Gravity.END));
164 setHasOptionsMenu(true);
166 refreshLocationMode();
171 * Add the settings injected by external apps into the "App Settings" category. Hides the
172 * category if there are no injected settings.
174 * Reloads the settings whenever receives
175 * {@link SettingInjectorService#ACTION_INJECTED_SETTING_CHANGED}. As a safety measure,
176 * also reloads on {@link LocationManager#MODE_CHANGED_ACTION} to ensure the settings are
177 * up-to-date after mode changes even if an affected app doesn't send the setting changed
180 private void addAppSettings(Context context, PreferenceScreen root) {
181 PreferenceCategory categoryAppSettings =
182 (PreferenceCategory) root.findPreference(KEY_APP_SETTINGS);
183 final SettingsInjector injector = new SettingsInjector(context);
184 List<Preference> appSettings = injector.getInjectedSettings();
186 mReceiver = new BroadcastReceiver() {
188 public void onReceive(Context context, Intent intent) {
189 if (Log.isLoggable(TAG, Log.DEBUG)) {
190 Log.d(TAG, "Received settings change intent: " + intent);
192 injector.reloadStatusMessages();
196 IntentFilter filter = new IntentFilter();
197 filter.addAction(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED);
198 filter.addAction(LocationManager.MODE_CHANGED_ACTION);
199 context.registerReceiver(mReceiver, filter);
201 if (appSettings.size() > 0) {
202 addPreferencesSorted(appSettings, categoryAppSettings);
204 // If there's no item to display, remove the whole category.
205 root.removePreference(categoryAppSettings);
210 public int getHelpResource() {
211 return R.string.help_url_location_access;
215 public void onModeChanged(int mode, boolean restricted) {
217 case Settings.Secure.LOCATION_MODE_OFF:
218 mLocationMode.setSummary(R.string.location_mode_location_off_title);
220 case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
221 mLocationMode.setSummary(R.string.location_mode_sensors_only_title);
223 case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
224 mLocationMode.setSummary(R.string.location_mode_battery_saving_title);
226 case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
227 mLocationMode.setSummary(R.string.location_mode_high_accuracy_title);
233 // Restricted user can't change the location mode, so disable the master switch. But in some
234 // corner cases, the location might still be enabled. In such case the master switch should
235 // be disabled but checked.
236 boolean enabled = (mode != Settings.Secure.LOCATION_MODE_OFF);
237 mSwitch.setEnabled(!restricted);
238 mLocationMode.setEnabled(enabled && !restricted);
239 mCategoryRecentLocationRequests.setEnabled(enabled);
241 if (enabled != mSwitch.isChecked()) {
242 // set listener to null so that that code below doesn't trigger onCheckedChanged()
243 if (mValidListener) {
244 mSwitch.setOnCheckedChangeListener(null);
246 mSwitch.setChecked(enabled);
247 if (mValidListener) {
248 mSwitch.setOnCheckedChangeListener(this);
254 * Listens to the state change of the location master switch.
257 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
259 setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
261 setLocationMode(Settings.Secure.LOCATION_MODE_OFF);