Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android fatal exception when calling scanDoc for the second time #99

Closed
Hamata6 opened this issue May 5, 2021 · 7 comments
Closed

Android fatal exception when calling scanDoc for the second time #99

Hamata6 opened this issue May 5, 2021 · 7 comments

Comments

@Hamata6
Copy link

Hamata6 commented May 5, 2021

Describe the bug
Fatal Exception on Android when calling scanDoc for the second time.
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@4693e70

Stacktrace W/Bitmap: Called hasAlpha() on a recycle()'d bitmap! This is undefined behavior!
Called hasAlpha() on a recycle()'d bitmap! This is undefined behavior!
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: io.ionic.starter, PID: 12600
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@4693e70
at android.graphics.BaseCanvas.throwIfCannotDraw(BaseCanvas.java:77) at android.graphics.RecordingCanvas.throwIfCannotDraw(RecordingCanvas.java:278) at android.graphics.BaseRecordingCanvas.drawBitmap(BaseRecordingCanvas.java:91) at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:548) at android.widget.ImageView.onDraw(ImageView.java:1435) at android.view.View.draw(View.java:23901) at android.view.View.updateDisplayListIfDirty(View.java:22776) at android.view.View.draw(View.java:23631) at android.view.ViewGroup.drawChild(ViewGroup.java:5336) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:5093) at android.view.View.updateDisplayListIfDirty(View.java:22762) at android.view.View.draw(View.java:23631) at android.view.ViewGroup.drawChild(ViewGroup.java:5336) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:5093) at android.view.View.draw(View.java:23904) at android.view.View.updateDisplayListIfDirty(View.java:22776) at android.view.View.draw(View.java:23631) at android.view.ViewGroup.drawChild(ViewGroup.java:5336) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:5093) at android.view.View.updateDisplayListIfDirty(View.java:22762) at android.view.View.draw(View.java:23631) at android.view.ViewGroup.drawChild(ViewGroup.java:5336) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:5093) at android.view.View.updateDisplayListIfDirty(View.java:22762) at android.view.View.draw(View.java:23631) at android.view.ViewGroup.drawChild(ViewGroup.java:5336) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:5093) at android.view.View.updateDisplayListIfDirty(View.java:22762) at android.view.View.draw(View.java:23631) at android.view.ViewGroup.drawChild(ViewGroup.java:5336) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:5093) at android.view.View.updateDisplayListIfDirty(View.java:22762) at android.view.View.draw(View.java:23631) at android.view.ViewGroup.drawChild(ViewGroup.java:5336) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:5093) at android.view.View.draw(View.java:23904) at com.android.internal.policy.DecorView.draw(DecorView.java:1282) at android.view.View.updateDisplayListIfDirty(View.java:22776) at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:579) at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:585) at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:662) at android.view.ViewRootImpl.draw(ViewRootImpl.java:5042) at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4749) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3866) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2618) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9965) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1010) at android.view.Choreographer.doCallbacks(Choreographer.java:809) at android.view.Choreographer.doFrame(Choreographer.java:744) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:995) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:246) at android.app.ActivityThread.main(ActivityThread.java:8512) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130) I/Process: Sending signal. PID: 12600 SIG: 9

To Reproduce
Let's make a brand new all clean project to reproduce:

Manually creating new project

1. Make a new Ionic Angular project with Capacitor: `ionic start DocScanIssue blank --type=angular --capacitor`
2. Install this cordova scanner plugin for Capacitor:
`npm install cordova-plugin-document-scanner`
`npm install @ionic-native/core`
`npm install @ionic-native/document-scanner`
3. Make src/app/home/home.page.ts look like this:

import { AfterViewInit, Component } from '@angular/core';
import { DocumentScannerOptions, DocumentScanner } from '@ionic-native/document-scanner';

@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage implements AfterViewInit {

constructor() {}

ngAfterViewInit() {
this.makeScanHandler();
}

private async makeScanHandler() {
//make infinite scans until error, just as example
let scanResult = false;
do {
scanResult = await this.makeScan();
} while (scanResult);
}

private makeScan(): Promise {
const opts: DocumentScannerOptions = {
sourceType : 1,
fileName : "image",
quality : 3,
returnBase64 : false
};
return DocumentScanner.scanDoc(opts)
.then((res) => {
console.log("res = ", res);
return true;
})
.catch((error) => {
console.log("catched");
console.log(error);
return false;
});
}
}


