Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 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; |
| 18 | |
| 19 | import android.app.Activity; |
| 20 | import android.app.AlarmManager; |
| 21 | import android.app.PendingIntent; |
| 22 | import android.app.Service; |
Jeremy Klein | b04fae2 | 2016-07-29 19:22:21 -0700 | [diff] [blame] | 23 | import android.app.usage.UsageStatsManager; |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 24 | import android.bluetooth.BluetoothAdapter; |
| 25 | import android.bluetooth.BluetoothPan; |
| 26 | import android.bluetooth.BluetoothProfile; |
| 27 | import android.bluetooth.BluetoothProfile.ServiceListener; |
| 28 | import android.content.BroadcastReceiver; |
| 29 | import android.content.Context; |
| 30 | import android.content.Intent; |
| 31 | import android.content.IntentFilter; |
| 32 | import android.content.SharedPreferences; |
Jeremy Klein | b04fae2 | 2016-07-29 19:22:21 -0700 | [diff] [blame] | 33 | import android.content.pm.PackageManager; |
| 34 | import android.content.pm.ResolveInfo; |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 35 | import android.net.ConnectivityManager; |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 36 | import android.os.IBinder; |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 37 | import android.os.ResultReceiver; |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 38 | import android.os.SystemClock; |
| 39 | import android.text.TextUtils; |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 40 | import android.util.ArrayMap; |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 41 | import android.util.Log; |
| 42 | |
Jeremy Klein | f6b6713 | 2016-02-01 18:58:57 -0800 | [diff] [blame] | 43 | import com.android.internal.annotations.VisibleForTesting; |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 44 | |
| 45 | import java.util.ArrayList; |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 46 | import java.util.List; |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 47 | |
| 48 | public class TetherService extends Service { |
| 49 | private static final String TAG = "TetherService"; |
| 50 | private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); |
| 51 | |
Jeremy Klein | f6b6713 | 2016-02-01 18:58:57 -0800 | [diff] [blame] | 52 | @VisibleForTesting |
| 53 | public static final String EXTRA_RESULT = "EntitlementResult"; |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 54 | |
| 55 | // Activity results to match the activity provision protocol. |
| 56 | // Default to something not ok. |
| 57 | private static final int RESULT_DEFAULT = Activity.RESULT_CANCELED; |
| 58 | private static final int RESULT_OK = Activity.RESULT_OK; |
| 59 | |
| 60 | private static final String TETHER_CHOICE = "TETHER_TYPE"; |
| 61 | private static final int MS_PER_HOUR = 60 * 60 * 1000; |
| 62 | |
| 63 | private static final String PREFS = "tetherPrefs"; |
| 64 | private static final String KEY_TETHERS = "currentTethers"; |
| 65 | |
| 66 | private int mCurrentTypeIndex; |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 67 | private boolean mInProvisionCheck; |
Jeremy Klein | b04fae2 | 2016-07-29 19:22:21 -0700 | [diff] [blame] | 68 | private UsageStatsManagerWrapper mUsageManagerWrapper; |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 69 | private ArrayList<Integer> mCurrentTethers; |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 70 | private ArrayMap<Integer, List<ResultReceiver>> mPendingCallbacks; |
Doris Ling | f94401b | 2017-03-30 14:40:25 -0700 | [diff] [blame] | 71 | private HotspotOffReceiver mHotspotReceiver; |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 72 | |
| 73 | @Override |
| 74 | public IBinder onBind(Intent intent) { |
| 75 | return null; |
| 76 | } |
| 77 | |
| 78 | @Override |
| 79 | public void onCreate() { |
| 80 | super.onCreate(); |
Jason Monk | 359170f | 2015-09-01 13:20:55 -0400 | [diff] [blame] | 81 | if (DEBUG) Log.d(TAG, "Creating TetherService"); |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 82 | String provisionResponse = getResources().getString( |
| 83 | com.android.internal.R.string.config_mobile_hotspot_provision_response); |
| 84 | registerReceiver(mReceiver, new IntentFilter(provisionResponse), |
| 85 | android.Manifest.permission.CONNECTIVITY_INTERNAL, null); |
| 86 | SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); |
| 87 | mCurrentTethers = stringToTethers(prefs.getString(KEY_TETHERS, "")); |
| 88 | mCurrentTypeIndex = 0; |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 89 | mPendingCallbacks = new ArrayMap<>(3); |
| 90 | mPendingCallbacks.put(ConnectivityManager.TETHERING_WIFI, new ArrayList<ResultReceiver>()); |
| 91 | mPendingCallbacks.put(ConnectivityManager.TETHERING_USB, new ArrayList<ResultReceiver>()); |
| 92 | mPendingCallbacks.put( |
| 93 | ConnectivityManager.TETHERING_BLUETOOTH, new ArrayList<ResultReceiver>()); |
Jeremy Klein | b04fae2 | 2016-07-29 19:22:21 -0700 | [diff] [blame] | 94 | if (mUsageManagerWrapper == null) { |
| 95 | mUsageManagerWrapper = new UsageStatsManagerWrapper(this); |
| 96 | } |
Doris Ling | f94401b | 2017-03-30 14:40:25 -0700 | [diff] [blame] | 97 | mHotspotReceiver = new HotspotOffReceiver(this); |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 98 | } |
| 99 | |
| 100 | @Override |
| 101 | public int onStartCommand(Intent intent, int flags, int startId) { |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 102 | if (intent.hasExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE)) { |
| 103 | int type = intent.getIntExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, |
| 104 | ConnectivityManager.TETHERING_INVALID); |
| 105 | ResultReceiver callback = |
| 106 | intent.getParcelableExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK); |
| 107 | if (callback != null) { |
| 108 | List<ResultReceiver> callbacksForType = mPendingCallbacks.get(type); |
| 109 | if (callbacksForType != null) { |
| 110 | callbacksForType.add(callback); |
| 111 | } else { |
| 112 | // Invalid tether type. Just ignore this request and report failure. |
| 113 | callback.send(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE, null); |
| 114 | stopSelf(); |
| 115 | return START_NOT_STICKY; |
| 116 | } |
| 117 | } |
| 118 | |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 119 | if (!mCurrentTethers.contains(type)) { |
| 120 | if (DEBUG) Log.d(TAG, "Adding tether " + type); |
| 121 | mCurrentTethers.add(type); |
| 122 | } |
| 123 | } |
Hyejin | 5565b5c | 2015-09-10 23:26:53 -0700 | [diff] [blame] | 124 | |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 125 | if (intent.hasExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE)) { |
Hyejin | 5565b5c | 2015-09-10 23:26:53 -0700 | [diff] [blame] | 126 | if (!mInProvisionCheck) { |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 127 | int type = intent.getIntExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE, |
| 128 | ConnectivityManager.TETHERING_INVALID); |
Hyejin | 5565b5c | 2015-09-10 23:26:53 -0700 | [diff] [blame] | 129 | int index = mCurrentTethers.indexOf(type); |
| 130 | if (DEBUG) Log.d(TAG, "Removing tether " + type + ", index " + index); |
| 131 | if (index >= 0) { |
Jeremy Klein | e3e7b95 | 2016-01-25 14:43:49 -0800 | [diff] [blame] | 132 | removeTypeAtIndex(index); |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 133 | } |
Hyejin | 5565b5c | 2015-09-10 23:26:53 -0700 | [diff] [blame] | 134 | cancelAlarmIfNecessary(); |
| 135 | } else { |
| 136 | if (DEBUG) Log.d(TAG, "Don't cancel alarm during provisioning"); |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 137 | } |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 138 | } |
Hyejin | 5565b5c | 2015-09-10 23:26:53 -0700 | [diff] [blame] | 139 | |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 140 | // Only set the alarm if we have one tether, meaning the one just added, |
| 141 | // to avoid setting it when it was already set previously for another |
| 142 | // type. |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 143 | if (intent.getBooleanExtra(ConnectivityManager.EXTRA_SET_ALARM, false) |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 144 | && mCurrentTethers.size() == 1) { |
| 145 | scheduleAlarm(); |
| 146 | } |
| 147 | |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 148 | if (intent.getBooleanExtra(ConnectivityManager.EXTRA_RUN_PROVISION, false)) { |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 149 | startProvisioning(mCurrentTypeIndex); |
| 150 | } else if (!mInProvisionCheck) { |
| 151 | // If we aren't running any provisioning, no reason to stay alive. |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 152 | if (DEBUG) Log.d(TAG, "Stopping self. startid: " + startId); |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 153 | stopSelf(); |
| 154 | return START_NOT_STICKY; |
| 155 | } |
| 156 | // We want to be started if we are killed accidently, so that we can be sure we finish |
| 157 | // the check. |
Jason Monk | 09ea972 | 2015-09-03 12:48:25 -0400 | [diff] [blame] | 158 | return START_REDELIVER_INTENT; |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 159 | } |
| 160 | |
| 161 | @Override |
| 162 | public void onDestroy() { |
| 163 | if (mInProvisionCheck) { |
| 164 | Log.e(TAG, "TetherService getting destroyed while mid-provisioning" |
| 165 | + mCurrentTethers.get(mCurrentTypeIndex)); |
| 166 | } |
| 167 | SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); |
| 168 | prefs.edit().putString(KEY_TETHERS, tethersToString(mCurrentTethers)).commit(); |
| 169 | |
Jason Monk | 359170f | 2015-09-01 13:20:55 -0400 | [diff] [blame] | 170 | if (DEBUG) Log.d(TAG, "Destroying TetherService"); |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 171 | unregisterReceiver(mReceiver); |
| 172 | super.onDestroy(); |
| 173 | } |
| 174 | |
Jeremy Klein | e3e7b95 | 2016-01-25 14:43:49 -0800 | [diff] [blame] | 175 | private void removeTypeAtIndex(int index) { |
| 176 | mCurrentTethers.remove(index); |
| 177 | // If we are currently in the middle of a check, we may need to adjust the |
| 178 | // index accordingly. |
| 179 | if (DEBUG) Log.d(TAG, "mCurrentTypeIndex: " + mCurrentTypeIndex); |
| 180 | if (index <= mCurrentTypeIndex && mCurrentTypeIndex > 0) { |
| 181 | mCurrentTypeIndex--; |
| 182 | } |
| 183 | } |
| 184 | |
Doris Ling | f94401b | 2017-03-30 14:40:25 -0700 | [diff] [blame] | 185 | @VisibleForTesting |
| 186 | void setHotspotOffReceiver(HotspotOffReceiver receiver) { |
| 187 | mHotspotReceiver = receiver; |
| 188 | } |
| 189 | |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 190 | private ArrayList<Integer> stringToTethers(String tethersStr) { |
| 191 | ArrayList<Integer> ret = new ArrayList<Integer>(); |
| 192 | if (TextUtils.isEmpty(tethersStr)) return ret; |
| 193 | |
| 194 | String[] tethersSplit = tethersStr.split(","); |
| 195 | for (int i = 0; i < tethersSplit.length; i++) { |
| 196 | ret.add(Integer.parseInt(tethersSplit[i])); |
| 197 | } |
| 198 | return ret; |
| 199 | } |
| 200 | |
| 201 | private String tethersToString(ArrayList<Integer> tethers) { |
| 202 | final StringBuffer buffer = new StringBuffer(); |
| 203 | final int N = tethers.size(); |
| 204 | for (int i = 0; i < N; i++) { |
| 205 | if (i != 0) { |
| 206 | buffer.append(','); |
| 207 | } |
| 208 | buffer.append(tethers.get(i)); |
| 209 | } |
| 210 | |
| 211 | return buffer.toString(); |
| 212 | } |
| 213 | |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 214 | private void disableWifiTethering() { |
Christopher Wiley | 9d25127 | 2016-07-18 11:16:15 -0700 | [diff] [blame] | 215 | ConnectivityManager cm = |
| 216 | (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); |
| 217 | cm.stopTethering(ConnectivityManager.TETHERING_WIFI); |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 218 | } |
| 219 | |
| 220 | private void disableUsbTethering() { |
| 221 | ConnectivityManager cm = |
| 222 | (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); |
| 223 | cm.setUsbTethering(false); |
| 224 | } |
| 225 | |
| 226 | private void disableBtTethering() { |
| 227 | final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); |
| 228 | if (adapter != null) { |
| 229 | adapter.getProfileProxy(this, new ServiceListener() { |
| 230 | @Override |
| 231 | public void onServiceDisconnected(int profile) { } |
| 232 | |
| 233 | @Override |
| 234 | public void onServiceConnected(int profile, BluetoothProfile proxy) { |
| 235 | ((BluetoothPan) proxy).setBluetoothTethering(false); |
| 236 | adapter.closeProfileProxy(BluetoothProfile.PAN, proxy); |
| 237 | } |
| 238 | }, BluetoothProfile.PAN); |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | private void startProvisioning(int index) { |
Hyejin | 5565b5c | 2015-09-10 23:26:53 -0700 | [diff] [blame] | 243 | if (index < mCurrentTethers.size()) { |
Jeremy Klein | b04fae2 | 2016-07-29 19:22:21 -0700 | [diff] [blame] | 244 | Intent intent = getProvisionBroadcastIntent(index); |
| 245 | setEntitlementAppActive(index); |
| 246 | |
| 247 | if (DEBUG) Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction() |
| 248 | + " type: " + mCurrentTethers.get(index)); |
Jeremy Klein | e3e7b95 | 2016-01-25 14:43:49 -0800 | [diff] [blame] | 249 | |
Hyejin | 5565b5c | 2015-09-10 23:26:53 -0700 | [diff] [blame] | 250 | sendBroadcast(intent); |
| 251 | mInProvisionCheck = true; |
| 252 | } |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 253 | } |
| 254 | |
Jeremy Klein | b04fae2 | 2016-07-29 19:22:21 -0700 | [diff] [blame] | 255 | private Intent getProvisionBroadcastIntent(int index) { |
| 256 | String provisionAction = getResources().getString( |
| 257 | com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui); |
| 258 | Intent intent = new Intent(provisionAction); |
| 259 | int type = mCurrentTethers.get(index); |
| 260 | intent.putExtra(TETHER_CHOICE, type); |
Christopher Tate | 9ea3dcb | 2017-02-22 11:10:10 -0800 | [diff] [blame] | 261 | intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND |
| 262 | | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); |
Jeremy Klein | b04fae2 | 2016-07-29 19:22:21 -0700 | [diff] [blame] | 263 | |
| 264 | return intent; |
| 265 | } |
| 266 | |
| 267 | private void setEntitlementAppActive(int index) { |
| 268 | final PackageManager packageManager = getPackageManager(); |
| 269 | Intent intent = getProvisionBroadcastIntent(index); |
| 270 | List<ResolveInfo> resolvers = |
| 271 | packageManager.queryBroadcastReceivers(intent, PackageManager.MATCH_ALL); |
| 272 | if (resolvers.isEmpty()) { |
| 273 | Log.e(TAG, "No found BroadcastReceivers for provision intent."); |
| 274 | return; |
| 275 | } |
| 276 | |
| 277 | for (ResolveInfo resolver : resolvers) { |
| 278 | if (resolver.activityInfo.applicationInfo.isSystemApp()) { |
| 279 | String packageName = resolver.activityInfo.packageName; |
| 280 | mUsageManagerWrapper.setAppInactive(packageName, false); |
| 281 | } |
| 282 | } |
| 283 | } |
| 284 | |
Doris Ling | f94401b | 2017-03-30 14:40:25 -0700 | [diff] [blame] | 285 | @VisibleForTesting |
| 286 | void scheduleAlarm() { |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 287 | Intent intent = new Intent(this, TetherService.class); |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 288 | intent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true); |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 289 | |
| 290 | PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0); |
| 291 | AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); |
| 292 | int period = getResources().getInteger( |
| 293 | com.android.internal.R.integer.config_mobile_hotspot_provision_check_period); |
| 294 | long periodMs = period * MS_PER_HOUR; |
| 295 | long firstTime = SystemClock.elapsedRealtime() + periodMs; |
| 296 | if (DEBUG) Log.d(TAG, "Scheduling alarm at interval " + periodMs); |
| 297 | alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, firstTime, periodMs, |
| 298 | pendingIntent); |
Doris Ling | f94401b | 2017-03-30 14:40:25 -0700 | [diff] [blame] | 299 | mHotspotReceiver.register(); |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 300 | } |
| 301 | |
| 302 | /** |
| 303 | * Cancels the recheck alarm only if no tethering is currently active. |
| 304 | * |
| 305 | * Runs in the background, to get access to bluetooth service that takes time to bind. |
| 306 | */ |
| 307 | public static void cancelRecheckAlarmIfNecessary(final Context context, int type) { |
| 308 | Intent intent = new Intent(context, TetherService.class); |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 309 | intent.putExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE, type); |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 310 | context.startService(intent); |
| 311 | } |
| 312 | |
Doris Ling | f94401b | 2017-03-30 14:40:25 -0700 | [diff] [blame] | 313 | @VisibleForTesting |
| 314 | void cancelAlarmIfNecessary() { |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 315 | if (mCurrentTethers.size() != 0) { |
| 316 | if (DEBUG) Log.d(TAG, "Tethering still active, not cancelling alarm"); |
| 317 | return; |
| 318 | } |
| 319 | Intent intent = new Intent(this, TetherService.class); |
| 320 | PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0); |
| 321 | AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); |
| 322 | alarmManager.cancel(pendingIntent); |
| 323 | if (DEBUG) Log.d(TAG, "Tethering no longer active, canceling recheck"); |
Doris Ling | f94401b | 2017-03-30 14:40:25 -0700 | [diff] [blame] | 324 | mHotspotReceiver.unregister(); |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 325 | } |
| 326 | |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 327 | private void fireCallbacksForType(int type, int result) { |
| 328 | List<ResultReceiver> callbacksForType = mPendingCallbacks.get(type); |
| 329 | if (callbacksForType == null) { |
| 330 | return; |
| 331 | } |
| 332 | int errorCode = result == RESULT_OK ? ConnectivityManager.TETHER_ERROR_NO_ERROR : |
| 333 | ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; |
| 334 | for (ResultReceiver callback : callbacksForType) { |
| 335 | if (DEBUG) Log.d(TAG, "Firing result: " + errorCode + " to callback"); |
| 336 | callback.send(errorCode, null); |
| 337 | } |
| 338 | callbacksForType.clear(); |
| 339 | } |
| 340 | |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 341 | private final BroadcastReceiver mReceiver = new BroadcastReceiver() { |
| 342 | @Override |
| 343 | public void onReceive(Context context, Intent intent) { |
| 344 | if (DEBUG) Log.d(TAG, "Got provision result " + intent); |
Jeremy Klein | f6b6713 | 2016-02-01 18:58:57 -0800 | [diff] [blame] | 345 | String provisionResponse = getResources().getString( |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 346 | com.android.internal.R.string.config_mobile_hotspot_provision_response); |
Hyejin | 5565b5c | 2015-09-10 23:26:53 -0700 | [diff] [blame] | 347 | |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 348 | if (provisionResponse.equals(intent.getAction())) { |
Jason Monk | 359170f | 2015-09-01 13:20:55 -0400 | [diff] [blame] | 349 | if (!mInProvisionCheck) { |
| 350 | Log.e(TAG, "Unexpected provision response " + intent); |
| 351 | return; |
| 352 | } |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 353 | int checkType = mCurrentTethers.get(mCurrentTypeIndex); |
Hyejin | 5565b5c | 2015-09-10 23:26:53 -0700 | [diff] [blame] | 354 | mInProvisionCheck = false; |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 355 | int result = intent.getIntExtra(EXTRA_RESULT, RESULT_DEFAULT); |
| 356 | if (result != RESULT_OK) { |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 357 | switch (checkType) { |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 358 | case ConnectivityManager.TETHERING_WIFI: |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 359 | disableWifiTethering(); |
| 360 | break; |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 361 | case ConnectivityManager.TETHERING_BLUETOOTH: |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 362 | disableBtTethering(); |
| 363 | break; |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 364 | case ConnectivityManager.TETHERING_USB: |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 365 | disableUsbTethering(); |
| 366 | break; |
| 367 | } |
| 368 | } |
Jeremy Klein | 8a93476 | 2016-01-22 16:14:05 -0800 | [diff] [blame] | 369 | fireCallbacksForType(checkType, result); |
Hyejin | 5565b5c | 2015-09-10 23:26:53 -0700 | [diff] [blame] | 370 | |
| 371 | if (++mCurrentTypeIndex >= mCurrentTethers.size()) { |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 372 | // We are done with all checks, time to die. |
| 373 | stopSelf(); |
| 374 | } else { |
| 375 | // Start the next check in our list. |
| 376 | startProvisioning(mCurrentTypeIndex); |
| 377 | } |
| 378 | } |
| 379 | } |
| 380 | }; |
| 381 | |
Jeremy Klein | b04fae2 | 2016-07-29 19:22:21 -0700 | [diff] [blame] | 382 | @VisibleForTesting |
| 383 | void setUsageStatsManagerWrapper(UsageStatsManagerWrapper wrapper) { |
| 384 | mUsageManagerWrapper = wrapper; |
| 385 | } |
| 386 | |
| 387 | /** |
| 388 | * A static helper class used for tests. UsageStatsManager cannot be mocked out becasue |
| 389 | * it's marked final. This class can be mocked out instead. |
| 390 | */ |
| 391 | @VisibleForTesting |
| 392 | public static class UsageStatsManagerWrapper { |
| 393 | private final UsageStatsManager mUsageStatsManager; |
| 394 | |
| 395 | UsageStatsManagerWrapper(Context context) { |
| 396 | mUsageStatsManager = (UsageStatsManager) |
| 397 | context.getSystemService(Context.USAGE_STATS_SERVICE); |
| 398 | } |
| 399 | |
| 400 | void setAppInactive(String packageName, boolean isInactive) { |
| 401 | mUsageStatsManager.setAppInactive(packageName, isInactive); |
| 402 | } |
| 403 | } |
Jason Monk | 37832d6 | 2014-12-10 17:21:51 -0500 | [diff] [blame] | 404 | } |