There are many questions and answers about this topic on the internet but unfortunately it didnt solve my problem.
I get a error every time I try to intent a Camera for a picture of video recording within my Fragment.
The path where I want to save those files are in /data/data/com.example.testing/files/*
The error that I always get is: Failed to find configured root that "contains/data/data/com.example.testing/files/test.jpg" and "Failed to find configured root that contains/data/data/com.example.testing/files/test.mp4"
The complete error log:
2020-12-16 00:14:32.093 6473-6473/com.example.testing E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.testing, PID: 6473
java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.example.testing/files/test.jpg
at androidx.core.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:744)
at androidx.core.content.FileProvider.getUriForFile(FileProvider.java:418)
at com.example.testing.fragments.InvitesCheck.capturePhoto(InvitesCheck.kt:141)
at com.example.testing.fragments.InvitesCheck.access$capturePhoto(InvitesCheck.kt:32)
at com.example.testing.fragments.InvitesCheck$onViewCreated$1.onClick(InvitesCheck.kt:53)
at android.view.View.performClick(View.java:7192)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:992)
at android.view.View.performClickInternal(View.java:7166)
at android.view.View.access$3500(View.java:824)
at android.view.View$PerformClick.run(View.java:27592)
at android.os.Handler.handleCallback(Handler.java:888)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:213)
at android.app.ActivityThread.main(ActivityThread.java:8178)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)
I tried different setups but unfortunately no luck.
This is my Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testing">
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
<application
android:allowBackup="false"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.Testing">
<activity
android:name=".MainActivity"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
</application>
</manifest>
I am using the following functions to call the camera:
private fun capturePhoto() {
val file = File(requireContext().filesDir.path, "test.jpg")
val uri = FileProvider.getUriForFile(requireActivity(), BuildConfig.APPLICATION_ID.toString() + ".provider", file)
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
startActivityForResult(intent, REQUEST_CODE)
}
private fun captureVideo() {
val file = File(requireContext().filesDir.path, "test.mp4")
val uri = FileProvider.getUriForFile(requireActivity(), BuildConfig.APPLICATION_ID.toString() + ".provider", file)
val intent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
startActivityForResult(intent, REQUEST_VIDEO)
}
xml/provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>
What am I doing wrong?
Thank you in advance.
Reading up on this question, it seems that you should be using Context.getExternalFilesDir() instead of Context.getFilesDir()` whenever you're creating the File to which to write to.
This would end up looking something like this:
private fun capturePhoto() {
val file = File(requireContext().getExternalFilesDir(null).path, "test.jpg")
val uri = FileProvider.getUriForFile(requireActivity(), BuildConfig.APPLICATION_ID.toString() + ".provider", file)
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
startActivityForResult(intent, REQUEST_CODE)
}
BONUS: I would recommend you take a look at the MediaStore class if you're planning on making a media-oriented app. Here's an official intro for it.
Related
I am making a app to read a text file from an external storage through Kotlin. Even after adding permission tags and changing options in the manifest file, the following error is displayed and the text file cannot be imported. How can I solve this?
errCode:
java.lang.IllegalArgumentException: File content://com.android.externalstorage.documents/document/primary%3ADocuments%2Ftest.txt contains a path separator
kotlin File
class MainActivity : AppCompatActivity() {
val getTextCode:Int = 2
override fun onCreate(savedInstanceState: Bundle?) {
val vBinding = ActivityMainBinding.inflate(layoutInflater)
super.onCreate(savedInstanceState)
setContentView(vBinding.root)
vBinding.getFromTxt.setOnClickListener {
val downUri = Uri.parse("/storage/self/primary/Documents")
openFile(downUri)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == getTextCode && resultCode == Activity.RESULT_OK) {
try{
data?.data?.also { uri ->
Toast.makeText(this, uri.toString(), Toast.LENGTH_SHORT).show()
Log.d("test", uri.toString())
openFileInput(uri.toString()).bufferedReader().useLines{ lines->
Log.d("test", lines.toString())
}
}
}catch(err:Exception){
Log.d("test", err.toString())
}
}
}
private fun openFile(pickerInitialUri: Uri){
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "text/*"
putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
}
startActivityForResult(intent, getTextCode)
}
}
manifest File
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.questionbank">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.QuestionBank"
android:requestLegacyExternalStorage="true"
>
<activity
android:name=".EditActivity"
android:exported="false" />
<activity
android:name=".TestActivity"
android:exported="false" />
<activity
android:name=".PrintActivity"
android:exported="false" />
<activity
android:name=".InputActivity"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
openFileInput(uri.toString()
The method openFileInput() only expects a file name. Not a file path or a complete content scheme. And it would search for a file with that name in getFilesDir().
If you want to read the file using the uri then open an inputstream for the uri and read from the stream. In Java:
InputStream is = getContentResolver().openInputStream(uri);
Further you do not need any permission to do so. Nor do you have to change options whatever you mean by that.
Hello I am trying to use the new AndroidX Activity Result APIs, especially the ActivityResultContracts.TakePicture() contract.
I created a sample project to test before putting in my real application.
MainActivity
class MainActivity : AppCompatActivity() {
private var _binding: ActivityMainBinding?=null
private val binding get() =_binding!!
private var photoUri:Uri?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = ActivityMainBinding.inflate(layoutInflater)
setupButtons()
setContentView(binding.root)
}
private val takePicture = registerForActivityResult(ActivityResultContracts.TakePicture()) { isSaved ->
if (isSaved) {
binding.imageView.setImageURI(photoUri)
}
}
private fun setupButtons() {
binding.button.setOnClickListener {
photoUri = pickUri()
takePicture.launch(photoUri)
}
}
private fun pickUri(): Uri {
val path = applicationContext.getExternalFilesDir(null)?.absolutePath
val picturesFolder = File(path, "pictures")
Log.d(TAG, "pickUri: ${picturesFolder.absolutePath}")
val sdf = SimpleDateFormat("yyyyMMdd_HHmmss")
val dt = sdf.format(Date())
val fileName = "profile-picture-user-4-${dt}.jpg"
val imagePath = File(applicationContext.filesDir, "pictures")
val newFile = File(imagePath, fileName)
if (!picturesFolder.exists()){
picturesFolder.mkdirs()
Log.d(TAG, "pickUri: directoryCreated")
}
return getUriForFile(applicationContext, "com.example.resultactivitytutorial.fileprovider", newFile)
}
What I am trying to achieve is: If not created, create a folder named pictures inside PACKAGE_NAME-> files to save a profile picture, and save the photo shot inside this folder using the new ActivityResultApi.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.resultactivitytutorial">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.ResultActivityTutorial">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.resultactivitytutorial.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
</application>
</manifest>
And the #xml/file_paths file is:
<paths>
<files-path
name="pictures"
path="pictures/" />
</paths>
The Problem is I am getting the error:
W/ImageView: Unable to open content: content://com.example.resultactivitytutorial.fileprovider/pictures/profile-picture-user-4-20210118_132245.jpg
java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)
I need some help with fixing this problem. Thanks in advance!!
var storage_path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
filePathh = Path.Combine(storage_path, filename);
Java.IO.File file = new Java.IO.File(filePathh);
Console.WriteLine("Downloaded file PATH: " + Query.filePathh);
Intent open = new Intent(Intent.ActionView);
open.AddFlags(ActivityFlags.GrantReadUriPermission);
open.SetFlags(ActivityFlags.NewTask);
Context context = Android.App.Application.Context;
Android.Net.Uri fileUri = FileProvider.GetUriForFile(context, "com.companyname.Login.provider", file).NormalizeScheme();
Console.WriteLine("File uri: " + fileUri.Path);
open.SetDataAndType(fileUri, "*/*");
Intent intentC = Intent.CreateChooser(open, "Open With");
intentC.AddFlags(ActivityFlags.GrantReadUriPermission);
intentC.SetFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intentC);
When trying to open a file (when choosing an app to open it - like Docs or HTML reader) we get error File Not Found.
We saw that filePathh and fileUri are different and are not pointing to the same location.
For storage_path:
storage/emulated/0/Download/How_to_initialize_your_Xamarin_app_to_use_AppConnect_C#_APIs.pdf
For Uri path:
/external/Download/How_to_initialize_your_Xamarin_app_to_use_AppConnect_C#_APIs.pdf
Do you want to achieve the result like following GIF?
I put a PDF in Download folder, I use following code to open it.
private void Button1_Click(object sender, System.EventArgs e)
{
var storage_path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
var filePathh = Path.Combine(storage_path, "test.pdf");
Java.IO.File file = new Java.IO.File(filePathh);
Intent open = new Intent(Intent.ActionView);
Uri photoURI = FileProvider.GetUriForFile(this, PackageName + ".provider", file);
open.SetDataAndType(photoURI, "application/pdf");
open.SetFlags(ActivityFlags.NoHistory | ActivityFlags.GrantReadUriPermission);
Intent intent = Intent.CreateChooser(open, "Open File");
try
{
StartActivity(intent);
}
catch (System.Exception)
{
throw;
}
}
Please add provider in your AndroidManifest.xml and read/write persmission.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.app17" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
<application android:allowBackup="true" android:icon="#mipmap/ic_launcher" android:label="#string/app_name" android:roundIcon="#mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="#style/AppTheme">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
Create a xml folder in Resource folder and add following provider_paths.xml file
<?xml version="1.0" encoding="utf-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
Here is my demo's link.
https://github.com/851265601/Xamarin.Android_ListviewSelect/blob/master/App17.zip
Please put PDF in the Download folder like following screenshot.
I want to share /Internal Storage/aaa/bbb.dat file to another app via FileProvider. But it errors out.
i've put the paths into provider_path.xml and put the provider into manifest file.
// share intent
private void initShareIntent(String type) {
boolean found = false;
Intent share = new Intent(android.content.Intent.ACTION_SEND);
share.setType("*/*");
// gets the list of intents that can be loaded.
List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(share, 0);
if (!resInfo.isEmpty()){
for (ResolveInfo info : resInfo) {
if (info.activityInfo.packageName.toLowerCase().contains(type) ||
info.activityInfo.name.toLowerCase().contains(type) ) {
File file = new File(Environment.getExternalStorageDirectory().getPath()+"/aaa/bbb.dat");
// wrap File object into a content provider. NOTE: authority here should match authority in manifest declaration
Uri uri = FileProvider.getUriForFile(MainActivity.this, "org.bramantya.news.copygame.cod.FileProvider", file);
share.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
share.putExtra(Intent.EXTRA_STREAM, uri); // Optional, just if you wanna share an image.
share.setPackage(info.activityInfo.packageName);
found = true;
break;
}
}
if (!found)
return;
startActivity(Intent.createChooser(share, "Select"));
}
}
final Button button = findViewById(R.id.button2);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Code here executes on main thread after user presses button
//initShareIntent("midrop");
initShareIntent("mail");
if (mInterstitialAd.isLoaded()) {
mInterstitialAd.show();
} else {
Log.d("TAG", "The interstitial wasn't loaded yet.");
}
}
});
I expect gmail or midrop/shareme to opens and bbb.dat file attached. But it errors out
2019-10-26 10:47:27.582 25559-25584/? E/FilePathConverter: resolveFilePath uri = content://org.bramantya.news.copygame.cod.FileProvider/oblehbleh/aaa/bbb.daterror!
java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
at android.database.CursorWindow.nativeGetString(Native Method)
at android.database.CursorWindow.getString(CursorWindow.java:465)
at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51)
at android.database.CursorWrapper.getString(CursorWrapper.java:137)
at com.xiaomi.midrop.sender.c.e.a(Unknown Source:31)
at com.xiaomi.midrop.sender.c.e.c(Unknown Source:0)
at com.xiaomi.midrop.sender.c.e.a(Unknown Source:44)
at com.xiaomi.midrop.sender.ui.TransmissionActivity.a(Unknown Source:61)
at com.xiaomi.midrop.sender.ui.TransmissionActivity$a.doInBackground(Unknown Source:12)
at android.os.AsyncTask$3.call(AsyncTask.java:362)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest
package="com.example.app"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:fullBackupContent="true"
android:icon="#mipmap/copygame"
android:label="#string/app_name"
android:theme="#style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
/>
<activity
android:name="com.example.app.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:grantUriPermissions="true"
android:exported="false"
android:authorities="org.bramantya.news.copygame.cod.FileProvider">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
</application>
</manifest>
provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="oblehbleh" path="/"/>
</paths>
I made the code by following these posts
Android : FileProvider on custom external storage folder
https://developer.android.com/training/sharing/send
https://developer.android.com/reference/android/support/v4/content/FileProvider
and many nmore i cant remember (i'm a total amateur at programming)
thank you
finally it works by changing the provider xml into this
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<paths>
<external-path name="provider" path="/" />
</paths>
</paths>
i am using this code to run a camera intent to take a photo. All being taken from HERE step by step (full sized camera option)
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(getActivity(), "com.example.android.fileprovider", photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(imageFileName, ".jpg",storageDir);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
Toast.makeText(getActivity(), mCurrentPhotoPath, Toast.LENGTH_SHORT).show();
return image;
}
This is my Manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.terrormachine.swipeapp">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.android.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths">
</meta-data>
</provider>
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
and my paths xml:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />
</paths>
and i am getting this error:
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example.terrormachine.swipeapp/files/Pictures/JPEG_20161015_211933_-593154643.jpg
A little surprising since the file "shell" is there(at this location).
I fount THIS thread but i cant understand a thing...can you explain it humanlike? Any solution is welcome! Its an important project and i need to finish as much as possible and this is a huge stop.
In your files_path.xml, you need to replace com.example.package.name with your apps package name, as explained on developers site.
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.example.terrormachine.swipeapp/files/Pictures" />
</paths>
Also add camera permission in your AndroidManifest.xml file.
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera"
android:required="true" />
I think you are missing "uses-feature android:name="android.hardware.camera" android:required="true"" in your manifest.