OSDN Git Service

Make recent location app list package based
[android-x86/packages-apps-Settings.git] / src / com / android / settings / location / LocationSettings.java
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.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;
38
39 import com.android.settings.R;
40
41 import java.util.Collections;
42 import java.util.Comparator;
43 import java.util.List;
44
45 /**
46  * Location access settings.
47  */
48 public class LocationSettings extends LocationSettingsBase
49         implements CompoundButton.OnCheckedChangeListener {
50
51     private static final String TAG = "LocationSettings";
52
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";
59
60     private Switch mSwitch;
61     private boolean mValidListener;
62     private Preference mLocationMode;
63     private PreferenceCategory mCategoryRecentLocationRequests;
64     /** Receives UPDATE_INTENT  */
65     private BroadcastReceiver mReceiver;
66
67     public LocationSettings() {
68         mValidListener = false;
69     }
70
71     @Override
72     public void onActivityResult(int requestCode, int resultCode, Intent data) {
73         super.onActivityResult(requestCode, resultCode, data);
74         createPreferenceHierarchy();
75     }
76
77     @Override
78     public void onResume() {
79         super.onResume();
80         mSwitch = new Switch(getActivity());
81         mSwitch.setOnCheckedChangeListener(this);
82         mValidListener = true;
83         createPreferenceHierarchy();
84     }
85
86     @Override
87     public void onPause() {
88         try {
89             getActivity().unregisterReceiver(mReceiver);
90         } catch (RuntimeException e) {
91             // Ignore exceptions caused by race condition
92         }
93         super.onPause();
94         mValidListener = false;
95         mSwitch.setOnCheckedChangeListener(null);
96     }
97
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>() {
101             @Override
102             public int compare(Preference lhs, Preference rhs) {
103                 return lhs.getTitle().toString().compareTo(rhs.getTitle().toString());
104             }
105         });
106         for (Preference entry : prefs) {
107             container.addPreference(entry);
108         }
109     }
110
111     private PreferenceScreen createPreferenceHierarchy() {
112         final PreferenceActivity activity = (PreferenceActivity) getActivity();
113         PreferenceScreen root = getPreferenceScreen();
114         if (root != null) {
115             root.removeAll();
116         }
117         addPreferencesFromResource(R.xml.location_settings);
118         root = getPreferenceScreen();
119
120         mLocationMode = root.findPreference(KEY_LOCATION_MODE);
121         mLocationMode.setOnPreferenceClickListener(
122                 new Preference.OnPreferenceClickListener() {
123                     @Override
124                     public boolean onPreferenceClick(Preference preference) {
125                         activity.startPreferencePanel(
126                                 LocationMode.class.getName(), null,
127                                 R.string.location_mode_screen_title, null, LocationSettings.this,
128                                 0);
129                         return true;
130                     }
131                 });
132
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);
139         } else {
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);
146         }
147
148         addAppSettings(activity, root);
149
150         // Only show the master switch when we're not in multi-pane mode, and not being used as
151         // Setup Wizard.
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));
162         }
163
164         setHasOptionsMenu(true);
165
166         refreshLocationMode();
167         return root;
168     }
169
170     /**
171      * Add the settings injected by external apps into the "App Settings" category. Hides the
172      * category if there are no injected settings.
173      *
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
178      * broadcast.
179      */
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();
185
186         mReceiver = new BroadcastReceiver() {
187             @Override
188             public void onReceive(Context context, Intent intent) {
189                 if (Log.isLoggable(TAG, Log.DEBUG)) {
190                     Log.d(TAG, "Received settings change intent: " + intent);
191                 }
192                 injector.reloadStatusMessages();
193             }
194         };
195
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);
200
201         if (appSettings.size() > 0) {
202             addPreferencesSorted(appSettings, categoryAppSettings);
203         } else {
204             // If there's no item to display, remove the whole category.
205             root.removePreference(categoryAppSettings);
206         }
207     }
208
209     @Override
210     public int getHelpResource() {
211         return R.string.help_url_location_access;
212     }
213
214     @Override
215     public void onModeChanged(int mode, boolean restricted) {
216         switch (mode) {
217             case Settings.Secure.LOCATION_MODE_OFF:
218                 mLocationMode.setSummary(R.string.location_mode_location_off_title);
219                 break;
220             case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
221                 mLocationMode.setSummary(R.string.location_mode_sensors_only_title);
222                 break;
223             case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
224                 mLocationMode.setSummary(R.string.location_mode_battery_saving_title);
225                 break;
226             case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
227                 mLocationMode.setSummary(R.string.location_mode_high_accuracy_title);
228                 break;
229             default:
230                 break;
231         }
232
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);
240
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);
245             }
246             mSwitch.setChecked(enabled);
247             if (mValidListener) {
248                 mSwitch.setOnCheckedChangeListener(this);
249             }
250         }
251     }
252
253     /**
254      * Listens to the state change of the location master switch.
255      */
256     @Override
257     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
258         if (isChecked) {
259             setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
260         } else {
261             setLocationMode(Settings.Secure.LOCATION_MODE_OFF);
262         }
263     }
264 }