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