Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialNiyamat Almass
8,176 PointsThere was a problem accessing your device's external storage?
My code is match with the video but When I choose to take a picture a toast is appear and say "There was a problem accessing your device's external storage".But I set my emulator sdcard and I declare necessary method in the menifast.But still I get the toast.The toast is only appear when mMediaUri is null.
public static final String TAG = MainActivity.class.getSimpleName();
public static final int TAKE_PHOTO_REQUEST = 0;
public static final int TAKE_VIDEO_REQUEST = 1;
public static final int PICK_PHOTO_REQUEST = 2;
public static final int PICK_VIDEO_REQUEST = 3;
public static final int MEDIA_TYPE_IMAGE = 4;
public static final int MEDIA_TYPE_VIDEO = 5;
private Uri mMediaUri;
private DialogInterface.OnClickListener mDialogListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case 0:
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
mMediaUri = getOutPutMediaFileUri(MEDIA_TYPE_IMAGE);
if (mMediaUri == null) {
//display an error
Toast.makeText(MainActivity.this, R.string.error_external_storage, Toast.LENGTH_LONG).show();
} else {
takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
startActivityForResult(takePhotoIntent, TAKE_PHOTO_REQUEST);
}
break;
case 1:
Intent videoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
mMediaUri = getOutPutMediaFileUri(MEDIA_TYPE_VIDEO);
if (mMediaUri == null) {
//display an error
Toast.makeText(MainActivity.this, R.string.error_external_storage, Toast.LENGTH_LONG).show();
} else {
videoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
videoIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10);
videoIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0); //0 for low quality
startActivityForResult(videoIntent, TAKE_VIDEO_REQUEST);
}
break;
case 2:
break;
case 3:
break;
}
}
private Uri getOutPutMediaFileUri(int mediaType) {
if (isExternalStorageAvailable()) {
//Get the external storage directory
String appName = MainActivity.this.getString(R.string.app_name);
File mediaStorageDir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), appName);
//Create our subdirectory
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d(TAG, "failed to create directory");
return null;
}
}
//Create file name
//Create the file
File mediaFile;
Date now = new Date();
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(now);
String path = mediaStorageDir.getPath() + File.separator;
if (mediaType == MEDIA_TYPE_IMAGE) {
mediaFile = new File(path + "IMG_" + timestamp + ".jpg");
} else if (mediaType == MEDIA_TYPE_VIDEO) {
mediaFile = new File(path + "VID_" + timestamp + ".mp4");
} else {
return null;
}
Log.d(TAG, "File: " + Uri.fromFile(mediaFile));
//Return the file's uri
return Uri.fromFile(mediaFile);
} else {
return null;
}
}
private boolean isExternalStorageAvailable() {
String state = Environment.getExternalStorageState();
if (state.equals(Environment.MEDIA_MOUNTED)) {
return true;
} else {
return false;
}
}
};
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.niyamat.ribbit" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera2" android:required="true"/>
<application
android:name=".RibbitApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".LoginActivity"
android:label="@string/title_activity_login"
android:screenOrientation="portrait" >
</activity>
<activity
android:name=".SignUpActivity"
android:label="@string/title_activity_sign_up"
android:parentActivityName=".LoginActivity"
android:screenOrientation="portrait" >
</activity>
<activity
android:name=".EditFriendsActivity"
android:label="@string/title_activity_edit_friends"
android:parentActivityName=".MainActivity"
android:screenOrientation="portrait">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.niyamat.ribbit.MainActivity" />
</activity>
</application>
</manifest>
So why mMediaUri return null. Can someone solve this problem?
Harry James
14,780 PointsHey Niyamat!
I haven't had the time to take a look at this code yet but if like Steve is saying everything looks OK then there's a few things we need to check to see if it's a problem with the device storing (In which case we need to use another device or find a way around it) or with the code itself.
I put together a piece of debug code for students who have issues with writing to external storage for this exact purpose, so go ahead and plug it in at the top of your getOutPutMediaFileUri() method.
Log.d("MainActivity", ">> Let's debug why this directory isn't being created: ");
Log.d("MainActivity", "Is it working?: " + mediaStorageDir.mkdirs());
Log.d("MainActivity", "Is the external storage mounted?: " + Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED));
Log.d("MainActivity", "Does the directory exist?: " + mediaStorageDir.exists());
Log.d("MainActivity", "What is the full URI?: " + mediaStorageDir.toURI());
Log.d("MainActivity", "--");
Log.d("MainActivity", "Can we write to this file?: " + mediaStorageDir.canWrite());
if (!mediaStorageDir.canWrite()) {
Log.d("MainActivity", ">> We can't write! Do we have WRITE_EXTERNAL_STORAGE permission?");
if (getBaseContext().checkCallingOrSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE") == PackageManager.PERMISSION_DENIED) {
Log.d("MainActivity", ">> We don't have permission to write - please add it.");
} else {
Log.d("MainActivity", "We do have permission - the problem lies elsewhere.");
}
}
Log.d("MainActivity", "Are we even allowed to read this file?: " + mediaStorageDir.canRead());
Log.d("MainActivity", "--");
Log.d("MainActivity", ">> End of debugging.");
After that, run your app and post the logcat results over here. I'll get back to you tomorrow when I've got more time :)
Steve Hunter
57,712 PointsNice test. Like that a lot!
Niyamat Almass
8,176 PointsHi Harry James
I added your debug code at top of the getOutPutMediaFileUri() like that
Log.d("MainActivity", ">> Let's debug why this directory isn't being created: ");
Log.d("MainActivity", "Is it working?: " + mediaStorageDir.mkdirs());
Log.d("MainActivity", "Is it available?: " + isExternalStorageAvailable());
Log.d("MainActivity", "Does it exist?: " + mediaStorageDir.exists());
Log.d("MainActivity", "What is the full URI?: " + mediaStorageDir.toURI());
Log.d("MainActivity", "--");
Log.d("MainActivity", "Can we write to this file?: " + mediaStorageDir.canWrite());
if (!mediaStorageDir.canWrite()) {
Log.d("MainActivity", ">> We can't write! Do we have WRITE_EXTERNAL_STORAGE permission?");
if (getBaseContext().checkCallingOrSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE") == PackageManager.PERMISSION_DENIED) {
Log.d("MainActivity", ">> We don't have permission to write - please add it.");
} else {
Log.d("MainActivity", "We do have permission - the problem lies elsewhere.");
}
}
Log.d("MainActivity", "Are we even allowed to read this file?: " + mediaStorageDir.canRead());
Log.d("MainActivity", "--");
Log.d("MainActivity", ">> End of debugging.");
private Uri getOutPutMediaFileUri(int mediaType) {
if (isExternalStorageAvailable()) {
//Get the external storage directory
String appName = MainActivity.this.getString(R.string.app_name);
File mediaStorageDir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), appName);
//Create our subdirectory
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d(TAG, "failed to create directory");
return null;
}
}
//Create file name
//Create the file
File mediaFile;
Date now = new Date();
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(now);
String path = mediaStorageDir.getPath() + File.separator;
if (mediaType == MEDIA_TYPE_IMAGE) {
mediaFile = new File(path + "IMG_" + timestamp + ".jpg");
} else if (mediaType == MEDIA_TYPE_VIDEO) {
mediaFile = new File(path + "VID_" + timestamp + ".mp4");
} else {
return null;
}
Log.d(TAG, "File: " + Uri.fromFile(mediaFile));
//Return the file's uri
return Uri.fromFile(mediaFile);
} else {
return null;
}
}
But it gives me many error that cannot resolve mediaStorageDir.Here is a picture https://drive.google.com/file/d/0Bze-_k4O9A53dXlUb2tGX3gxZnc/view?usp=sharing
When I added the debug code in the getOutPutMediaUri it gives me that https://drive.google.com/file/d/0Bze-_k4O9A53anY4UmIzR1JyQmc/view?usp=sharing
But when I added your debug code below of mediaStorageDir that there was no error. Here is a picture https://drive.google.com/file/d/0Bze-_k4O9A53N1hmbl82bjI3YzQ/view?usp=sharing
But unfortunately when I run the app and choose to take a picture there was nothing shown in the logcat.
I am really confused!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Niyamat Almass
8,176 Pointswhere I placed that debug code?
Am I do something wrong to placed that debug code?
Steve Hunter
57,712 PointsIt needs to be inside the method getOutPutMediaFile
- at the top means "the first lines of". So, paste it in right after the method header.
[EDIT: I was wrong! add it after the declaration of mediaStorageDir
]
Harry James
14,780 PointsYep, Steve is right here! Sorry about my wording there! I can see how this can be misleading!
Anyhow, after placing the code on the first lines of getOutPutMediaFileUri(), the code should compile fine. Go ahead and paste the logcat in now and either me, Steve or another forum user will help you out.
Edit: Yes, apologies again! My fault for not reading your question in detail before. The code should be added after the declaration of mediaStorageDir which is within the getOutPutMediaFireUri() method towards the top.
Niyamat Almass
8,176 PointsWhen I added that debug code in the getOutPutMediaFileUri()'s first line it shows error.
In the debug code's mediaStorageDir is red lined and say can not resolve.
Here is picture
https://drive.google.com/file/d/0Bze-_k4O9A53anY4UmIzR1JyQmc/view?usp=sharing
Steve Hunter
57,712 PointsYes, it will.
Add it here:
private Uri getOutPutMediaFileUri(int mediaType) {
if (isExternalStorageAvailable()) {
//Get the external storage directory
String appName = MainActivity.this.getString(R.string.app_name);
File mediaStorageDir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), appName);
// ADD HARRY's CODE HERE
because that is after the declaration and initialization of mediaStorageDir
.
Make sense?
Steve.
Niyamat Almass
8,176 PointsYes its make sense.
Here is the logcat
11-11 08:05:34.819 2200-2200/com.example.niyamat.ribbit I/MainActivity? Niyamat
11-11 08:07:37.952 2200-2200/com.example.niyamat.ribbit D/MainActivity? >> Let's debug why this directory isn't being created:
11-11 08:07:37.953 2200-2200/com.example.niyamat.ribbit D/MainActivity? Is it working?: false
11-11 08:07:37.953 2200-2200/com.example.niyamat.ribbit D/MainActivity? Is it available?: true
11-11 08:07:37.953 2200-2200/com.example.niyamat.ribbit D/MainActivity? Does it exist?: false
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? What is the full URI?: file:/storage/0E16-1009/Pictures/Ribbit
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? --
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? Can we write to this file?: false
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? >> We can't write! Do we have WRITE_EXTERNAL_STORAGE permission?
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? >> We don't have permission to write - please add it.
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? Are we even allowed to read this file?: false
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? --
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? >> End of debugging.
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? failed to create directory
Steve Hunter
57,712 PointsThis thread is getting a little long now!
I can't see what the issue is, unfortunately. The tests seem to imply that you have no write access to the external storage. Your manifest tells a different story, though. Not sure why that is.
When you run your code, in Logcat, do you also see this line firing?:
Log.d(TAG, "failed to create directory");
Are there any other logs created by your code? I'd like to see precisely which null
is being returned. I suspect the one immediately by the line above, but I'd like to check.
Also, to make your code clearer, can you reindent the lines? I think the curly braces are all OK but it's good to check.
Niyamat Almass
8,176 PointsHi Steve Hunter
I am updating my project to github so you have closer look of my code.
Just setting the github in android studio...............................
Steve Hunter
57,712 PointsPerfect, I'll pull that down and see if I can replicate the error. And, more to the point, fix it!! :-)
Look me up on there - I'm OnlySteveH.
Niyamat Almass
8,176 PointsHi Steve Hunter
Here is the link of my github project
github.com/niyamatalmass/Ribbit
[Note: This is the first time I am using github so I knowledge about github is not good.So if do something on github please tell what should I do next,Please]
Niyamat Almass
8,176 PointsHave you got it?Steve Hunter
Steve Hunter
57,712 PointsYep - got it. Just loading an emulator. Will be right back.
3 Answers
Harry James
14,780 PointsHey Niyamat!
I've gone ahead and forked your project as well and the logcat produced good results for me.
In the logcat you provided, we got these results:
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? Can we write to this file?: false
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? >> We can't write! Do we have WRITE_EXTERNAL_STORAGE permission?
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? >> We don't have permission to write - please add it.
11-11 08:07:37.954 2200-2200/com.example.niyamat.ribbit D/MainActivity? Are we even allowed to read this file?: false
The logcat specifies that we don't have permission to write and therefore, this code won't work. As I have checked your manifest and ran the code myself, I know that this does work perfectly fine.
I am assuming therefore that you are running your app on the latest API version, Android Marshmallow (API 23).
Things have changed in API 23 and now, permissions have multiple protection levels, primarily Normal and Dangerous permissions (See here for more info on this). if we take a look at the WRITE_EXTERNAL_STORAGE permission on the Android Developer site, we can see that this is classed as a Dangerous permission, this means that we must explicitly ask the user for permission if they are using API 23/Marshmallow and we should also check that they have the permission every time we want to use it (Yes, it's annoying and a lot of Android Developers are against it).
So, your app will work perfectly fine on API 22 and lower but on newer versions of Android, we must ask for the permission and check it each time. This is all explained very well on the Android Developer site however, it does take up a lot of code.
I've gone ahead and done the hard work for you and created a pull request on your GitHub repository. Go ahead and read through what I've done (See the Files Changed tab) and then accept the pull request to push it into your code.
I've made sure to comment a lot of my code so that you know what's going on but if there's anything you don't understand about it then please give me a shout here so that I can explain it to you :)
Also, if you are another student having this issue, you can find a gist of the changes to update your project, I've put them on GitHub Gist to keep this post short.
Niyamat Almass
8,176 PointsFinally got it!
- Last night I installed genymotion on my computer (because Steve Hunter said that it works fine on his emulator) and there is old emulator that's api is 19, so I think why shouldn't I download the latest version? So I download the latest version of google nexus 5X api label 23 but again the same problem.
2.Then I made android studio emulator api label 21 ,and run it .Yes It works!!!!! 3.So I am really confused that what just happen in 23 api.But your answer remove my tension and make me understand what is happening in api 23.
4.Harry James Steve Hunter you guys are really great and helpful.
5.Thank you so much for helping me.
6.Now I am understanding what Harry James is done.Thank you Harry James for doing a hard work for me.
Niyamat Almass
8,176 PointsHi Harry James
I come again to disturb you.
Now I am making an app that take photo and store it in the external storage for practicing android runtime permission.
I share my project on github https://github.com/niyamatalmass/Marshallow
In the app I write same code for runtime permission that you have done in the Build a self destructing messaging app on github.
But when I run the app and choose to take photo ,the app crash.
Please help me to find out the problem!
Harry James
14,780 PointsHey Niyamat!
Sorry for my late response - I've been with work recently. Anyhow, if you're still having issues then I'll take a look at your project tomorrow for you :)
Harry James
14,780 PointsHey again Niyamat!
I had no issues with running the app on Marshmallow or Lollipop - could you please instead provide a Logcat so that I can see the issue you are having?
Niyamat Almass
8,176 PointsHi Harry James
Yes! After a lot of research over the internet I finally get rid of the problem of Marshallow project.
But I have another problem for understanding recycler view.
Here I post a question
https://teamtreehouse.com/community/need-help-for-understanding-recyclerview
Steve Hunter
57,712 PointsHi there,
I can't see anything immediately wrong with that, but something's clearly amiss.
Do you know which null
you are receiving? There are three possible places that null
can be returned. Perhaps place a Toast or a Log.e just above each one (the "failed to create directory" already has that) to see which part of getOutputMediaFileUri
is giving you the null
result.
Steve.
Steve Hunter
57,712 PointsLet's move the conversation about my download of your project onto this answer, please. It keeps it all under some order, that way.
I've pulled your project from Github, got it into Android Studio and run it. I have created a new user on your Parse back-end. I then added you as a Friend from the two people created in the app, using Edit Friends in the overflow menu. I clicked the camera icon from the action bar. This produces the four optios, take photo, take video, choose photo or choose video. I selected Take Photo. The emulator emulates the takiing of a photo. This works fine, there is a log entry from your code saying that the jpg has been stored correctly.
What doesn't work on your app and what Log output are you seeing inLogcat. Let's pin down what behaviour you think you should see that you shouldn't or what exactly the problem is. This app appears to work fine - it certainly isn't returning null on selecting the 'take photo' option.
Steve.
Niyamat Almass
8,176 PointsWhy that happen?Can you just post a picture of configuration of your emulator.
What happen to my emulator?
I created new emulator but nothing change.
What happen to my computer?
I am just confused!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Steve Hunter
57,712 PointsI'm using Genymotion stock settings for a Nexus5 running 4.4.4 API 19.
What are you using?
Niyamat Almass
8,176 PointsI am using nexux 5, android studio default emulator.
I have genymotion but not installed on my computer.But now I am installing it to check that work or not.
Steve Hunter
57,712 PointsI'll checl the stock emulator too ... did you use default settings or did you change anything?
Niyamat Almass
8,176 PointsNiyamat Almass
8,176 PointsBen Jakuben Steve Hunter Harry James Jon Kussmann
Please guys solve that problem.