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.Bundle; 25 import android.os.UserManager; 26 import android.provider.Settings; 27 import android.support.v17.preference.LeanbackPreferenceFragment; 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.settingslib.location.RecentLocationApps; 37 import com.android.tv.settings.R; 38 import com.android.tv.settings.device.apps.AppManagementFragment; 39 40 import java.util.ArrayList; 41 import java.util.Collections; 42 import java.util.Comparator; 43 import java.util.List; 44 45 public class LocationFragment extends LeanbackPreferenceFragment implements 46 Preference.OnPreferenceChangeListener { 47 48 private static final String TAG = "LocationFragment"; 49 50 private static final String LOCATION_MODE_WIFI = "wifi"; 51 private static final String LOCATION_MODE_OFF = "off"; 52 53 private static final String KEY_LOCATION_MODE = "locationMode"; 54 55 private static final String MODE_CHANGING_ACTION = 56 "com.android.settings.location.MODE_CHANGING"; 57 private static final String CURRENT_MODE_KEY = "CURRENT_MODE"; 58 private static final String NEW_MODE_KEY = "NEW_MODE"; 59 60 private ListPreference mLocationMode; 61 62 private BroadcastReceiver mReceiver = new BroadcastReceiver() { 63 @Override 64 public void onReceive(Context context, Intent intent) { 65 if (Log.isLoggable(TAG, Log.DEBUG)) { 66 Log.d(TAG, "Received location mode change intent: " + intent); 67 } 68 refreshLocationMode(); 69 } 70 }; 71 newInstance()72 public static LocationFragment newInstance() { 73 return new LocationFragment(); 74 } 75 76 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)77 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 78 final Context themedContext = getPreferenceManager().getContext(); 79 final PreferenceScreen screen = getPreferenceManager().createPreferenceScreen( 80 themedContext); 81 screen.setTitle(R.string.system_location); 82 83 mLocationMode = new ListPreference(themedContext); 84 screen.addPreference(mLocationMode); 85 mLocationMode.setKey(KEY_LOCATION_MODE); 86 mLocationMode.setPersistent(false); 87 mLocationMode.setTitle(R.string.location_status); 88 mLocationMode.setDialogTitle(R.string.location_status); 89 mLocationMode.setSummary("%s"); 90 mLocationMode.setEntries(new CharSequence[] { 91 getString(R.string.location_mode_wifi_description), 92 getString(R.string.off) 93 }); 94 mLocationMode.setEntryValues(new CharSequence[] { 95 LOCATION_MODE_WIFI, 96 LOCATION_MODE_OFF 97 }); 98 mLocationMode.setOnPreferenceChangeListener(this); 99 100 final UserManager um = UserManager.get(getContext()); 101 mLocationMode.setEnabled(!um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION)); 102 103 final PreferenceCategory recentRequests = new PreferenceCategory(themedContext); 104 screen.addPreference(recentRequests); 105 recentRequests.setTitle(R.string.location_category_recent_location_requests); 106 107 List<RecentLocationApps.Request> recentLocationRequests = 108 new RecentLocationApps(themedContext).getAppList(); 109 List<Preference> recentLocationPrefs = new ArrayList<>(recentLocationRequests.size()); 110 for (final RecentLocationApps.Request request : recentLocationRequests) { 111 Preference pref = new Preference(themedContext); 112 pref.setIcon(request.icon); 113 pref.setTitle(request.label); 114 if (request.isHighBattery) { 115 pref.setSummary(R.string.location_high_battery_use); 116 } else { 117 pref.setSummary(R.string.location_low_battery_use); 118 } 119 pref.setFragment(AppManagementFragment.class.getName()); 120 AppManagementFragment.prepareArgs(pref.getExtras(), request.packageName); 121 recentLocationPrefs.add(pref); 122 } 123 124 if (recentLocationRequests.size() > 0) { 125 addPreferencesSorted(recentLocationPrefs, recentRequests); 126 } else { 127 // If there's no item to display, add a "No recent apps" item. 128 Preference banner = new Preference(themedContext); 129 banner.setTitle(R.string.location_no_recent_apps); 130 banner.setSelectable(false); 131 recentRequests.addPreference(banner); 132 } 133 134 // TODO: are location services relevant on TV? 135 136 setPreferenceScreen(screen); 137 } 138 139 @Override onStart()140 public void onStart() { 141 super.onStart(); 142 IntentFilter filter = new IntentFilter(); 143 filter.addAction(LocationManager.MODE_CHANGED_ACTION); 144 getActivity().registerReceiver(mReceiver, filter); 145 refreshLocationMode(); 146 } 147 148 @Override onStop()149 public void onStop() { 150 super.onStop(); 151 try { 152 getActivity().unregisterReceiver(mReceiver); 153 } catch (RuntimeException e) { 154 // Ignore exceptions caused by race condition 155 } 156 } 157 addPreferencesSorted(List<Preference> prefs, PreferenceGroup container)158 private void addPreferencesSorted(List<Preference> prefs, PreferenceGroup container) { 159 // If there's some items to display, sort the items and add them to the container. 160 Collections.sort(prefs, new Comparator<Preference>() { 161 @Override 162 public int compare(Preference lhs, Preference rhs) { 163 return lhs.getTitle().toString().compareTo(rhs.getTitle().toString()); 164 } 165 }); 166 for (Preference entry : prefs) { 167 container.addPreference(entry); 168 } 169 } 170 171 @Override onPreferenceChange(Preference preference, Object newValue)172 public boolean onPreferenceChange(Preference preference, Object newValue) { 173 if (TextUtils.equals(preference.getKey(), KEY_LOCATION_MODE)) { 174 int mode = Settings.Secure.LOCATION_MODE_OFF; 175 if (TextUtils.equals((CharSequence) newValue, LOCATION_MODE_WIFI)) { 176 // TODO 177 // com.google.android.gms/com.google.android.location.network.ConfirmAlertActivity 178 // pops up when we turn this on. 179 mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY; 180 } else if (TextUtils.equals((CharSequence) newValue, LOCATION_MODE_OFF)) { 181 mode = Settings.Secure.LOCATION_MODE_OFF; 182 } else { 183 Log.wtf(TAG, "Tried to set unknown location mode!"); 184 } 185 186 int currentMode = Settings.Secure.getInt(getActivity().getContentResolver(), 187 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); 188 Intent intent = new Intent(MODE_CHANGING_ACTION); 189 intent.putExtra(CURRENT_MODE_KEY, currentMode); 190 intent.putExtra(NEW_MODE_KEY, mode); 191 getActivity().sendBroadcast(intent, android.Manifest.permission.WRITE_SECURE_SETTINGS); 192 Settings.Secure.putInt(getActivity().getContentResolver(), 193 Settings.Secure.LOCATION_MODE, mode); 194 195 refreshLocationMode(); 196 } 197 return true; 198 } 199 refreshLocationMode()200 private void refreshLocationMode() { 201 if (mLocationMode == null) { 202 return; 203 } 204 final int mode = Settings.Secure.getInt(getActivity().getContentResolver(), 205 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); 206 if (mode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY) { 207 mLocationMode.setValue(LOCATION_MODE_WIFI); 208 } else if (mode == Settings.Secure.LOCATION_MODE_OFF) { 209 mLocationMode.setValue(LOCATION_MODE_OFF); 210 } else { 211 Log.d(TAG, "Unknown location mode: " + mode); 212 } 213 } 214 } 215