Android Studio - QR code scanning
===
* [name=Ander Liu]
###### tags: `Android Studio`
[TOC]
## Zxing
* **ZXing** ("zebra crossing") is an open-source, multi-format 1D/2D barcode image processing library implemented in Java, with ports to other languages.
* 這堂課,我們打算使用 **Zxing** 這個 library to implement QR code scanning
* The Supported Formats of **Zxing**
| 1D product | 1D industrial | 2D |
| ---------- | ------------- | -------------- |
| UPC-A | Code 39 | QR Code |
| EAN-8 | Code 128 | Aztec (beta) |
| EAN-13 | Codabar | PDF 417 (beta) |
| | ITF | MaxiCode |
| | RSS-14 | |
| | RSS-Expanded | |
* [Official APP on Google Play](https://play.google.com/store/apps/details?id=com.google.zxing.client.android)
* 我們基本上是根據此網站來設置
https://github.com/journeyapps/zxing-android-embedded
## Adding dependency with Gradle
:::danger
Android SDK 需要 19 以上
:::
* 我們先把 library 加進來
* 開啟 **build.gradle**,在適當的位置加入以下 dependency
```groovy=1
dependencies {
implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
implementation 'com.android.support:appcompat-v7:25.3.1' // Minimum 23+ is required
}
```

## Hardware Acceleration
* Hardware accelation is required since [`TextureView`](https://developer.android.com/reference/android/view/TextureView) is used
* 開啟 **AndroidManifest.xml**,在適當的位置 enable hardwareAccelerated 屬性
```xml=1
<application android:hardwareAccelerated="true" ... >
```
## Usage with IntentIntegrator
* 此為 the source code of the `IntentIntegrator`
https://github.com/journeyapps/zxing-android-embedded/blob/master/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java
* `IntentIntegrator`顧名思義,就是 [`intent`](https://developer.android.com/reference/android/content/Intent)的integrate版。可以call一些method來設定要開啟的掃描acticity的屬性,最後 call [`initiateScan()`](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L258)來開啟掃描acticity
:::warning
有關 [`intent`](https://developer.android.com/reference/android/content/Intent),之後會再介紹
:::
* 以下為可能會用到的 method
* 第 98 行 [IntentIntegrator(Activity activity)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L98) `the Constructor`
* 第 146 行 [IntentIntegrator forFragment(Fragment fragment)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L146)
* 第 167 行 [IntentIntegrator setPrompt(String prompt)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L167) `Set a prompt to display on the capture screen, instead of using the default.`
* 第 179 行 [IntentIntegrator setOrientationLocked(boolean locked)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L179) `By default, the orientation is locked. Set to false to not lock.`
* 第 189 行 [IntentIntegrator setCameraId(int cameraId)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L189) `Use the specified camera ID.`
* 第 214 行 [IntentIntegrator setBeepEnabled(boolean enabled)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L214) `Set to false to disable beep on scan.`
* 第 225 行 [IntentIntegrator setBarcodeImageEnabled(boolean enabled)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L225) `Set to true to enable saving the barcode image and sending its path in the result Intent.`
* 第 247 行 [IntentIntegrator setDesiredBarcodeFormats(String... desiredBarcodeFormats)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L247) `Set the desired barcode formats to scan.`
* 第 258 行 [void initiateScan()](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L258) `Initiates a scan for all known barcode types with the default camera.`
```java=1
new IntentIntegrator(this).initiateScan(); // \`this\` is the current Activity
// Get the results:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if(result != null) {
if(result.getContents() == null) {
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
```
* 第 1 行,[`initiateScan()`](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L258),用來啟動掃描Activity,可以寫在 onClick() 或是 onCreate() 等等method裡面
* 第 3-16行,[`onActictyResult()`](https://developer.android.com/reference/android/app/Activity#onActivityResult(int,%20int,%20android.content.Intent)),目的是取得掃描Activity傳回來的結果,不需要動這部分,直接貼到 **MainActivity.java** 即可
:::warning
有關*啟動 Activity 以取得結果*,之後會再介紹
:::
* result.getContents() 為結果,如果打算顯示掃描結果,複製結果,開啟URL,便需要利用此結果
### Customize options
* 此為其他客製化功能,和 [`initiateScan()`](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L258)一樣,寫在 onClick() 或是 onCreate() 等等method裡面
```java=1
IntentIntegrator integrator = new IntentIntegrator(this);
integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE);
integrator.setPrompt("Scan a QR code");
integrator.setCameraId(0); // Use a specific camera of the device
integrator.setBeepEnabled(false);
integrator.setBarcodeImageEnabled(true);
integrator.initiateScan();
```
### Changing the orientation
1. 開啟 **AndroidManifest.xml**,加入以下code
```xml=1
<activity
android:name="com.journeyapps.barcodescanner.CaptureActivity"
android:screenOrientation="fullSensor"
tools:replace="screenOrientation" />
```

2. [`setOrientationLocked()`](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L179) set false to not lock,和 [`initiateScan()`](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L258)寫在一起
```java=
IntentIntegrator integrator = new IntentIntegrator(this);
integrator.setOrientationLocked(false);
integrator.initiateScan();
```
## Button and Text display
1. layout 如下所示

2. 在 **MainActivity.java** 寫一個 onClick() method,裡面放剛剛的那些code
```java=1
public void onClick(View view){
IntentIntegrator integrator = new IntentIntegrator(this);
integrator.setOrientationLocked(false);
integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE);
integrator.setPrompt("Scan a QR code");
integrator.setCameraId(0); // Use a specific camera of the device
integrator.setBeepEnabled(false);
integrator.setBarcodeImageEnabled(true);
integrator.initiateScan();
}
```
3. 在 [`onActictyResult()`](https://developer.android.com/reference/android/app/Activity#onActivityResult(int,%20int,%20android.content.Intent))裡面加入第 4 行和第 12 行,用 [`TextView`](https://developer.android.com/reference/android/widget/TextView)顯示結果
```java=1
// Get the results:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
TextView textView = findViewById(R.id.textView);
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if(result != null) {
if(result.getContents() == null) {
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Scanned: " \+ result.getContents(), Toast.LENGTH_LONG).show();
textView.setText(result.getContents());
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
```
4. 把 onClick() 設置到 button 上
:::success
Done!!!
:::


## Reference
* [Github | Zxing](https://github.com/journeyapps/zxing-android-embedded)
* [Github | IntentIntegrator.java](https://github.com/journeyapps/zxing-android-embedded/blob/master/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java)
* [Useful Reference](http://lmgtfy.com/?q=Android+QR+code)
## Future feature
* Scan a photo
* [Copy to clipboard](https://developer.android.com/guide/topics/text/copy-paste#java)
* Open the URL link
## Homepage
* [Homepage](/@NDR/Homepage)
*[SDK]: Software Development Kit
*[URL]: Uniform Resource Locator