• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.tv.settings.system;
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.LocationManager;
24 import android.os.BatteryManager;
25 import android.os.Bundle;
26 import android.os.UserManager;
27 import android.provider.Settings;
28 import android.support.v7.preference.ListPreference;
29 import android.support.v7.preference.Preference;
30 import android.support.v7.preference.PreferenceCategory;
31 import android.support.v7.preference.PreferenceGroup;
32 import android.support.v7.preference.PreferenceScreen;
33 import android.text.TextUtils;
34 import android.util.Log;
35 
36 import com.android.internal.logging.nano.MetricsProto;
37 import com.android.settingslib.location.RecentLocationApps;
38 import com.android.tv.settings.R;
39 import com.android.tv.settings.SettingsPreferenceFragment;
40 import com.android.tv.settings.device.apps.AppManagementFragment;
41 
42 import java.util.ArrayList;
43 import java.util.Comparator;
44 import java.util.List;
45 
46 /**
47  * The location settings screen in TV settings.
48  */
49 public class LocationFragment extends SettingsPreferenceFragment implements
50         Preference.OnPreferenceChangeListener {
51 
52     private static final String TAG = "LocationFragment";
53 
54     private static final String LOCATION_MODE_WIFI = "wifi";
55     private static final String LOCATION_MODE_OFF = "off";
56 
57     private static final String KEY_LOCATION_MODE = "locationMode";
58 
59     private static final String MODE_CHANGING_ACTION =
60             "com.android.settings.location.MODE_CHANGING";
61     private static final String CURRENT_MODE_KEY = "CURRENT_MODE";
62     private static final String NEW_MODE_KEY = "NEW_MODE";
63 
64     private ListPreference mLocationMode;
65 
66     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
67         @Override
68         public void onReceive(Context context, Intent intent) {
69             if (Log.isLoggable(TAG, Log.DEBUG)) {
70                 Log.d(TAG, "Received location mode change intent: " + intent);
71             }
72             refreshLocationMode();
73         }
74     };
75 
newInstance()76     public static LocationFragment newInstance() {
77         return new LocationFragment();
78     }
79 
80     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)81     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
82         final Context themedContext = getPreferenceManager().getContext();
83         final PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(
84                 themedContext);
85         screen.setTitle(R.string.system_location);
86 
87         mLocationMode = new ListPreference(themedContext);
88         screen.addPreference(mLocationMode);
89         mLocationMode.setKey(KEY_LOCATION_MODE);
90         mLocationMode.setPersistent(false);
91         mLocationMode.setTitle(R.string.location_status);
92         mLocationMode.setDialogTitle(R.string.location_status);
93         mLocationMode.setSummary("%s");
94         mLocationMode.setEntries(new CharSequence[] {
95                 getString(R.string.location_mode_wifi_description),
96                 getString(R.string.off)
97         });
98         mLocationMode.setEntryValues(new CharSequence[] {
99                 LOCATION_MODE_WIFI,
100                 LOCATION_MODE_OFF
101         });
102         mLocationMode.setOnPreferenceChangeListener(this);
103 
104         final UserManager um = UserManager.get(getContext());
105         mLocationMode.setEnabled(!um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION));
106 
107         final PreferenceCategory recentRequests = new PreferenceCategory(themedContext);
108         screen.addPreference(recentRequests);
109         recentRequests.setTitle(R.string.location_category_recent_location_requests);
110         recentRequests.setLayoutResource(R.layout.preference_category_compact_layout);
111 
112         List<RecentLocationApps.Request> recentLocationRequests =
113                 new RecentLocationApps(themedContext).getAppList();
114         List<Preference> recentLocationPrefs = new ArrayList<>(recentLocationRequests.size());
115         for (final RecentLocationApps.Request request : recentLocationRequests) {
116             Preference pref = new Preference(themedContext);
117             pref.setIcon(request.icon);
118             pref.setTitle(request.label);
119             // Most Android TV devices don't have built-in batteries and we ONLY show "High/Low
120             // battery use" for devices with built-in batteries when they are not plugged-in.
121             final BatteryManager batteryManager = (BatteryManager) getContext()
122                     .getSystemService(Context.BATTERY_SERVICE);
123             if (batteryManager != null && !batteryManager.isCharging()) {
124                 if (request.isHighBattery) {
125                     pref.setSummary(R.string.location_high_battery_use);
126                 } else {
127                     pref.setSummary(R.string.location_low_battery_use);
128                 }
129             }
130             pref.setFragment(AppManagementFragment.class.getName());
131             AppManagementFragment.prepareArgs(pref.getExtras(), request.packageName);
132             recentLocationPrefs.add(pref);
133         }
134 
135         if (recentLocationRequests.size() > 0) {
136             addPreferencesSorted(recentLocationPrefs, recentRequests);
137         } else {
138             // If there's no item to display, add a "No recent apps" item.
139             Preference banner = new Preference(themedContext);
140             banner.setTitle(R.string.location_no_recent_apps);
141             banner.setSelectable(false);
142             recentRequests.addPreference(banner);
143         }
144 
145         // TODO: are location services relevant on TV?
146 
147         setPreferenceScreen(screen);
148     }
149 
150     // When selecting the location preference, LeanbackPreferenceFragment
151     // creates an inner view with the selection options; that's when we want to
152     // register our receiver, bacause from now on user can change the location
153     // providers.
154     @Override
onCreate(Bundle savedInstanceState)155     public void onCreate(Bundle savedInstanceState) {
156         super.onCreate(savedInstanceState);
157         getActivity().registerReceiver(mReceiver,
158                 new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
159         refreshLocationMode();
160     }
161 
162     @Override
onDestroy()163     public void onDestroy() {
164         super.onDestroy();
165         getActivity().unregisterReceiver(mReceiver);
166     }
167 
addPreferencesSorted(List<Preference> prefs, PreferenceGroup container)168     private void addPreferencesSorted(List<Preference> prefs, PreferenceGroup container) {
169         // If there's some items to display, sort the items and add them to the container.
170         prefs.sort(Comparator.comparing(lhs -> lhs.getTitle().toString()));
171         for (Preference entry : prefs) {
172             container.addPreference(entry);
173         }
174     }
175 
176     @Override
onPreferenceChange(Preference preference, Object newValue)177     public boolean onPreferenceChange(Preference preference, Object newValue) {
178         if (TextUtils.equals(preference.getKey(), KEY_LOCATION_MODE)) {
179             int mode = Settings.Secure.LOCATION_MODE_OFF;
180             if (TextUtils.equals((CharSequence) newValue, LOCATION_MODE_WIFI)) {
181                 mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
182             } else if (TextUtils.equals((CharSequence) newValue, LOCATION_MODE_OFF)) {
183                 mode = Settings.Secure.LOCATION_MODE_OFF;
184             } else {
185                 Log.wtf(TAG, "Tried to set unknown location mode!");
186             }
187 
188             writeLocationMode(mode);
189             refreshLocationMode();
190         }
191         return true;
192     }
193 
writeLocationMode(int mode)194     private void writeLocationMode(int mode) {
195         int currentMode = Settings.Secure.getInt(getActivity().getContentResolver(),
196                 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
197         Intent intent = new Intent(MODE_CHANGING_ACTION);
198         intent.putExtra(CURRENT_MODE_KEY, currentMode);
199         intent.putExtra(NEW_MODE_KEY, mode);
200         getActivity().sendBroadcast(intent, android.Manifest.permission.WRITE_SECURE_SETTINGS);
201         Settings.Secure.putInt(getActivity().getContentResolver(),
202                 Settings.Secure.LOCATION_MODE, mode);
203     }
204 
refreshLocationMode()205     private void refreshLocationMode() {
206         if (mLocationMode == null) {
207             return;
208         }
209         final int mode = Settings.Secure.getInt(getActivity().getContentResolver(),
210                 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
211         if (mode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
212                     || mode == Settings.Secure.LOCATION_MODE_BATTERY_SAVING) {
213             mLocationMode.setValue(LOCATION_MODE_WIFI);
214         } else if (mode == Settings.Secure.LOCATION_MODE_OFF) {
215             mLocationMode.setValue(LOCATION_MODE_OFF);
216         } else if (mode == Settings.Secure.LOCATION_MODE_SENSORS_ONLY) {
217             writeLocationMode(Settings.Secure.LOCATION_MODE_OFF);
218             mLocationMode.setValue(LOCATION_MODE_OFF);
219         } else {
220             Log.d(TAG, "Unknown location mode: " + mode);
221         }
222     }
223 
224     @Override
getMetricsCategory()225     public int getMetricsCategory() {
226         return MetricsProto.MetricsEvent.LOCATION;
227     }
228 }
229