1 /* 2 * Copyright (C) 2016 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.wifi; 18 19 import android.app.Activity; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.DialogInterface; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.pm.ApplicationInfo; 26 import android.content.pm.PackageItemInfo; 27 import android.content.pm.PackageManager; 28 import android.net.wifi.WifiManager; 29 import android.os.Bundle; 30 import android.text.TextUtils; 31 import android.util.Log; 32 import android.widget.Toast; 33 34 import androidx.annotation.NonNull; 35 36 import com.android.internal.app.AlertActivity; 37 import com.android.settings.R; 38 39 /** 40 * This activity handles requests to toggle WiFi by collecting user 41 * consent and waiting until the state change is completed. 42 */ 43 public class RequestToggleWiFiActivity extends AlertActivity 44 implements DialogInterface.OnClickListener { 45 private static final String LOG_TAG = "RequestToggleWiFiActivity"; 46 47 private static final long TOGGLE_TIMEOUT_MILLIS = 10000; // 10 sec 48 49 private static final int STATE_UNKNOWN = -1; 50 private static final int STATE_ENABLE = 1; 51 private static final int STATE_ENABLING = 2; 52 private static final int STATE_DISABLE = 3; 53 private static final int STATE_DISABLING = 4; 54 55 private final StateChangeReceiver mReceiver = new StateChangeReceiver(); 56 57 private final Runnable mTimeoutCommand = () -> { 58 if (!isFinishing() && !isDestroyed()) { 59 finish(); 60 } 61 }; 62 63 private @NonNull WifiManager mWiFiManager; 64 private @NonNull CharSequence mAppLabel; 65 66 private int mState = STATE_UNKNOWN; 67 private int mLastUpdateState = STATE_UNKNOWN; 68 69 @Override onCreate(Bundle savedInstanceState)70 protected void onCreate(Bundle savedInstanceState) { 71 super.onCreate(savedInstanceState); 72 73 mWiFiManager = getSystemService(WifiManager.class); 74 75 setResult(Activity.RESULT_CANCELED); 76 77 String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME); 78 if (TextUtils.isEmpty(packageName)) { 79 finish(); 80 return; 81 } 82 83 try { 84 ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo( 85 packageName, 0); 86 mAppLabel = applicationInfo.loadSafeLabel(getPackageManager(), 87 PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, PackageItemInfo.SAFE_LABEL_FLAG_TRIM 88 | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); 89 } catch (PackageManager.NameNotFoundException e) { 90 Log.e(LOG_TAG, "Couldn't find app with package name " + packageName); 91 finish(); 92 return; 93 } 94 95 String action = getIntent().getAction(); 96 switch (action) { 97 case WifiManager.ACTION_REQUEST_ENABLE: { 98 mState = STATE_ENABLE; 99 } break; 100 101 case WifiManager.ACTION_REQUEST_DISABLE: { 102 mState = STATE_DISABLE; 103 } break; 104 105 default: { 106 finish(); 107 } 108 } 109 } 110 111 @Override onClick(DialogInterface dialog, int which)112 public void onClick(DialogInterface dialog, int which) { 113 switch (which) { 114 case DialogInterface.BUTTON_POSITIVE: { 115 switch (mState) { 116 case STATE_ENABLE: { 117 mWiFiManager.setWifiEnabled(true); 118 mState = STATE_ENABLING; 119 scheduleToggleTimeout(); 120 updateUi(); 121 } break; 122 123 case STATE_DISABLE: { 124 mWiFiManager.setWifiEnabled(false); 125 mState = STATE_DISABLING; 126 scheduleToggleTimeout(); 127 updateUi(); 128 } break; 129 } 130 } 131 break; 132 case DialogInterface.BUTTON_NEGATIVE: { 133 finish(); 134 } 135 break; 136 } 137 } 138 139 @Override onStart()140 protected void onStart() { 141 super.onStart(); 142 143 mReceiver.register(); 144 145 final int wifiState = mWiFiManager.getWifiState(); 146 147 switch (mState) { 148 case STATE_ENABLE: { 149 switch (wifiState) { 150 case WifiManager.WIFI_STATE_ENABLED: { 151 setResult(RESULT_OK); 152 finish(); 153 } return; 154 155 case WifiManager.WIFI_STATE_ENABLING: { 156 mState = STATE_ENABLING; 157 scheduleToggleTimeout(); 158 } break; 159 } 160 } break; 161 162 case STATE_DISABLE: { 163 switch (wifiState) { 164 case WifiManager.WIFI_STATE_DISABLED: { 165 setResult(RESULT_OK); 166 finish(); 167 } 168 return; 169 170 case WifiManager.WIFI_STATE_ENABLING: { 171 mState = STATE_DISABLING; 172 scheduleToggleTimeout(); 173 } 174 break; 175 } 176 } break; 177 178 case STATE_ENABLING: { 179 switch (wifiState) { 180 case WifiManager.WIFI_STATE_ENABLED: { 181 setResult(RESULT_OK); 182 finish(); 183 } return; 184 185 case WifiManager.WIFI_STATE_ENABLING: { 186 scheduleToggleTimeout(); 187 } break; 188 189 case WifiManager.WIFI_STATE_DISABLED: 190 case WifiManager.WIFI_STATE_DISABLING: { 191 mState = STATE_ENABLE; 192 } break; 193 } 194 } break; 195 196 case STATE_DISABLING: { 197 switch (wifiState) { 198 case WifiManager.WIFI_STATE_DISABLED: { 199 setResult(RESULT_OK); 200 finish(); 201 } return; 202 203 case WifiManager.WIFI_STATE_DISABLING: { 204 scheduleToggleTimeout(); 205 } break; 206 207 case WifiManager.WIFI_STATE_ENABLED: 208 case WifiManager.WIFI_STATE_ENABLING: { 209 mState = STATE_DISABLE; 210 } break; 211 } 212 } break; 213 } 214 215 updateUi(); 216 } 217 218 @Override onStop()219 protected void onStop() { 220 mReceiver.unregister(); 221 unscheduleToggleTimeout(); 222 super.onStop(); 223 } 224 updateUi()225 private void updateUi() { 226 if (mLastUpdateState == mState) { 227 return; 228 } 229 mLastUpdateState = mState; 230 231 switch (mState) { 232 case STATE_ENABLE: { 233 mAlertParams.mPositiveButtonText = getString(R.string.allow); 234 mAlertParams.mPositiveButtonListener = this; 235 mAlertParams.mNegativeButtonText = getString(R.string.deny); 236 mAlertParams.mNegativeButtonListener = this; 237 mAlertParams.mMessage = getString(R.string.wifi_ask_enable, mAppLabel); 238 } break; 239 240 case STATE_ENABLING: { 241 // Params set button text only if non-null, but we want a null 242 // button text to hide the button, so reset the controller directly. 243 mAlert.setButton(DialogInterface.BUTTON_POSITIVE, null, null, null); 244 mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, null, null, null); 245 mAlertParams.mPositiveButtonText = null; 246 mAlertParams.mPositiveButtonListener = null; 247 mAlertParams.mNegativeButtonText = null; 248 mAlertParams.mNegativeButtonListener = null; 249 mAlertParams.mMessage = getString(R.string.wifi_starting); 250 } break; 251 252 case STATE_DISABLE: { 253 mAlertParams.mPositiveButtonText = getString(R.string.allow); 254 mAlertParams.mPositiveButtonListener = this; 255 mAlertParams.mNegativeButtonText = getString(R.string.deny); 256 mAlertParams.mNegativeButtonListener = this; 257 mAlertParams.mMessage = getString(R.string.wifi_ask_disable, mAppLabel); 258 } break; 259 260 case STATE_DISABLING: { 261 // Params set button text only if non-null, but we want a null 262 // button text to hide the button, so reset the controller directly. 263 mAlert.setButton(DialogInterface.BUTTON_POSITIVE, null, null, null); 264 mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, null, null, null); 265 mAlertParams.mPositiveButtonText = null; 266 mAlertParams.mPositiveButtonListener = null; 267 mAlertParams.mNegativeButtonText = null; 268 mAlertParams.mNegativeButtonListener = null; 269 mAlertParams.mMessage = getString(R.string.wifi_stopping); 270 } break; 271 } 272 273 setupAlert(); 274 } 275 276 @Override dismiss()277 public void dismiss() { 278 // Clicking on the dialog buttons dismisses the dialog and finishes 279 // the activity but we want to finish after the WiFi state changed. 280 } 281 scheduleToggleTimeout()282 private void scheduleToggleTimeout() { 283 getWindow().getDecorView().postDelayed(mTimeoutCommand, TOGGLE_TIMEOUT_MILLIS); 284 } 285 unscheduleToggleTimeout()286 private void unscheduleToggleTimeout() { 287 getWindow().getDecorView().removeCallbacks(mTimeoutCommand); 288 } 289 290 private final class StateChangeReceiver extends BroadcastReceiver { 291 private final IntentFilter mFilter = new IntentFilter( 292 WifiManager.WIFI_STATE_CHANGED_ACTION); 293 register()294 public void register() { 295 registerReceiver(this, mFilter); 296 } 297 unregister()298 public void unregister() { 299 unregisterReceiver(this); 300 } 301 onReceive(Context context, Intent intent)302 public void onReceive(Context context, Intent intent) { 303 Activity activity = RequestToggleWiFiActivity.this; 304 if (activity.isFinishing() || activity.isDestroyed()) { 305 return; 306 } 307 final int currentState = mWiFiManager.getWifiState(); 308 switch (currentState) { 309 case WifiManager.WIFI_STATE_ENABLED: 310 case WifiManager.WIFI_STATE_DISABLED: { 311 if (mState == STATE_ENABLING || mState == STATE_DISABLING) { 312 RequestToggleWiFiActivity.this.setResult(Activity.RESULT_OK); 313 finish(); 314 } 315 } break; 316 317 case WifiManager.ERROR: { 318 Toast.makeText(activity, R.string.wifi_error, Toast.LENGTH_SHORT).show(); 319 finish(); 320 } break; 321 } 322 } 323 } 324 } 325