Integrate QrCode Camera with WifiDppQrCodeScannerFragment

Bug: 118797380
Test: RunSettingsRoboTests
Change-Id: I328bebbbcf44136df2c18ca1929a5da377a0cf6b
This commit is contained in:
Johnson Lu
2018-11-28 15:31:16 +08:00
parent 0173c5f532
commit a558c01696
6 changed files with 189 additions and 21 deletions

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/wifi_dpp_fragment_header"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<SurfaceView
android:id="@+id/preview_view"
android:layout_width="426dp"
android:layout_height="320dp"
android:layout_gravity="center"/>
<com.android.settings.wifi.qrcode.QrDecorateView
android:id="@+id/decorate_view"
android:layout_width="426dp"
android:layout_height="320dp"
android:layout_gravity="center"/>
</FrameLayout>
<TextView android:id="@+id/error_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
<include layout="@layout/wifi_dpp_fragment_footer"
android:gravity="center|bottom"/>
</LinearLayout>

View File

@@ -32,7 +32,7 @@
android:layout_width="320dp"
android:layout_height="426dp"
android:layout_gravity="center"/>
<ImageView
<com.android.settings.wifi.qrcode.QrDecorateView
android:id="@+id/decorate_view"
android:layout_width="320dp"
android:layout_height="426dp"

View File

@@ -21,6 +21,7 @@ import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
@@ -86,21 +87,21 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity {
}
private void addQrCodeScannerFragment() {
WifiDppQrCodeScannerFragment fragment = new WifiDppQrCodeScannerFragment();
final WifiDppQrCodeScannerFragment fragment = new WifiDppQrCodeScannerFragment();
mFragmentTransaction.add(R.id.fragment_container, fragment);
mFragmentTransaction.addToBackStack(null);
mFragmentTransaction.addToBackStack(/* name */ null);
mFragmentTransaction.commit();
}
private void addQrCodeGeneratorFragment() {
WifiDppQrCodeGeneratorFragment fragment = new WifiDppQrCodeGeneratorFragment();
final WifiDppQrCodeGeneratorFragment fragment = new WifiDppQrCodeGeneratorFragment();
mFragmentTransaction.add(R.id.fragment_container, fragment);
mFragmentTransaction.addToBackStack(null);
mFragmentTransaction.addToBackStack(/* name */ null);
mFragmentTransaction.commit();
}
private void addChooseSavedWifiNetworkFragment() {
ActionBar action = getActionBar();
final ActionBar action = getActionBar();
if (action != null) {
action.hide();
}
@@ -108,7 +109,18 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity {
WifiDppChooseSavedWifiNetworkFragment fragment =
new WifiDppChooseSavedWifiNetworkFragment();
mFragmentTransaction.add(R.id.fragment_container, fragment);
mFragmentTransaction.addToBackStack(null);
mFragmentTransaction.addToBackStack(/* name */ null);
mFragmentTransaction.commit();
}
@Override
protected void onStop() {
final Fragment fragment = mFragmentManager.findFragmentById(R.id.fragment_container);
if (fragment != null) {
// Remove it to prevent stacking multiple fragments after screen rotated.
mFragmentManager.beginTransaction().remove(fragment).commit();
}
super.onStop();
}
}

View File

@@ -16,13 +16,28 @@
package com.android.settings.wifi.dpp;
import android.annotation.Nullable;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Size;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
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
SurfaceHolder.Callback,
QrCamera.ScannerCallback {
private QrCamera mCamera;
private SurfaceView mSurfaceView;
private QrDecorateView mDecorateView;
public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment {
@Override
protected int getLayout() {
return R.layout.wifi_dpp_qrcode_scanner_fragment;
@@ -34,12 +49,15 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment {
setTitle(getString(R.string.wifi_dpp_add_device_to_network));
String ssid = "";
Intent intent = getActivity().getIntent();
if (intent != null)
String ssid = null;
final Intent intent = getActivity().getIntent();
if (intent != null) {
ssid = intent.getStringExtra(WifiDppConfiguratorActivity.EXTRA_SSID);
String description = getString(R.string.wifi_dpp_center_qr_code, ssid);
setDescription(description);
}
if (TextUtils.isEmpty(ssid)) {
throw new IllegalArgumentException("Invalid SSID");
}
setDescription(getString(R.string.wifi_dpp_center_qr_code, ssid));
hideRightButton();
@@ -47,6 +65,71 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment {
setLeftButtonOnClickListener((view) -> {
getActivity().setResult(Activity.RESULT_CANCELED);
getActivity().finish();});
getActivity().finish();
});
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mSurfaceView = (SurfaceView) view.findViewById(R.id.preview_view);
final SurfaceHolder surfaceHolder = mSurfaceView.getHolder();
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceHolder.addCallback(this);
mDecorateView = (QrDecorateView) view.findViewById(R.id.decorate_view);
}
@Override
public void surfaceCreated(final SurfaceHolder holder) {
initCamera(holder);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
destroyCamera();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// Do nothing
}
@Override
public Size getViewSize() {
return new Size(mSurfaceView.getWidth(), mSurfaceView.getHeight());
}
@Override
public Rect getFramePosition(Size previewSize, int cameraOrientation) {
return new Rect(0, 0, previewSize.getHeight(), previewSize.getHeight());
}
@Override
public void handleSuccessfulResult(String qrCode) {
destroyCamera();
mDecorateView.setFocused(true);
// TODO(b/120243131): Add a network by Wi-Fi Network config shared via QR code.
}
@Override
public void handleCameraFailure() {
destroyCamera();
}
private void initCamera(SurfaceHolder holder) {
// Check if the camera has already created.
if (mCamera == null) {
mCamera = new QrCamera(getContext(), this);
mCamera.start(holder);
}
}
private void destroyCamera() {
if (mCamera != null) {
mCamera.stop();
mCamera = null;
}
}
}

View File

@@ -43,6 +43,7 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import androidx.annotation.VisibleForTesting;
@@ -85,14 +86,26 @@ public class QrCamera extends Handler {
mReader.setHints(HINTS);
}
void start(SurfaceHolder surfaceHolder) {
/**
* The function start camera preview and capture pictures to decode QR code continuously in a
* background task.
*
* @param surfaceHolder the Surface to be used for live preview, must already contain a surface
* when this method is called.
*/
public void start(SurfaceHolder surfaceHolder) {
if (mDecodeTask == null) {
mDecodeTask = new DecodingTask(surfaceHolder);
mDecodeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
// Execute in the separate thread pool to prevent block other AsyncTask.
mDecodeTask.executeOnExecutor(Executors.newSingleThreadExecutor());
}
}
void stop() {
/**
* The function stop camera preview and background decode task. Caller call this function when
* the surface is being destroyed.
*/
public void stop() {
removeMessages(MSG_AUTO_FOCUS);
if (mDecodeTask != null) {
mDecodeTask.cancel(true);
@@ -104,7 +117,7 @@ public class QrCamera extends Handler {
}
/** The scanner which includes this QrCamera class should implement this */
interface ScannerCallback {
public interface ScannerCallback {
/**
* The function used to handle the decoding result of the QR code.

View File

@@ -24,6 +24,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
@@ -53,4 +54,12 @@ public class WifiDppQrCodeScannerFragmentTest {
assertThat(mActivityRule.getActivityResult().getResultCode()).
isEqualTo(Activity.RESULT_CANCELED);
}
@Test
public void rotateScreen_shouldNotCrash() {
mActivityRule.getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mActivityRule.getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}