• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 package com.android.settings.location;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.location.SettingInjectorService;
24 import android.os.Bundle;
25 import android.preference.Preference;
26 import android.preference.PreferenceCategory;
27 import android.preference.PreferenceGroup;
28 import android.preference.PreferenceScreen;
29 import android.util.Log;
30 import android.widget.Switch;
31 
32 import com.android.settings.R;
33 import com.android.settings.SettingsActivity;
34 import com.android.settings.widget.SwitchBar;
35 
36 import java.util.Collections;
37 import java.util.Comparator;
38 import java.util.List;
39 
40 /**
41  * Location access settings.
42  */
43 public class LocationSettings extends LocationSettingsBase
44         implements SwitchBar.OnSwitchChangeListener {
45 
46     private static final String TAG = "LocationSettings";
47 
48     /** Key for preference screen "Mode" */
49     private static final String KEY_LOCATION_MODE = "location_mode";
50     /** Key for preference category "Recent location requests" */
51     private static final String KEY_RECENT_LOCATION_REQUESTS = "recent_location_requests";
52     /** Key for preference category "Location services" */
53     private static final String KEY_LOCATION_SERVICES = "location_services";
54 
55     private SwitchBar mSwitchBar;
56     private Switch mSwitch;
57     private boolean mValidListener = false;
58     private Preference mLocationMode;
59     private PreferenceCategory mCategoryRecentLocationRequests;
60     /** Receives UPDATE_INTENT  */
61     private BroadcastReceiver mReceiver;
62     private SettingsInjector injector;
63 
64     @Override
onActivityCreated(Bundle savedInstanceState)65     public void onActivityCreated(Bundle savedInstanceState) {
66         super.onActivityCreated(savedInstanceState);
67 
68         final SettingsActivity activity = (SettingsActivity) getActivity();
69 
70         mSwitchBar = activity.getSwitchBar();
71         mSwitch = mSwitchBar.getSwitch();
72         mSwitchBar.show();
73     }
74 
75     @Override
onDestroyView()76     public void onDestroyView() {
77         super.onDestroyView();
78         mSwitchBar.hide();
79     }
80 
81     @Override
onResume()82     public void onResume() {
83         super.onResume();
84         createPreferenceHierarchy();
85         if (!mValidListener) {
86             mSwitchBar.addOnSwitchChangeListener(this);
87             mValidListener = true;
88         }
89     }
90 
91     @Override
onPause()92     public void onPause() {
93         try {
94             getActivity().unregisterReceiver(mReceiver);
95         } catch (RuntimeException e) {
96             // Ignore exceptions caused by race condition
97             if (Log.isLoggable(TAG, Log.VERBOSE)) {
98                 Log.v(TAG, "Swallowing " + e);
99             }
100         }
101         if (mValidListener) {
102             mSwitchBar.removeOnSwitchChangeListener(this);
103             mValidListener = false;
104         }
105         super.onPause();
106     }
107 
addPreferencesSorted(List<Preference> prefs, PreferenceGroup container)108     private void addPreferencesSorted(List<Preference> prefs, PreferenceGroup container) {
109         // If there's some items to display, sort the items and add them to the container.
110         Collections.sort(prefs, new Comparator<Preference>() {
111             @Override
112             public int compare(Preference lhs, Preference rhs) {
113                 return lhs.getTitle().toString().compareTo(rhs.getTitle().toString());
114             }
115         });
116         for (Preference entry : prefs) {
117             container.addPreference(entry);
118         }
119     }
120 
createPreferenceHierarchy()121     private PreferenceScreen createPreferenceHierarchy() {
122         final SettingsActivity activity = (SettingsActivity) getActivity();
123         PreferenceScreen root = getPreferenceScreen();
124         if (root != null) {
125             root.removeAll();
126         }
127         addPreferencesFromResource(R.xml.location_settings);
128         root = getPreferenceScreen();
129 
130         mLocationMode = root.findPreference(KEY_LOCATION_MODE);
131         mLocationMode.setOnPreferenceClickListener(
132                 new Preference.OnPreferenceClickListener() {
133                     @Override
134                     public boolean onPreferenceClick(Preference preference) {
135                         activity.startPreferencePanel(
136                                 LocationMode.class.getName(), null,
137                                 R.string.location_mode_screen_title, null, LocationSettings.this,
138                                 0);
139                         return true;
140                     }
141                 });
142 
143         mCategoryRecentLocationRequests =
144                 (PreferenceCategory) root.findPreference(KEY_RECENT_LOCATION_REQUESTS);
145         RecentLocationApps recentApps = new RecentLocationApps(activity);
146         List<Preference> recentLocationRequests = recentApps.getAppList();
147         if (recentLocationRequests.size() > 0) {
148             addPreferencesSorted(recentLocationRequests, mCategoryRecentLocationRequests);
149         } else {
150             // If there's no item to display, add a "No recent apps" item.
151             Preference banner = new Preference(activity);
152             banner.setLayoutResource(R.layout.location_list_no_item);
153             banner.setTitle(R.string.location_no_recent_apps);
154             banner.setSelectable(false);
155             mCategoryRecentLocationRequests.addPreference(banner);
156         }
157 
158         addLocationServices(activity, root);
159 
160         refreshLocationMode();
161         return root;
162     }
163 
164     /**
165      * Add the settings injected by external apps into the "App Settings" category. Hides the
166      * category if there are no injected settings.
167      *
168      * Reloads the settings whenever receives
169      * {@link SettingInjectorService#ACTION_INJECTED_SETTING_CHANGED}.
170      */
addLocationServices(Context context, PreferenceScreen root)171     private void addLocationServices(Context context, PreferenceScreen root) {
172         PreferenceCategory categoryLocationServices =
173                 (PreferenceCategory) root.findPreference(KEY_LOCATION_SERVICES);
174         injector = new SettingsInjector(context);
175         List<Preference> locationServices = injector.getInjectedSettings();
176 
177         mReceiver = new BroadcastReceiver() {
178             @Override
179             public void onReceive(Context context, Intent intent) {
180                 if (Log.isLoggable(TAG, Log.DEBUG)) {
181                     Log.d(TAG, "Received settings change intent: " + intent);
182                 }
183                 injector.reloadStatusMessages();
184             }
185         };
186 
187         IntentFilter filter = new IntentFilter();
188         filter.addAction(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED);
189         context.registerReceiver(mReceiver, filter);
190 
191         if (locationServices.size() > 0) {
192             addPreferencesSorted(locationServices, categoryLocationServices);
193         } else {
194             // If there's no item to display, remove the whole category.
195             root.removePreference(categoryLocationServices);
196         }
197     }
198 
199     @Override
getHelpResource()200     public int getHelpResource() {
201         return R.string.help_url_location_access;
202     }
203 
204     @Override
onModeChanged(int mode, boolean restricted)205     public void onModeChanged(int mode, boolean restricted) {
206         switch (mode) {
207             case android.provider.Settings.Secure.LOCATION_MODE_OFF:
208                 mLocationMode.setSummary(R.string.location_mode_location_off_title);
209                 break;
210             case android.provider.Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
211                 mLocationMode.setSummary(R.string.location_mode_sensors_only_title);
212                 break;
213             case android.provider.Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
214                 mLocationMode.setSummary(R.string.location_mode_battery_saving_title);
215                 break;
216             case android.provider.Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
217                 mLocationMode.setSummary(R.string.location_mode_high_accuracy_title);
218                 break;
219             default:
220                 break;
221         }
222 
223         // Restricted user can't change the location mode, so disable the master switch. But in some
224         // corner cases, the location might still be enabled. In such case the master switch should
225         // be disabled but checked.
226         boolean enabled = (mode != android.provider.Settings.Secure.LOCATION_MODE_OFF);
227         // Disable the whole switch bar instead of the switch itself. If we disabled the switch
228         // only, it would be re-enabled again if the switch bar is not disabled.
229         mSwitchBar.setEnabled(!restricted);
230         mLocationMode.setEnabled(enabled && !restricted);
231         mCategoryRecentLocationRequests.setEnabled(enabled);
232 
233         if (enabled != mSwitch.isChecked()) {
234             // set listener to null so that that code below doesn't trigger onCheckedChanged()
235             if (mValidListener) {
236                 mSwitchBar.removeOnSwitchChangeListener(this);
237             }
238             mSwitch.setChecked(enabled);
239             if (mValidListener) {
240                 mSwitchBar.addOnSwitchChangeListener(this);
241             }
242         }
243         // As a safety measure, also reloads on location mode change to ensure the settings are
244         // up-to-date even if an affected app doesn't send the setting changed broadcast.
245         injector.reloadStatusMessages();
246     }
247 
248     /**
249      * Listens to the state change of the location master switch.
250      */
251     @Override
onSwitchChanged(Switch switchView, boolean isChecked)252     public void onSwitchChanged(Switch switchView, boolean isChecked) {
253         if (isChecked) {
254             setLocationMode(android.provider.Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
255         } else {
256             setLocationMode(android.provider.Settings.Secure.LOCATION_MODE_OFF);
257         }
258     }
259 }
260