jibon57 / nativescript-mediafilepicker

A complete file picker solution for NativeScript
Apache License 2.0
51 stars 36 forks source link

Android crash on recording Audio #135

Open davecoffin opened 3 years ago

davecoffin commented 3 years ago

On Android, when recording audio, then saving, the app crashes with the following stack:

System.err: An uncaught Exception occurred on "main" thread.
System.err: Failure delivering result ResultInfo{who=null, request=769, result=-1, data=Intent { dat=content://com.google.android.apps.recorder.fileprovider/recording/4dd5a0e7-5225-405f-8f75-8ef13f0e704b.m4a flg=0x1 }} to activity {com.presonus.mypresonus/com.tns.NativeScriptActivity}: com.tns.NativeScriptException: Calling js method onActivityResult failed
System.err: Error: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
System.err: 
System.err: StackTrace:
System.err: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=769, result=-1, data=Intent { dat=content://com.google.android.apps.recorder.fileprovider/recording/4dd5a0e7-5225-405f-8f75-8ef13f0e704b.m4a flg=0x1 }} to activity {com.presonus.mypresonus/com.tns.NativeScriptActivity}: com.tns.NativeScriptException: Calling js method onActivityResult failed
System.err: Error: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
System.err:     at android.app.ActivityThread.deliverResults(ActivityThread.java:5009)
System.err:     at android.app.ActivityThread.handleSendResult(ActivityThread.java:5050)
System.err:     at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51)
System.err:     at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
System.err:     at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
System.err:     at android.os.Handler.dispatchMessage(Handler.java:106)
System.err:     at android.os.Looper.loop(Looper.java:223)
System.err:     at android.app.ActivityThread.main(ActivityThread.java:7660)
System.err:     at java.lang.reflect.Method.invoke(Native Method)
System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
System.err: Caused by: com.tns.NativeScriptException: Calling js method onActivityResult failed
System.err: Error: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
System.err:     at com.tns.Runtime.callJSMethodNative(Native Method)
System.err:     at com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1302)
System.err:     at com.tns.Runtime.callJSMethodImpl(Runtime.java:1188)
System.err:     at com.tns.Runtime.callJSMethod(Runtime.java:1175)
System.err:     at com.tns.Runtime.callJSMethod(Runtime.java:1153)
System.err:     at com.tns.Runtime.callJSMethod(Runtime.java:1149)
System.err:     at com.tns.NativeScriptActivity.onActivityResult(NativeScriptActivity.java:58)
System.err:     at android.app.Activity.dispatchActivityResult(Activity.java:8310)
System.err:     at android.app.ActivityThread.deliverResults(ActivityThread.java:5002)
System.err:     ... 11 more
System.err: Caused by: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
System.err:     at android.database.CursorWindow.nativeGetString(Native Method)
System.err:     at android.database.CursorWindow.getString(CursorWindow.java:469)
System.err:     at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:53)
System.err:     at android.database.CursorWrapper.getString(CursorWrapper.java:141)
System.err:     ... 20 more

Open the audio picker:

let options: AudioPickerOptions = {
          android: {
            isCaptureMood: true, // if true then voice recorder will open directly.
            isNeedRecorder: true,
            maxNumberFiles: 1,
            isNeedFolderList: true,
            maxSize: 102400 // Maximum size of recorded file in bytes. 5900 = ~ 1 second
          },
          ios: {
            isCaptureMood: true, // if true then voice recorder will open directly.
            maxNumberFiles: 0,
            audioMaximumDuration: 500,
          }
        };
        this.mediaFilePicker.openAudioPicker(options);
davecoffin commented 3 years ago

@jibon57 any thoughts on this?

davecoffin commented 3 years ago

I sort of figured this out, I'm not good enough at Android to know whats going on...but heres what I found:

this block:

case Constant.REQUEST_CODE_TAKE_AUDIO:
                if (resultCode === androidAcivity.RESULT_OK) {

                    let rawData = Uri.parse(data.getData().toString());
                    let cursor = context.getContentResolver().query(rawData, null, null, null, null);
                    let column_index = cursor.getColumnIndex(MediaStore.Audio.Media.DATA);
                    cursor.moveToFirst();

                    let file = {
                        type: 'capturedAudio',
                        file: cursor.getString(column_index),
                        rawData: rawData
                    };

                    output.push(file);
                    cursor.close();
                }
                break;

column_index ends up being -1 for some reason. That crashes the app. First I tried this:

file: cursor.getString(column_index > -1 ? column_index : 0),

but that would simply return the filename, not the path to the file. I did notice though, that

data.getData().toString()

returns the full path to the file, in my case it was

content://com.google.android.apps.recorder.fileprovider/recording/634999c5-1dd1-4053-a2e6-fdd550ecc78a.m4a

So, i just pass that back as the file instead of using the cursor thing at all. The block above became

case Constant.REQUEST_CODE_TAKE_AUDIO:
                if (resultCode === androidAcivity.RESULT_OK) {

                    let rawData = Uri.parse(data.getData().toString());
                    let cursor = context.getContentResolver().query(rawData, null, null, null, null);
                    let column_index = cursor.getColumnIndex(MediaStore.Audio.Media.DATA);
                    cursor.moveToFirst();

                    let file = {
                        type: 'capturedAudio',
                        file: data.getData().toString(),
                        rawData: rawData
                    };

                    output.push(file);
                    cursor.close();
                }
                break;

I have no idea how this will work with android phones that have other recording apps or whatever. Any thoughts on this would be appreciated.