Android screenrecorder crash when writing to external storage
<p>I'm using this code as base for my app: <a href="https://github.com/commonsguy/cw-omnibus/tree/master/MediaProjection/andcorder" rel="nofollow">https://github.com/commonsguy/cw-omnibus/tree/master/MediaProjection/andcorder</a></p>

<p>Now i changed the path for the output file. I want to save it on the external sd card, but if i start recording, i get this error:</p>

<pre><code>09-24 01:37:50.225 4428-4428/me.bleuzen.android.screenrecorder E/AndroidRuntime: FATAL EXCEPTION: main
                                                                             Process: me.bleuzen.android.screenrecorder, PID: 4428
                                                                             java.lang.RuntimeException: Unable to start service me.bleuzen.android.screenrecorder.RecorderService@1febce5 with Intent { act=me.bleuzen.android.screenrecorder.RECORD flg=0x10000000 cmp=me.bleuzen.android.screenrecorder/.RecorderService bnds=[257,1321][832,1513] }: java.lang.RuntimeException: Exception preparing recorder
                                                                                 at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3045)
                                                                                 at android.app.ActivityThread.access$2200(ActivityThread.java:157)
                                                                                 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1454)
                                                                                 at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                 at android.os.Looper.loop(Looper.java:148)
                                                                                 at android.app.ActivityThread.main(ActivityThread.java:5525)
                                                                                 at java.lang.reflect.Method.invoke(Native Method)
                                                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
                                                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
                                                                              Caused by: java.lang.RuntimeException: Exception preparing recorder
                                                                                 at me.bleuzen.android.screenrecorder.RecordingSession.start(RecordingSession.java:98)
                                                                                 at me.bleuzen.android.screenrecorder.RecorderService.startRecorder(RecorderService.java:169)
                                                                                 at me.bleuzen.android.screenrecorder.RecorderService.onStartCommand(RecorderService.java:76)
                                                                                 at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3028)
                                                                                 at android.app.ActivityThread.access$2200(ActivityThread.java:157) 
                                                                                 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1454) 
                                                                                 at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                 at android.os.Looper.loop(Looper.java:148) 
                                                                                 at android.app.ActivityThread.main(ActivityThread.java:5525) 
                                                                                 at java.lang.reflect.Method.invoke(Native Method) 
                                                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730) 
                                                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620) 
                                                                              Caused by: java.io.FileNotFoundException: /storage/3E0D-1BF9/20160924_013750.mp4: open failed: EACCES (Permission denied)
                                                                                 at libcore.io.IoBridge.open(IoBridge.java:452)
                                                                                 at java.io.RandomAccessFile.&lt;init&gt;(RandomAccessFile.java:117)
                                                                                 at java.io.RandomAccessFile.&lt;init&gt;(RandomAccessFile.java:149)
                                                                                 at android.media.MediaRecorder.prepare(MediaRecorder.java:780)
                                                                                 at me.bleuzen.android.screenrecorder.RecordingSession.start(RecordingSession.java:89)
                                                                                 at me.bleuzen.android.screenrecorder.RecorderService.startRecorder(RecorderService.java:169) 
                                                                                 at me.bleuzen.android.screenrecorder.RecorderService.onStartCommand(RecorderService.java:76) 
                                                                                 at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3028) 
                                                                                 at android.app.ActivityThread.access$2200(ActivityThread.java:157) 
                                                                                 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1454) 
                                                                                 at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                 at android.os.Looper.loop(Looper.java:148) 
                                                                                 at android.app.ActivityThread.main(ActivityThread.java:5525) 
                                                                                 at java.lang.reflect.Method.invoke(Native Method) 
                                                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730) 
                                                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620) 
                                                                              Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
                                                                                 at libcore.io.Posix.open(Native Method)
                                                                                 at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
                                                                                 at libcore.io.IoBridge.open(IoBridge.java:438)
                                                                                 at java.io.RandomAccessFile.&lt;init&gt;(RandomAccessFile.java:117) 
                                                                                 at java.io.RandomAccessFile.&lt;init&gt;(RandomAccessFile.java:149) 
                                                                                 at android.media.MediaRecorder.prepare(MediaRecorder.java:780) 
                                                                                 at me.bleuzen.android.screenrecorder.RecordingSession.start(RecordingSession.java:89) 
                                                                                 at me.bleuzen.android.screenrecorder.RecorderService.startRecorder(RecorderService.java:169) 
                                                                                 at me.bleuzen.android.screenrecorder.RecorderService.onStartCommand(RecorderService.java:76) 
                                                                                 at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3028) 
                                                                                 at android.app.ActivityThread.access$2200(ActivityThread.java:157) 
                                                                                 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1454) 
                                                                                 at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                 at android.os.Looper.loop(Looper.java:148) 
                                                                                 at android.app.ActivityThread.main(ActivityThread.java:5525) 
                                                                                 at java.lang.reflect.Method.invoke(Native Method) 
                                                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730) 
                                                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620) 
</code></pre>

<p>My Manifest:</p>

<pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="me.bleuzen.android.screenrecorder"&gt;

&lt;application
    android:icon="@drawable/ic_videocam_white_24dp"
    android:label="@string/app_name"&gt;
    &lt;activity
        android:name="me.bleuzen.android.screenrecorder.MainActivity"
        android:theme="@style/AppTheme"&gt;
        &lt;intent-filter&gt;
            &lt;action android:name="android.intent.action.MAIN" /&gt;

            &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
        &lt;/intent-filter&gt;
    &lt;/activity&gt;

    &lt;service
        android:name="me.bleuzen.android.screenrecorder.RecorderService"
        android:exported="true" /&gt;
