Skip to content
This repository was archived by the owner on Jun 5, 2023. It is now read-only.

Commit 399eed5

Browse files
Initial commit for the QRCodeScannerSample application
Change-Id: I6fb65b73c0b77a1ba2b0bcd59e7414dbd21dbf13
1 parent 0a2f620 commit 399eed5

26 files changed

+2015
-0
lines changed

QRCodeScannerSample/.gitignore

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
*.iml
2+
.gradle
3+
/local.properties
4+
.idea
5+
.project
6+
.settings
7+
.DS_Store
8+
/bin
9+
/build
10+
/captures
11+
/out
12+
.externalNativeBuild
13+
.cxx

QRCodeScannerSample/README.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Glass QR Code Scanner Sample
2+
3+
This project shows how to scan and read the QR codes using touch gestures,
4+
the [CameraX API](https://developer.android.com/training/camerax) and
5+
the [ZXing API](https://github.com/zxing/zxing/wiki/Getting-Started-Developing).
6+
7+
## Running
8+
9+
This sample does not require any additional setup. Open the project in Android Studio, connect your device,
10+
and press Play to launch the app!

QRCodeScannerSample/app/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/bin
2+
/build

QRCodeScannerSample/app/build.gradle

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2019 Google LLC
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+
apply plugin: 'com.android.application'
18+
19+
android {
20+
compileSdkVersion 29
21+
defaultConfig {
22+
applicationId "com.example.glass.glassqrcodescanner"
23+
minSdkVersion 27
24+
targetSdkVersion 29
25+
versionCode 1
26+
versionName "1.0"
27+
}
28+
buildTypes {
29+
release {
30+
minifyEnabled false
31+
}
32+
}
33+
compileOptions {
34+
sourceCompatibility JavaVersion.VERSION_1_8
35+
targetCompatibility JavaVersion.VERSION_1_8
36+
}
37+
}
38+
39+
dependencies {
40+
implementation 'androidx.appcompat:appcompat:1.1.0'
41+
implementation 'androidx.camera:camera-core:1.0.0-alpha06'
42+
implementation 'androidx.camera:camera-camera2:1.0.0-alpha06'
43+
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
44+
implementation 'com.google.zxing:core:3.2.1'
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?xml version="1.0" encoding="utf-8"?><!--
2+
Copyright 2019 Google LLC
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+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
17+
xmlns:tools="http://schemas.android.com/tools"
18+
package="com.example.glass.qrcodescannersample">
19+
20+
<uses-feature android:name="android.hardware.camera" />
21+
22+
<uses-permission android:name="android.permission.CAMERA" />
23+
24+
<application
25+
android:allowBackup="true"
26+
android:icon="@mipmap/ic_launcher"
27+
android:label="@string/app_name"
28+
android:roundIcon="@mipmap/ic_launcher_round"
29+
android:supportsRtl="true"
30+
android:theme="@style/AppTheme"
31+
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
32+
<!--
33+
Changes Glass touchpad response from the following key strokes:
34+
- Enter
35+
- Tab
36+
- Shift + Tab
37+
- Back button
38+
- Home button
39+
- Arrows
40+
to the motion events, enabling this app to use the touch gestures.
41+
-->
42+
<meta-data
43+
android:name="com.google.android.glass.TouchEnabledApplication"
44+
android:value="true" />
45+
46+
<activity android:name="com.example.glass.qrcodescannersample.MainActivity">
47+
<intent-filter>
48+
<action android:name="android.intent.action.MAIN" />
49+
50+
<category android:name="android.intent.category.LAUNCHER" />
51+
<!--
52+
Makes this app visible on the application list in the Glass Launcher.
53+
-->
54+
<category android:name="com.google.android.glass.category.DIRECTORY" />
55+
</intent-filter>
56+
</activity>
57+
<activity android:name="com.example.glass.qrcodescannersample.CameraActivity">
58+
<intent-filter>
59+
<action android:name="android.intent.action.MAIN" />
60+
61+
<category android:name="android.intent.category.DEFAULT" />
62+
</intent-filter>
63+
</activity>
64+
</application>
65+
66+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2019 Google LLC
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.example.glass.qrcodescannersample;
18+
19+
import android.os.Bundle;
20+
import android.view.MotionEvent;
21+
import android.view.View;
22+
import androidx.annotation.Nullable;
23+
import androidx.fragment.app.FragmentActivity;
24+
import com.example.glass.qrcodescannersample.GlassGestureDetector.OnGestureListener;
25+
26+
/**
27+
* Base Activity class used to hide the system UI and capture gestures.
28+
*/
29+
public abstract class BaseActivity extends FragmentActivity implements OnGestureListener {
30+
31+
private GlassGestureDetector glassGestureDetector;
32+
private View decorView;
33+
34+
@Override
35+
protected void onCreate(@Nullable Bundle savedInstanceState) {
36+
super.onCreate(savedInstanceState);
37+
decorView = getWindow().getDecorView();
38+
decorView.setOnSystemUiVisibilityChangeListener(visibility -> {
39+
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
40+
hideSystemUI();
41+
}
42+
});
43+
glassGestureDetector = new GlassGestureDetector(this, this);
44+
}
45+
46+
@Override
47+
protected void onResume() {
48+
super.onResume();
49+
hideSystemUI();
50+
}
51+
52+
@Override
53+
public boolean dispatchTouchEvent(MotionEvent ev) {
54+
return glassGestureDetector.onTouchEvent(ev) || super.dispatchTouchEvent(ev);
55+
}
56+
57+
private void hideSystemUI() {
58+
decorView.setSystemUiVisibility(
59+
View.SYSTEM_UI_FLAG_IMMERSIVE
60+
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
61+
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
62+
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
63+
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
64+
| View.SYSTEM_UI_FLAG_FULLSCREEN);
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright 2019 Google LLC
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.example.glass.qrcodescannersample;
18+
19+
import android.Manifest.permission;
20+
import android.app.Activity;
21+
import android.content.Intent;
22+
import android.content.pm.PackageManager;
23+
import android.os.Bundle;
24+
import android.util.DisplayMetrics;
25+
import android.util.Size;
26+
import android.view.TextureView;
27+
import androidx.annotation.NonNull;
28+
import androidx.camera.core.CameraX;
29+
import androidx.core.content.ContextCompat;
30+
import com.example.glass.qrcodescannersample.GlassGestureDetector.Gesture;
31+
import com.example.glass.qrcodescannersample.QRCodeImageAnalysis.QrCodeAnalysisCallback;
32+
import java.util.concurrent.ExecutorService;
33+
import java.util.concurrent.Executors;
34+
35+
/**
36+
* Activity responsible for requesting camera permission, starting camera and returning scanned QR
37+
* code as a result.
38+
*/
39+
public class CameraActivity extends BaseActivity implements QrCodeAnalysisCallback {
40+
41+
/**
42+
* Key for the scan result in an {@link Intent}.
43+
*/
44+
public static final String QR_SCAN_RESULT = "SCAN_RESULT";
45+
46+
/**
47+
* Request code for the camera permission. This value doesn't have any special meaning.
48+
*/
49+
private static final int CAMERA_PERMISSIONS_REQUEST_CODE = 105;
50+
51+
/**
52+
* Single thread executor service for the image analysis purposes.
53+
*/
54+
private ExecutorService executorService;
55+
56+
@Override
57+
protected void onCreate(Bundle savedInstanceState) {
58+
super.onCreate(savedInstanceState);
59+
setContentView(R.layout.activity_camera);
60+
executorService = Executors.newSingleThreadExecutor();
61+
62+
if (ContextCompat.checkSelfPermission(this,
63+
permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
64+
startCamera();
65+
} else {
66+
requestPermissions(new String[]{permission.CAMERA}, CAMERA_PERMISSIONS_REQUEST_CODE);
67+
}
68+
}
69+
70+
@Override
71+
protected void onDestroy() {
72+
super.onDestroy();
73+
executorService.shutdown();
74+
}
75+
76+
@Override
77+
public boolean onGesture(Gesture gesture) {
78+
switch (gesture) {
79+
case SWIPE_DOWN:
80+
finishNoQR();
81+
return true;
82+
default:
83+
return false;
84+
}
85+
}
86+
87+
@Override
88+
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
89+
@NonNull int[] grantResults) {
90+
if (requestCode == CAMERA_PERMISSIONS_REQUEST_CODE) {
91+
for (int result : grantResults) {
92+
if (result != PackageManager.PERMISSION_GRANTED) {
93+
finishNoQR();
94+
} else {
95+
startCamera();
96+
}
97+
}
98+
} else {
99+
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
100+
}
101+
}
102+
103+
@Override
104+
public void onQrCodeDetected(String result) {
105+
final Intent intent = new Intent();
106+
intent.putExtra(QR_SCAN_RESULT, result);
107+
setResult(Activity.RESULT_OK, intent);
108+
finish();
109+
}
110+
111+
private void startCamera() {
112+
final TextureView textureView = findViewById(R.id.view_finder);
113+
final QRCodePreview qrCodePreview = new QRCodePreview(
114+
CameraConfigProvider.getPreviewConfig(getDisplaySize()),
115+
textureView);
116+
final QRCodeImageAnalysis qrCodeImageAnalysis = new QRCodeImageAnalysis(
117+
CameraConfigProvider.getImageAnalysisConfig(), executorService, this);
118+
119+
CameraX.bindToLifecycle(this, qrCodePreview.getUseCase(), qrCodeImageAnalysis.getUseCase());
120+
}
121+
122+
private void finishNoQR() {
123+
setResult(Activity.RESULT_CANCELED);
124+
finish();
125+
}
126+
127+
private Size getDisplaySize() {
128+
final DisplayMetrics displayMetrics = new DisplayMetrics();
129+
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
130+
return new Size(displayMetrics.widthPixels, displayMetrics.heightPixels);
131+
}
132+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2019 Google LLC
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.example.glass.qrcodescannersample;
18+
19+
import android.util.Size;
20+
import androidx.camera.core.ImageAnalysis.ImageReaderMode;
21+
import androidx.camera.core.ImageAnalysisConfig;
22+
import androidx.camera.core.PreviewConfig;
23+
24+
/**
25+
* Provides appropriate {@link androidx.camera.core.UseCaseConfig} objects.
26+
*/
27+
public class CameraConfigProvider {
28+
29+
/**
30+
* Returns {@link PreviewConfig} object to create the {@link androidx.camera.core.Preview}
31+
* instance. It is important to build {@link PreviewConfig} object with the appropriate display
32+
* size.
33+
*/
34+
public static PreviewConfig getPreviewConfig(Size displaySize) {
35+
return new PreviewConfig.Builder()
36+
.setTargetResolution(displaySize)
37+
.build();
38+
}
39+
40+
/**
41+
* Returns {@link ImageAnalysisConfig} object to create the {@link androidx.camera.core.ImageAnalysis}
42+
* instance.
43+
*/
44+
public static ImageAnalysisConfig getImageAnalysisConfig() {
45+
return new ImageAnalysisConfig.Builder()
46+
.setImageReaderMode(ImageReaderMode.ACQUIRE_LATEST_IMAGE)
47+
.build();
48+
}
49+
}

0 commit comments

Comments
 (0)