1 /* 2 * Copyright (C) 2018 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.ProgressDialog; 20 import android.content.Intent; 21 import android.net.wifi.ScanResult; 22 import android.net.wifi.WifiConfiguration; 23 import android.net.wifi.WifiInfo; 24 import android.net.wifi.WifiManager; 25 import android.net.wifi.WifiManager.NetworkRequestMatchCallback; 26 import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback; 27 import android.os.Bundle; 28 import android.os.Handler; 29 import android.os.HandlerExecutor; 30 import android.os.Message; 31 import android.widget.Toast; 32 33 import androidx.annotation.Nullable; 34 import androidx.annotation.VisibleForTesting; 35 import androidx.fragment.app.FragmentActivity; 36 37 import com.android.settings.R; 38 import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE; 39 40 import java.util.List; 41 42 /** 43 * When other applications request to have a wifi connection, framework will bring up this activity 44 * to let user select which wifi ap wanna to connect. This activity contains 45 * {@code NetworkRequestDialogFragment}, {@code NetworkRequestSingleSsidDialogFragment} to show UI 46 * and handles framework callback. 47 */ 48 public class NetworkRequestDialogActivity extends FragmentActivity implements 49 NetworkRequestMatchCallback { 50 private static String TAG = "NetworkRequestDialogActivity"; 51 52 /** Message sent to stop scanning wifi and pop up timeout dialog. */ 53 private static final int MESSAGE_STOP_SCAN_WIFI_LIST = 0; 54 55 /** Delayed time to stop scanning wifi. */ 56 private static final int DELAY_TIME_STOP_SCAN_MS = 30 * 1000; 57 58 final static String EXTRA_IS_SPECIFIED_SSID = 59 "com.android.settings.wifi.extra.REQUEST_IS_FOR_SINGLE_NETWORK"; 60 61 @VisibleForTesting 62 NetworkRequestDialogBaseFragment mDialogFragment; 63 @VisibleForTesting 64 boolean mIsSpecifiedSsid; 65 @VisibleForTesting 66 boolean mShowingErrorDialog; 67 @VisibleForTesting 68 ProgressDialog mProgressDialog; 69 70 private NetworkRequestUserSelectionCallback mUserSelectionCallback; 71 private WifiConfiguration mMatchedConfig; 72 73 @Override onCreate(@ullable Bundle savedInstanceState)74 protected void onCreate(@Nullable Bundle savedInstanceState) { 75 super.onCreate(savedInstanceState); 76 77 final Intent intent = getIntent(); 78 if (intent != null) { 79 mIsSpecifiedSsid = intent.getBooleanExtra(EXTRA_IS_SPECIFIED_SSID, false); 80 } 81 82 if (mIsSpecifiedSsid) { 83 showProgressDialog(getString(R.string.network_connection_searching_message)); 84 } else { 85 mDialogFragment = NetworkRequestDialogFragment.newInstance(); 86 mDialogFragment.show(getSupportFragmentManager(), TAG); 87 } 88 } 89 showProgressDialog(String message)90 private void showProgressDialog(String message) { 91 dismissDialogs(); 92 93 mProgressDialog = new ProgressDialog(this); 94 mProgressDialog.setIndeterminate(true); 95 mProgressDialog.setCancelable(false); 96 mProgressDialog.setMessage(message); 97 mProgressDialog.show(); 98 } 99 showSingleSsidRequestDialog(String ssid, boolean isTryAgain)100 private void showSingleSsidRequestDialog(String ssid, boolean isTryAgain) { 101 dismissDialogs(); 102 103 mDialogFragment = new NetworkRequestSingleSsidDialogFragment(); 104 final Bundle bundle = new Bundle(); 105 bundle.putString(NetworkRequestSingleSsidDialogFragment.EXTRA_SSID, ssid); 106 bundle.putBoolean(NetworkRequestSingleSsidDialogFragment.EXTRA_TRYAGAIN, isTryAgain); 107 mDialogFragment.setArguments(bundle); 108 mDialogFragment.show(getSupportFragmentManager(), TAG); 109 } 110 111 @VisibleForTesting dismissDialogs()112 void dismissDialogs() { 113 if (mDialogFragment != null) { 114 mDialogFragment.dismiss(); 115 mDialogFragment = null; 116 } 117 if (mProgressDialog != null) { 118 mProgressDialog.dismiss(); 119 mProgressDialog = null; 120 } 121 } 122 123 @Override onResume()124 protected void onResume() { 125 super.onResume(); 126 127 final WifiManager wifiManager = getSystemService(WifiManager.class); 128 if (wifiManager != null) { 129 wifiManager.registerNetworkRequestMatchCallback(new HandlerExecutor(mHandler), this); 130 } 131 // Sets time-out to stop scanning. 132 mHandler.sendEmptyMessageDelayed(MESSAGE_STOP_SCAN_WIFI_LIST, DELAY_TIME_STOP_SCAN_MS); 133 } 134 135 @Override onPause()136 protected void onPause() { 137 mHandler.removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST); 138 final WifiManager wifiManager = getSystemService(WifiManager.class); 139 if (wifiManager != null) { 140 wifiManager.unregisterNetworkRequestMatchCallback(this); 141 } 142 143 super.onPause(); 144 } 145 146 private final Handler mHandler = new Handler() { 147 @Override 148 public void handleMessage(Message msg) { 149 switch (msg.what) { 150 case MESSAGE_STOP_SCAN_WIFI_LIST: 151 removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST); 152 stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.TIME_OUT); 153 break; 154 default: 155 // Do nothing. 156 break; 157 } 158 } 159 }; 160 stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE type)161 protected void stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE type) { 162 dismissDialogs(); 163 164 // Throws error dialog. 165 final NetworkRequestErrorDialogFragment dialogFragment = 166 NetworkRequestErrorDialogFragment.newInstance(); 167 dialogFragment.setRejectCallback(mUserSelectionCallback); 168 final Bundle bundle = new Bundle(); 169 bundle.putSerializable(NetworkRequestErrorDialogFragment.DIALOG_TYPE, type); 170 dialogFragment.setArguments(bundle); 171 dialogFragment.show(getSupportFragmentManager(), TAG); 172 mShowingErrorDialog = true; 173 } 174 175 @Override onUserSelectionCallbackRegistration( NetworkRequestUserSelectionCallback userSelectionCallback)176 public void onUserSelectionCallbackRegistration( 177 NetworkRequestUserSelectionCallback userSelectionCallback) { 178 if (mIsSpecifiedSsid) { 179 mUserSelectionCallback = userSelectionCallback; 180 return; 181 } 182 183 if (mDialogFragment != null) { 184 mDialogFragment.onUserSelectionCallbackRegistration(userSelectionCallback); 185 } 186 } 187 188 @Override onAbort()189 public void onAbort() { 190 stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.ABORT); 191 } 192 193 @Override onMatch(List<ScanResult> scanResults)194 public void onMatch(List<ScanResult> scanResults) { 195 if (mShowingErrorDialog) { 196 // Don't do anything since error dialog shows. 197 return; 198 } 199 200 mHandler.removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST); 201 202 if (mIsSpecifiedSsid) { 203 // Prevent from throwing same dialog, because onMatch() will be called many times. 204 if (mMatchedConfig == null) { 205 mMatchedConfig = WifiUtils.getWifiConfig(null /* wifiEntry */, scanResults.get(0)); 206 showSingleSsidRequestDialog( 207 WifiInfo.sanitizeSsid(mMatchedConfig.SSID), false /* isTryAgain */); 208 } 209 return; 210 } 211 212 if (mDialogFragment != null) { 213 mDialogFragment.onMatch(scanResults); 214 } 215 } 216 217 @Override onUserSelectionConnectSuccess(WifiConfiguration wificonfiguration)218 public void onUserSelectionConnectSuccess(WifiConfiguration wificonfiguration) { 219 if (!isFinishing()) { 220 Toast.makeText(this, R.string.network_connection_connect_successful, Toast.LENGTH_SHORT) 221 .show(); 222 setResult(RESULT_OK); 223 finish(); 224 } 225 } 226 227 @Override onUserSelectionConnectFailure(WifiConfiguration wificonfiguration)228 public void onUserSelectionConnectFailure(WifiConfiguration wificonfiguration) { 229 if (!isFinishing()) { 230 Toast.makeText(this, R.string.network_connection_connect_failure, Toast.LENGTH_SHORT) 231 .show(); 232 setResult(RESULT_OK); 233 finish(); 234 } 235 } 236 237 // Called when user click "Connect" button. Called by 238 // {@code NetworkRequestSingleSsidDialogFragment}. onClickConnectButton()239 public void onClickConnectButton() { 240 if (mUserSelectionCallback != null) { 241 mUserSelectionCallback.select(mMatchedConfig); 242 showProgressDialog(getString(R.string.network_connection_connecting_message)); 243 } 244 } 245 246 // Called when user click retry button. Called by {@link NetworkRequestErrorDialogFragment}. onClickRescanButton()247 public void onClickRescanButton() { 248 // Sets time-out to stop scanning. 249 mHandler.sendEmptyMessageDelayed(MESSAGE_STOP_SCAN_WIFI_LIST, DELAY_TIME_STOP_SCAN_MS); 250 251 mShowingErrorDialog = false; 252 253 if (mIsSpecifiedSsid) { 254 mMatchedConfig = null; 255 showProgressDialog(getString(R.string.network_connection_searching_message)); 256 } else { 257 mDialogFragment = NetworkRequestDialogFragment.newInstance(); 258 mDialogFragment.show(getSupportFragmentManager(), TAG); 259 } 260 } 261 262 // Called when user click cancel button. onCancel()263 public void onCancel() { 264 dismissDialogs(); 265 266 if (mUserSelectionCallback != null) { 267 mUserSelectionCallback.reject(); 268 } 269 finish(); 270 } 271 } 272