4. Run ionic cap sync

5. Generate Android project: ionic cap add android

6. Open the Android project with Android Studio: ionic cap open android

7. If your physical device is Android 10+, set targetSdkVersion to 28 in Gradle Scripts/variables.gradle (don't forget to press Sync now) to bypass the storage permission issue for now (default targets 29)

8. Connect a physical device with USB debugging enabled, select it from the devices list, and run the project (I haven't tested it on emulator)

9. Try to make a second scan

Or just clone this repo in which I did all the work already ;)
https://github.com/Hamata6/DocScanIssue
Execute npm i, ionic cap sync, ionic cap open android
Connect a physical device with USB debugging enabled, select it from the devices list, and run the project (I haven't tested it on emulator)
Try to make a second scan

Expected behavior
Being able to make a second (and more) scan. The second time the native Android camera activity opens, but the activity in the background crashes.

Smartphone (please complete the following information):

  • Device: Samsung Galaxy S10
  • OS: Android 11
  • Browser: Android System Webview 90.0.4430.91
  • Capacitor Version 2.4.7
  • Plugin version 4.2.6
@Hamata6
Copy link
Author

Hamata6 commented May 5, 2021

I just found out that sometimes it happens on the second scan, sometimes on the third scan

@ChrisTomAlx
Copy link
Collaborator

Could you try with this version of the plugin? #74 (comment)

Cheers and have a nice day :)
Chris
Neutrinos

@Hamata6
Copy link
Author

Hamata6 commented May 5, 2021

Thanks for your quick response @ChrisTomAlx. I did. However I'm using Capacitor so cordova plugin commands won't work.
I did update it to the beta.1 with editing the package.json to contain "cordova-plugin-document-scanner": "^5.0.0-beta.1"and rerun npm i. It still gives me the same error (after i had encountered and fixed the same issue as #96 )

@Hamata6
Copy link
Author

Hamata6 commented May 7, 2021

@ChrisTomAlx I updated my repo to install the beta.1 version. You can try it yourself: https://github.com/Hamata6/DocScanIssue

@ChrisTomAlx
Copy link
Collaborator

ChrisTomAlx commented May 7, 2021

Could you instead just send me the apk file you are testing with

EDIT: Whoops accidentally closed the issue - My bad sorry...

Cheers and have a nice day :)
Chris
Neutrinos

@Hamata6
Copy link
Author

Hamata6 commented May 7, 2021

Generated a debug app of my repo so you can attach the Android debugger to it:
app-debug.apk.zip

@Hamata6
Copy link
Author

Hamata6 commented May 7, 2021

I think I found out the issue. When the .then() of .scanDoc() is called, the native library (in Androids case the Java code of the scan-library) is not finished yet. So when calling .scanDoc() in a immediate loop without any delay, the .scanDoc() function gets called again before the native code is finished cleaning up (or something).

I found out that the same was happening on iOS. The iOS simulator opened the camera the first time when calling .scanDoc(), but refused to open the camera a second time.

For example this code works perfectly fine:

  private async makeScanHandler() {
    let scanResult = await this.makeScan();
    if (scanResult) {
      setTimeout(() => {
        this.makeScanHandler();
      }, 500); //Timeout of 500ms
    }
  }

  private makeScan(): Promise<boolean> {
    return DocumentScanner.scanDoc()
      .then((res) => {
        console.log("res = ", res);
        return true;
      })
      .catch((error) => {
        console.log("catch, error = ", error);
        return false;
      });
  }

While the old code without delay does not work:

  private async makeScanHandler() {
    let scanResult = false;
    do {
      scanResult = await this.makeScan();
    } while (scanResult);
  }

  private makeScan(): Promise<boolean> {
    return DocumentScanner.scanDoc()
      .then((res) => {
        console.log("res = ", res);
        return true;
      })
      .catch((error) => {
        console.log("catch, error = ", error);
        return false;
      });
  }

I think I can handle this myself now xD. The remaining question is: Can you make .scanDoc() resolve only when the native library is finished doing its work? Then we don't need a delay for the second scan.

@Hamata6 Hamata6 closed this as completed Nov 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants