Files
packages_apps_Settings/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
Arc Wang a7d51370c8 Implement Wi-Fi DPP flow
1. Wi-Fi DPP hanshake fail UI
2. Show Wi-Fi DPP QR code information field on WifiDppAddDeviceFragment if it's available.
3. Click 'Choose Different Network' button will show WifiDppChooseSavedWifiNetworkFragment
4. After QR code scanner scans success, WifiDppConfiguratorActivity caches WifiQrCode instead
   of just a QR code string

Bug: 122429170
Test: manual test
Change-Id: I1ce1b014ff86903b5a7a8f3575cc98eb1079583c
2019-01-10 12:09:58 +08:00

383 lines
12 KiB
Java

/*
* 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.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
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.widget.TextView;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.wifi.qrcode.QrCamera;
import com.android.settings.wifi.qrcode.QrDecorateView;
public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment implements
SurfaceTextureListener,
QrCamera.ScannerCallback {
private static final String TAG = "WifiDppQrCodeScannerFragment";
/** 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 = 2000;
private static final long SHOW_SUCCESS_SQUARE_INTERVAL = 1000;
// Key for Bundle usage
private static final String KEY_PUBLIC_URI = "key_public_uri";
private static final String KEY_IS_CONFIGURATOR_MODE = "key_is_configurator_mode";
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;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mIsConfiguratorMode = savedInstanceState.getBoolean(KEY_IS_CONFIGURATOR_MODE);
}
}
@Override
public int getMetricsCategory() {
if (mIsConfiguratorMode) {
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
} else {
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_ENROLLEE;
}
}
// Container Activity must implement this interface
public interface OnScanWifiDppSuccessListener {
public void onScanWifiDppSuccess(WifiQrCode wifiQrCode);
}
OnScanWifiDppSuccessListener mScanWifiDppSuccessListener;
// Container Activity must implement this interface
public interface OnScanZxingWifiFormatSuccessListener {
public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig);
}
OnScanZxingWifiFormatSuccessListener mScanZxingWifiFormatSuccessListener;
/**
* 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.
*/
public WifiDppQrCodeScannerFragment(String ssid) {
super();
mIsConfiguratorMode = false;
mSsid = ssid;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final ActionBar actionBar = getActivity().getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.show();
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mScanWifiDppSuccessListener = (OnScanWifiDppSuccessListener) context;
mScanZxingWifiFormatSuccessListener = (OnScanZxingWifiFormatSuccessListener) context;
}
@Override
public void onDetach() {
mScanWifiDppSuccessListener = null;
mScanZxingWifiFormatSuccessListener = 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 = (TextureView) view.findViewById(R.id.preview_view);
mTextureView.setSurfaceTextureListener(this);
mDecorateView = (QrDecorateView) view.findViewById(R.id.decorate_view);
mHeaderIcon.setImageResource(R.drawable.ic_scan_24dp);
if (mIsConfiguratorMode) {
mTitle.setText(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 {
mTitle.setText(R.string.wifi_dpp_scan_qr_code);
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);
}
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) {
mHandler.sendEmptyMessage(MESSAGE_SHOW_ERROR_MESSAGE);
return false;
}
final String scheme = mWifiQrCode.getScheme();
// When SSID is specified for enrollee, avoid to connect to the Wi-Fi of different SSID
if (!mIsConfiguratorMode && WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG.equals(scheme)) {
final String ssidQrCode = mWifiQrCode.getWifiNetworkConfig().getSsid();
if (!TextUtils.isEmpty(mSsid) && !mSsid.equals(ssidQrCode)) {
mHandler.sendEmptyMessage(MESSAGE_SHOW_ERROR_MESSAGE);
return false;
}
}
// It's impossible to provision other device with ZXing Wi-Fi Network config format
if (mIsConfiguratorMode && WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG.equals(scheme)) {
mHandler.sendEmptyMessage(MESSAGE_SHOW_ERROR_MESSAGE);
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() {
destroyCamera();
mDecorateView.setFocused(true);
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() {
destroyCamera();
mDecorateView.setFocused(true);
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);
mCamera.start(surface);
}
}
private void destroyCamera() {
if (mCamera != null) {
mCamera.stop();
mCamera = null;
}
}
public void showErrorMessage(boolean show) {
mErrorMessage.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
if (show) {
mHandler.removeMessages(MESSAGE_HIDE_ERROR_MESSAGE);
mHandler.sendEmptyMessageDelayed(MESSAGE_HIDE_ERROR_MESSAGE,
SHOW_ERROR_MESSAGE_INTERVAL);
}
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_HIDE_ERROR_MESSAGE:
showErrorMessage(false);
break;
case MESSAGE_SHOW_ERROR_MESSAGE:
showErrorMessage(true);
break;
case MESSAGE_SCAN_WIFI_DPP_SUCCESS:
if (mScanWifiDppSuccessListener == null) {
return;
}
mScanWifiDppSuccessListener.onScanWifiDppSuccess((WifiQrCode)msg.obj);
break;
case MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS:
if (mScanZxingWifiFormatSuccessListener == null) {
return;
}
mScanZxingWifiFormatSuccessListener.onScanZxingWifiFormatSuccess(
(WifiNetworkConfig)msg.obj);
break;
default:
return;
}
}
};
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putBoolean(KEY_IS_CONFIGURATOR_MODE, mIsConfiguratorMode);
super.onSaveInstanceState(outState);
}
}