| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.settings.wifi.dpp; |
| |
| import android.app.Activity; |
| import android.app.settings.SettingsEnums; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.graphics.Matrix; |
| import android.graphics.Rect; |
| import android.graphics.SurfaceTexture; |
| import android.net.wifi.EasyConnectStatusCallback; |
| import android.net.wifi.WifiConfiguration; |
| import android.net.wifi.WifiManager; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.text.TextUtils; |
| import android.util.Log; |
| import android.util.Size; |
| import android.view.LayoutInflater; |
| import android.view.Menu; |
| import android.view.MenuInflater; |
| import android.view.TextureView; |
| import android.view.TextureView.SurfaceTextureListener; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.accessibility.AccessibilityEvent; |
| import android.widget.TextView; |
| |
| import androidx.annotation.StringRes; |
| import androidx.annotation.UiThread; |
| import androidx.annotation.VisibleForTesting; |
| import androidx.lifecycle.ViewModelProviders; |
| |
| import com.android.settings.R; |
| import com.android.settings.wifi.WifiDialogActivity; |
| import com.android.settings.wifi.qrcode.QrCamera; |
| import com.android.settings.wifi.qrcode.QrDecorateView; |
| |
| import com.android.settingslib.wifi.AccessPoint; |
| import com.android.settingslib.wifi.WifiTracker; |
| import com.android.settingslib.wifi.WifiTrackerFactory; |
| |
| import java.util.List; |
| |
| public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment implements |
| SurfaceTextureListener, |
| QrCamera.ScannerCallback, |
| WifiManager.ActionListener, |
| WifiTracker.WifiListener { |
| private static final String TAG = "WifiDppQrCodeScanner"; |
| |
| /** Message sent to hide error message */ |
| private static final int MESSAGE_HIDE_ERROR_MESSAGE = 1; |
| |
| /** Message sent to show error message */ |
| private static final int MESSAGE_SHOW_ERROR_MESSAGE = 2; |
| |
| /** Message sent to manipulate Wi-Fi DPP QR code */ |
| private static final int MESSAGE_SCAN_WIFI_DPP_SUCCESS = 3; |
| |
| /** Message sent to manipulate ZXing Wi-Fi QR code */ |
| private static final int MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS = 4; |
| |
| private static final long SHOW_ERROR_MESSAGE_INTERVAL = 10000; |
| private static final long SHOW_SUCCESS_SQUARE_INTERVAL = 1000; |
| |
| // Key for Bundle usage |
| private static final String KEY_IS_CONFIGURATOR_MODE = "key_is_configurator_mode"; |
| private static final String KEY_LATEST_ERROR_CODE = "key_latest_error_code"; |
| private static final String KEY_WIFI_CONFIGURATION = "key_wifi_configuration"; |
| |
| private static final int ARG_RESTART_CAMERA = 1; |
| |
| private QrCamera mCamera; |
| private TextureView mTextureView; |
| private QrDecorateView mDecorateView; |
| private TextView mErrorMessage; |
| |
| /** true if the fragment working for configurator, false enrollee*/ |
| private boolean mIsConfiguratorMode; |
| |
| /** The SSID of the Wi-Fi network which the user specify to enroll */ |
| private String mSsid; |
| |
| /** QR code data scanned by camera */ |
| private WifiQrCode mWifiQrCode; |
| |
| /** The WifiConfiguration connecting for enrollee usage */ |
| private WifiConfiguration mEnrolleeWifiConfiguration; |
| |
| private int mLatestStatusCode = WifiDppUtils.EASY_CONNECT_EVENT_FAILURE_NONE; |
| |
| private WifiTracker mWifiTracker; |
| |
| private final Handler mHandler = new Handler() { |
| @Override |
| public void handleMessage(Message msg) { |
| switch (msg.what) { |
| case MESSAGE_HIDE_ERROR_MESSAGE: |
| mErrorMessage.setVisibility(View.INVISIBLE); |
| break; |
| |
| case MESSAGE_SHOW_ERROR_MESSAGE: |
| final String errorMessage = (String) msg.obj; |
| |
| mErrorMessage.setVisibility(View.VISIBLE); |
| mErrorMessage.setText(errorMessage); |
| mErrorMessage.sendAccessibilityEvent( |
| AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); |
| |
| // Cancel any pending messages to hide error view and requeue the message so |
| // user has time to see error |
| removeMessages(MESSAGE_HIDE_ERROR_MESSAGE); |
| sendEmptyMessageDelayed(MESSAGE_HIDE_ERROR_MESSAGE, |
| SHOW_ERROR_MESSAGE_INTERVAL); |
| |
| if (msg.arg1 == ARG_RESTART_CAMERA) { |
| setProgressBarShown(false); |
| mDecorateView.setFocused(false); |
| restartCamera(); |
| } |
| break; |
| |
| case MESSAGE_SCAN_WIFI_DPP_SUCCESS: |
| if (mScanWifiDppSuccessListener == null) { |
| // mScanWifiDppSuccessListener may be null after onDetach(), do nothing here |
| return; |
| } |
| mScanWifiDppSuccessListener.onScanWifiDppSuccess((WifiQrCode)msg.obj); |
| |
| if (!mIsConfiguratorMode) { |
| setProgressBarShown(true); |
| startWifiDppEnrolleeInitiator((WifiQrCode)msg.obj); |
| updateEnrolleeSummary(); |
| mSummary.sendAccessibilityEvent( |
| AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); |
| } |
| |
| notifyUserForQrCodeRecognition(); |
| break; |
| |
| case MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS: |
| // We may get 2 WifiConfiguration if the QR code has no password in it, |
| // one for open network and one for enhanced open network. |
| final WifiManager wifiManager = |
| getContext().getSystemService(WifiManager.class); |
| final WifiNetworkConfig qrCodeWifiNetworkConfig = |
| (WifiNetworkConfig)msg.obj; |
| final List<WifiConfiguration> qrCodeWifiConfigurations = |
| qrCodeWifiNetworkConfig.getWifiConfigurations(); |
| |
| // Adds all Wi-Fi networks in QR code to the set of configured networks and |
| // connects to it if it's reachable. |
| boolean hasHiddenOrReachableWifiNetwork = false; |
| for (WifiConfiguration qrCodeWifiConfiguration : qrCodeWifiConfigurations) { |
| final int id = wifiManager.addNetwork(qrCodeWifiConfiguration); |
| if (id == -1) { |
| continue; |
| } |
| wifiManager.enableNetwork(id, /* attemptConnect */ false); |
| // WifiTracker only contains a hidden SSID Wi-Fi network if it's saved. |
| // We can't check if a hidden SSID Wi-Fi network is reachable in advance. |
| if (qrCodeWifiConfiguration.hiddenSSID || |
| isReachableWifiNetwork(qrCodeWifiConfiguration)) { |
| hasHiddenOrReachableWifiNetwork = true; |
| mEnrolleeWifiConfiguration = qrCodeWifiConfiguration; |
| wifiManager.connect(id, |
| /* listener */ WifiDppQrCodeScannerFragment.this); |
| } |
| } |
| |
| if (!hasHiddenOrReachableWifiNetwork) { |
| showErrorMessageAndRestartCamera( |
| R.string.wifi_dpp_check_connection_try_again); |
| return; |
| } |
| |
| mMetricsFeatureProvider.action( |
| mMetricsFeatureProvider.getAttribution(getActivity()), |
| SettingsEnums.ACTION_SETTINGS_ENROLL_WIFI_QR_CODE, |
| SettingsEnums.SETTINGS_WIFI_DPP_ENROLLEE, |
| /* key */ null, |
| /* value */ Integer.MIN_VALUE); |
| |
| notifyUserForQrCodeRecognition(); |
| break; |
| |
| default: |
| } |
| } |
| }; |
| |
| @UiThread |
| private void notifyUserForQrCodeRecognition() { |
| if (mCamera != null) { |
| mCamera.stop(); |
| } |
| |
| mDecorateView.setFocused(true); |
| mErrorMessage.setVisibility(View.INVISIBLE); |
| |
| WifiDppUtils.triggerVibrationForQrCodeRecognition(getContext()); |
| } |
| |
| private boolean isReachableWifiNetwork(WifiConfiguration wifiConfiguration) { |
| final List<AccessPoint> scannedAccessPoints = mWifiTracker.getAccessPoints(); |
| |
| for (AccessPoint scannedAccessPoint : scannedAccessPoints) { |
| if (scannedAccessPoint.matches(wifiConfiguration) && |
| scannedAccessPoint.isReachable()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| |
| if (savedInstanceState != null) { |
| mIsConfiguratorMode = savedInstanceState.getBoolean(KEY_IS_CONFIGURATOR_MODE); |
| mLatestStatusCode = savedInstanceState.getInt(KEY_LATEST_ERROR_CODE); |
| mEnrolleeWifiConfiguration = savedInstanceState.getParcelable(KEY_WIFI_CONFIGURATION); |
| } |
| |
| final WifiDppInitiatorViewModel model = |
| ViewModelProviders.of(this).get(WifiDppInitiatorViewModel.class); |
| |
| model.getEnrolleeSuccessNetworkId().observe(this, networkId -> { |
| // After configuration change, observe callback will be triggered, |
| // do nothing for this case if a handshake does not end |
| if (model.isWifiDppHandshaking()) { |
| return; |
| } |
| |
| new EasyConnectEnrolleeStatusCallback().onEnrolleeSuccess(networkId.intValue()); |
| }); |
| |
| model.getStatusCode().observe(this, statusCode -> { |
| // After configuration change, observe callback will be triggered, |
| // do nothing for this case if a handshake does not end |
| if (model.isWifiDppHandshaking()) { |
| return; |
| } |
| |
| int code = statusCode.intValue(); |
| Log.d(TAG, "Easy connect enrollee callback onFailure " + code); |
| new EasyConnectEnrolleeStatusCallback().onFailure(code); |
| }); |
| } |
| |
| @Override |
| public void onPause() { |
| if (mCamera != null) { |
| mCamera.stop(); |
| } |
| |
| super.onPause(); |
| } |
| |
| @Override |
| public void onResume() { |
| super.onResume(); |
| |
| if (!isWifiDppHandshaking()) { |
| restartCamera(); |
| } |
| } |
| |
| @Override |
| public int getMetricsCategory() { |
| if (mIsConfiguratorMode) { |
| return SettingsEnums.SETTINGS_WIFI_DPP_CONFIGURATOR; |
| } else { |
| return SettingsEnums.SETTINGS_WIFI_DPP_ENROLLEE; |
| } |
| } |
| |
| // Container Activity must implement this interface |
| public interface OnScanWifiDppSuccessListener { |
| void onScanWifiDppSuccess(WifiQrCode wifiQrCode); |
| } |
| private OnScanWifiDppSuccessListener mScanWifiDppSuccessListener; |
| |
| /** |
| * Configurator container activity of the fragment should create instance with this constructor. |
| */ |
| public WifiDppQrCodeScannerFragment() { |
| super(); |
| |
| mIsConfiguratorMode = true; |
| } |
| |
| /** |
| * Enrollee container activity of the fragment should create instance with this constructor and |
| * specify the SSID string of the WI-Fi network to be provisioned. |
| */ |
| WifiDppQrCodeScannerFragment(String ssid) { |
| super(); |
| |
| mIsConfiguratorMode = false; |
| mSsid = ssid; |
| } |
| |
| @Override |
| public void onActivityCreated(Bundle savedInstanceState) { |
| super.onActivityCreated(savedInstanceState); |
| |
| mWifiTracker = WifiTrackerFactory.create(getActivity(), /* wifiListener */ this, |
| getSettingsLifecycle(), /* includeSaved */ false, /* includeScans */ true); |
| |
| // setTitle for TalkBack |
| if (mIsConfiguratorMode) { |
| getActivity().setTitle(R.string.wifi_dpp_add_device_to_network); |
| } else { |
| getActivity().setTitle(R.string.wifi_dpp_scan_qr_code); |
| } |
| } |
| |
| @Override |
| public void onAttach(Context context) { |
| super.onAttach(context); |
| |
| mScanWifiDppSuccessListener = (OnScanWifiDppSuccessListener) context; |
| } |
| |
| @Override |
| public void onDetach() { |
| mScanWifiDppSuccessListener = null; |
| |
| super.onDetach(); |
| } |
| |
| @Override |
| public final View onCreateView(LayoutInflater inflater, ViewGroup container, |
| Bundle savedInstanceState) { |
| return inflater.inflate(R.layout.wifi_dpp_qrcode_scanner_fragment, container, |
| /* attachToRoot */ false); |
| } |
| |
| @Override |
| public void onViewCreated(View view, Bundle savedInstanceState) { |
| super.onViewCreated(view, savedInstanceState); |
| |
| mTextureView = view.findViewById(R.id.preview_view); |
| mTextureView.setSurfaceTextureListener(this); |
| |
| mDecorateView = view.findViewById(R.id.decorate_view); |
| |
| setProgressBarShown(isWifiDppHandshaking()); |
| |
| if (mIsConfiguratorMode) { |
| setHeaderTitle(R.string.wifi_dpp_add_device_to_network); |
| |
| WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity()) |
| .getWifiNetworkConfig(); |
| if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) { |
| throw new IllegalStateException("Invalid Wi-Fi network for configuring"); |
| } |
| mSummary.setText(getString(R.string.wifi_dpp_center_qr_code, |
| wifiNetworkConfig.getSsid())); |
| } else { |
| setHeaderTitle(R.string.wifi_dpp_scan_qr_code); |
| |
| updateEnrolleeSummary(); |
| } |
| |
| mErrorMessage = view.findViewById(R.id.error_message); |
| } |
| |
| @Override |
| public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { |
| menu.removeItem(Menu.FIRST); |
| |
| super.onCreateOptionsMenu(menu, inflater); |
| } |
| |
| @Override |
| public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { |
| initCamera(surface); |
| } |
| |
| @Override |
| public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { |
| // Do nothing |
| } |
| |
| @Override |
| public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { |
| destroyCamera(); |
| return true; |
| } |
| |
| @Override |
| public void onSurfaceTextureUpdated(SurfaceTexture surface) { |
| // Do nothing |
| } |
| |
| @Override |
| public Size getViewSize() { |
| return new Size(mTextureView.getWidth(), mTextureView.getHeight()); |
| } |
| |
| @Override |
| public Rect getFramePosition(Size previewSize, int cameraOrientation) { |
| return new Rect(0, 0, previewSize.getHeight(), previewSize.getHeight()); |
| } |
| |
| @Override |
| public void setTransform(Matrix transform) { |
| mTextureView.setTransform(transform); |
| } |
| |
| @Override |
| public boolean isValid(String qrCode) { |
| try { |
| mWifiQrCode = new WifiQrCode(qrCode); |
| } catch (IllegalArgumentException e) { |
| showErrorMessage(R.string.wifi_dpp_qr_code_is_not_valid_format); |
| return false; |
| } |
| |
| // It's impossible to provision other device with ZXing Wi-Fi Network config format |
| final String scheme = mWifiQrCode.getScheme(); |
| if (mIsConfiguratorMode && WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG.equals(scheme)) { |
| showErrorMessage(R.string.wifi_dpp_qr_code_is_not_valid_format); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * This method is only called when QrCamera.ScannerCallback.isValid returns true; |
| */ |
| @Override |
| public void handleSuccessfulResult(String qrCode) { |
| switch (mWifiQrCode.getScheme()) { |
| case WifiQrCode.SCHEME_DPP: |
| handleWifiDpp(); |
| break; |
| |
| case WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG: |
| handleZxingWifiFormat(); |
| break; |
| |
| default: |
| // continue below |
| } |
| } |
| |
| private void handleWifiDpp() { |
| Message message = mHandler.obtainMessage(MESSAGE_SCAN_WIFI_DPP_SUCCESS); |
| message.obj = new WifiQrCode(mWifiQrCode.getQrCode()); |
| |
| mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL); |
| } |
| |
| private void handleZxingWifiFormat() { |
| Message message = mHandler.obtainMessage(MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS); |
| message.obj = new WifiQrCode(mWifiQrCode.getQrCode()).getWifiNetworkConfig(); |
| |
| mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL); |
| } |
| |
| @Override |
| public void handleCameraFailure() { |
| destroyCamera(); |
| } |
| |
| private void initCamera(SurfaceTexture surface) { |
| // Check if the camera has already created. |
| if (mCamera == null) { |
| mCamera = new QrCamera(getContext(), this); |
| |
| if (isWifiDppHandshaking()) { |
| if (mDecorateView != null) { |
| mDecorateView.setFocused(true); |
| } |
| } else { |
| mCamera.start(surface); |
| } |
| } |
| } |
| |
| private void destroyCamera() { |
| if (mCamera != null) { |
| mCamera.stop(); |
| mCamera = null; |
| } |
| } |
| |
| private void showErrorMessage(@StringRes int messageResId) { |
| final Message message = mHandler.obtainMessage(MESSAGE_SHOW_ERROR_MESSAGE, |
| getString(messageResId)); |
| message.sendToTarget(); |
| } |
| |
| private void showErrorMessageAndRestartCamera(@StringRes int messageResId) { |
| final Message message = mHandler.obtainMessage(MESSAGE_SHOW_ERROR_MESSAGE, |
| getString(messageResId)); |
| message.arg1 = ARG_RESTART_CAMERA; |
| message.sendToTarget(); |
| } |
| |
| @Override |
| public void onSaveInstanceState(Bundle outState) { |
| outState.putBoolean(KEY_IS_CONFIGURATOR_MODE, mIsConfiguratorMode); |
| outState.putInt(KEY_LATEST_ERROR_CODE, mLatestStatusCode); |
| outState.putParcelable(KEY_WIFI_CONFIGURATION, mEnrolleeWifiConfiguration); |
| |
| super.onSaveInstanceState(outState); |
| } |
| |
| private class EasyConnectEnrolleeStatusCallback extends EasyConnectStatusCallback { |
| @Override |
| public void onEnrolleeSuccess(int newNetworkId) { |
| |
| // Connect to the new network. |
| final WifiManager wifiManager = getContext().getSystemService(WifiManager.class); |
| final List<WifiConfiguration> wifiConfigs = |
| wifiManager.getPrivilegedConfiguredNetworks(); |
| for (WifiConfiguration wifiConfig : wifiConfigs) { |
| if (wifiConfig.networkId == newNetworkId) { |
| mLatestStatusCode = WifiDppUtils.EASY_CONNECT_EVENT_SUCCESS; |
| mEnrolleeWifiConfiguration = wifiConfig; |
| wifiManager.connect(wifiConfig, WifiDppQrCodeScannerFragment.this); |
| return; |
| } |
| } |
| |
| Log.e(TAG, "Invalid networkId " + newNetworkId); |
| mLatestStatusCode = EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_GENERIC; |
| updateEnrolleeSummary(); |
| showErrorMessageAndRestartCamera(R.string.wifi_dpp_check_connection_try_again); |
| } |
| |
| @Override |
| public void onConfiguratorSuccess(int code) { |
| // Do nothing |
| } |
| |
| @Override |
| public void onFailure(int code) { |
| Log.d(TAG, "EasyConnectEnrolleeStatusCallback.onFailure " + code); |
| |
| int errorMessageResId; |
| switch (code) { |
| case EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_INVALID_URI: |
| errorMessageResId = R.string.wifi_dpp_qr_code_is_not_valid_format; |
| break; |
| |
| case EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION: |
| errorMessageResId = R.string.wifi_dpp_failure_authentication_or_configuration; |
| break; |
| |
| case EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE: |
| errorMessageResId = R.string.wifi_dpp_failure_not_compatible; |
| break; |
| |
| case EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_CONFIGURATION: |
| errorMessageResId = R.string.wifi_dpp_failure_authentication_or_configuration; |
| break; |
| |
| case EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_BUSY: |
| if (code == mLatestStatusCode) { |
| throw(new IllegalStateException("stopEasyConnectSession and try again for" |
| + "EASY_CONNECT_EVENT_FAILURE_BUSY but still failed")); |
| } |
| |
| mLatestStatusCode = code; |
| final WifiManager wifiManager = |
| getContext().getSystemService(WifiManager.class); |
| wifiManager.stopEasyConnectSession(); |
| startWifiDppEnrolleeInitiator(mWifiQrCode); |
| return; |
| |
| case EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_TIMEOUT: |
| errorMessageResId = R.string.wifi_dpp_failure_timeout; |
| break; |
| |
| case EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_GENERIC: |
| errorMessageResId = R.string.wifi_dpp_failure_generic; |
| break; |
| |
| case EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED: |
| throw(new IllegalStateException("EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED" + |
| " should be a configurator only error")); |
| |
| case EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK: |
| throw(new IllegalStateException("EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK" + |
| " should be a configurator only error")); |
| |
| default: |
| throw(new IllegalStateException("Unexpected Wi-Fi DPP error")); |
| } |
| |
| mLatestStatusCode = code; |
| updateEnrolleeSummary(); |
| showErrorMessageAndRestartCamera(errorMessageResId); |
| } |
| |
| @Override |
| public void onProgress(int code) { |
| // Do nothing |
| } |
| } |
| |
| private void startWifiDppEnrolleeInitiator(WifiQrCode wifiQrCode) { |
| final WifiDppInitiatorViewModel model = |
| ViewModelProviders.of(this).get(WifiDppInitiatorViewModel.class); |
| |
| model.startEasyConnectAsEnrolleeInitiator(wifiQrCode.getQrCode()); |
| } |
| |
| @Override |
| public void onSuccess() { |
| final Intent resultIntent = new Intent(); |
| resultIntent.putExtra(WifiDialogActivity.KEY_WIFI_CONFIGURATION, |
| mEnrolleeWifiConfiguration); |
| |
| final Activity hostActivity = getActivity(); |
| hostActivity.setResult(Activity.RESULT_OK, resultIntent); |
| hostActivity.finish(); |
| } |
| |
| @Override |
| public void onFailure(int reason) { |
| Log.d(TAG, "Wi-Fi connect onFailure reason - " + reason); |
| showErrorMessageAndRestartCamera(R.string.wifi_dpp_check_connection_try_again); |
| } |
| |
| // Check is Easy Connect handshaking or not |
| private boolean isWifiDppHandshaking() { |
| final WifiDppInitiatorViewModel model = |
| ViewModelProviders.of(this).get(WifiDppInitiatorViewModel.class); |
| |
| return model.isWifiDppHandshaking(); |
| } |
| |
| /** |
| * To resume camera decoding task after handshake fail or Wi-Fi connection fail. |
| */ |
| private void restartCamera() { |
| if (mCamera == null) { |
| Log.d(TAG, "mCamera is not available for restarting camera"); |
| return; |
| } |
| |
| if (mCamera.isDecodeTaskAlive()) { |
| mCamera.stop(); |
| } |
| |
| final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture(); |
| if (surfaceTexture == null) { |
| throw new IllegalStateException("SurfaceTexture is not ready for restarting camera"); |
| } |
| |
| mCamera.start(surfaceTexture); |
| } |
| |
| private void updateEnrolleeSummary() { |
| if (isWifiDppHandshaking()) { |
| mSummary.setText(R.string.wifi_dpp_connecting); |
| } else { |
| String description; |
| if (TextUtils.isEmpty(mSsid)) { |
| description = getString(R.string.wifi_dpp_scan_qr_code_join_unknown_network, mSsid); |
| } else { |
| description = getString(R.string.wifi_dpp_scan_qr_code_join_network, mSsid); |
| } |
| mSummary.setText(description); |
| } |
| } |
| |
| /** Called when the state of Wifi has changed. */ |
| @Override |
| public void onWifiStateChanged(int state) { |
| // Do nothing. |
| } |
| |
| /** Called when the connection state of wifi has changed. */ |
| @Override |
| public void onConnectedChanged() { |
| // Do nothing. |
| } |
| |
| /** |
| * Called to indicate the list of AccessPoints has been updated and |
| * getAccessPoints should be called to get the latest information. |
| */ |
| @Override |
| public void onAccessPointsChanged() { |
| // Do nothing. |
| } |
| |
| @VisibleForTesting |
| protected boolean isDecodeTaskAlive() { |
| return mCamera != null && mCamera.isDecodeTaskAlive(); |
| } |
| |
| @Override |
| protected boolean isFooterAvailable() { |
| return false; |
| } |
| } |