&lt;/application&gt;

&lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&gt;
&lt;uses-permission android:name="android.permission.RECORD_AUDIO" /&gt;
&lt;uses-permission android:name="android.permission.WRITE_SETTINGS" /&gt;
</code></pre>

<p></p>

<p>I already put in the WRITE_EXTERNAL_STORAGE permission.
WRITE_SETTINGS is to set show touches.</p>

<p>The most interesting line should be:
Caused by: java.io.FileNotFoundException: /storage/3E0D-1BF9/20160924_013750.mp4: open failed: EACCES (Permission denied)
, where /storage/3E0D-1BF9/ is my external sd card. But why "Permission denied"? I added WRITE_EXTERNAL_STORAGE. Any idea?</p>

<p>Edit 1: I added this to onCreate in my Main / Settings and only Activity:</p>

<pre><code>ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.WRITE_SETTINGS, Manifest.permission.RECORD_AUDIO}, RecorderService.NOTIFY_ID);
</code></pre>

<p>where RecorderService.NOTIFY_ID is just an int</p>

<p>and checked it with:</p>

<pre><code>showToast(String.valueOf(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) + " " +
                String.valueOf(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED) + " " +
                String.valueOf(ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED));

static void showToast(String msg) {
    Toast.makeText(appContext, msg, Toast.LENGTH_SHORT).show();
}
</code></pre>

<p>The Output was: "true false true"</p>

<p>WRITE_SETTINGS stays false :(
... but if I can save the video to the external sd card instead, it's ok. Maybe we will find a fix for this too ;)</p>

<p>Now WRITE_EXTERNAL_STORAGE is allowed, the problem SHOULD be resolved, but it still doesn't work. If I can guess why:
To request a permission, the method needs an activity. Does this mean, that every activity has to request the permission? The problem with this is: The recorder is a Service. I can't request a permission without an activity.</p>

<p>Edit 2: Example:
In AndroidManifest.xml:</p>

<pre><code>&lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&gt;
</code></pre>

<p>activity_main.xml:</p>

<pre><code>    &lt;?xml version="1.0" encoding="utf-8"?&gt;
    &lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="me.bleuzen.android.screenrecorder.MainActivity"
    android:background="@android:color/background_light"&gt;

    &lt;TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true"
        android:id="@+id/textView"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true" /&gt;


    &lt;/RelativeLayout&gt;
</code></pre>

<p>MainActivity:</p>

<pre><code>package me.bleuzen.android.screenrecorder;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.widget.TextView;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class MainActivity extends Activity {

    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.textView);

        boolean canWrite = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;

        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        textView.append("WRITE_EXTERNAL_STORAGE: " + canWrite + "\n");

        if(canWrite) {
            textView.append("Befor: " + new File("/storage/emulated/0/z.txt").exists() + " " + new File("/storage/6301-17FC/z.txt").exists() + "\n");

            writeToFile("Unglaublich wichtig", "/storage/emulated/0/z.txt");
            writeToFile("Unglaublich wichtig", "/storage/6301-17FC/z.txt");

            textView.append("After: " + new File("/storage/emulated/0/z.txt").exists() + " " + new File("/storage/6301-17FC/z.txt").exists() + "\n");
        } else {
            textView.append("Please restart this app after granting permission.");
        }
    }

    private static void writeToFile(String s, String f) {
        File file = new File(f);
        try {
            file.createNewFile();
            FileOutputStream outputStream = new FileOutputStream(file);
            OutputStreamWriter writer = new OutputStreamWriter(outputStream);
            writer.append(s);
            writer.close();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
</code></pre>

<p>Result of this example code:
On /storage/emulated/0 (internal) the file gets created, on /storage/6301-17FC (my external sd card) not.</p>

<p>Edit 3: I tryed this:</p>

<pre><code>@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
        try {
            new File("/storage/6391-A617/test").createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
</code></pre>

<p>, where 6391-A617 is my external SD Card (this time another one to test).
Result:</p>

<pre><code>09-27 15:39:16.624 4965-4965/me.bleuzen.android.screenrecorder W/System.err: java.io.IOException: open failed: EACCES (Permission denied)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at java.io.File.createNewFile(File.java:939)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at me.bleuzen.android.screenrecorder.MainActivity.onRequestPermissionsResult(MainActivity.java:226)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6588)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at android.app.Activity.dispatchActivityResult(Activity.java:6467)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at android.app.ActivityThread.deliverResults(ActivityThread.java:3738)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at android.app.ActivityThread.handleSendResult(ActivityThread.java:3785)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at android.app.ActivityThread.access$1400(ActivityThread.java:157)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at android.os.Looper.loop(Looper.java:148)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5525)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
09-27 15:39:16.633 4965-4965/me.bleuzen.android.screenrecorder W/System.err: Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
09-27 15:39:16.634 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at libcore.io.Posix.open(Native Method)
09-27 15:39:16.634 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
09-27 15:39:16.634 4965-4965/me.bleuzen.android.screenrecorder W/System.err:     at java.io.File.createNewFile(File.java:932)
09-27 15:39:16.634 4965-4965/me.bleuzen.android.screenrecorder W/System.err:    ... 13 more
</code></pre>