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