Android , ndk, write willfully to a sd card file - java

After Android 4.4, the SD card needs permission to write files.
You can request to write to the SD card by StorageVolume. createAccessIntent ().
The stream is then accessed using ContentResolver().openoutputstream (file.geturi ()) to write data to the file.
How do I write data in the NDK?
public void startRequestPermissions(Context context) {
Intent intent = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
if (mStorageManager != null) {
StorageVolume volume = mStorageManager.getStorageVolume(new File(timePath));
if (volume != null) {
intent = volume.createAccessIntent(null);
}
}
}
if (intent == null) {
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
}
((Activity) context).startActivityForResult(intent, FileBrowserConfig.OPEN_DOCUMENT_TREE_CODE);
}
public OutputStream getOutputStream(Context context, File destFile) {
OutputStream out = null;
try {
DocumentFile file = getDocumentFile(destFile, false, context);
out = context.getContentResolver().openOutputStream(file.getUri());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return out;
}
Can write data in sd card with NDK!

Instead of openOutputStream(), you can get a file descriptor with openAssetFileDescriptor().

Related

How to use Intent.ACTION_OPEN_DOCUMENT in Android Pie

I'm making a profile photo change function using Retrofit in android pie.
So I succeeded in uploading the photos taken with the camera to the server.
But I don't know how to transfer the photos selected from the gallery to my server.
(I'm fine with any kind of code in Java Kotlin.)
I will upload the video later.
I searched a lot on Google, but it was hard to get the information I wanted.
Well done in the google doc but i don't know how to do it.
https://developer.android.com/guide/topics/providers/document-provider
The Google doc shows examples of using bitmap or inputstream or something.
Do I need a bitmap or inputstream to upload photos using Retrofit?
I actually need a valid uri.
public void performFileSearch() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, PICTURES_DIR_ACCESS_REQUEST_CODE);
}
#Override
public void onActivityResult(int requestCode, int resultCode,Intent resultData) {
if (requestCode == READ_REQUEST_CODE && resultCode ==Activity.RESULT_OK) {
Uri uri = null;
if (resultData != null) {
uri = resultData.getData();
Log.i(TAG, "Uri: " + uri.toString());
showImage(uri);
}
}
}
public void Edit_Profile (String Image_Uri) {
File file = new File(Image_Uri);
RequestBody requestBody = RequestBody.create(file, MediaType.parse("image/*"));
MultipartBody.Part body = MultipartBody.Part.createFormData("uploaded_file", Num+ID+".jpg", requestBody);
}
In fact, onActivityResult returns the following type of uri.
content://com.android.providers.media.documents/document/image%3A191474
So when I try to send it to my server using that uri I get a FileNotFoundException error.
This is a privacy restriction introduced in Android-Q. Direct access to shared/external storage devices is deprecated when an app targets API 29 and the path returned from getExternalStorageDirectory method is no longer directly accessible to apps. Use the app-specific directory to write & read files.
By default, apps targeting Android 10 and higher are given scoped access into external storage, or scoped storage. Such apps can see the following types of files within an external storage device without needing to request any storage-related user permissions:
Files in the app-specific directory, accessed using getExternalFilesDir().
Photos, videos, and audio clips that the app created from the media store.
Files in the app-specific directory, accessed using getExternalFilesDir().
Photos, videos, and audio clips that the app created from the media store.
Go through the documentation Open files using storage access framework
Coming to the context, One thing that you can do is that as
CommonsWare suggested use InputStreamRequestBody. Otherwise, copy
the selected file to your app sandbox folder IE, app-specific
directory, then access the file from there without any permission.
Just see the below implementation that works in Android-Q and later.
Perform file search
private void performFileSearch(String messageTitle) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
intent.setType("application/*");
String[] mimeTypes = new String[]{"application/x-binary,application/octet-stream"};
if (mimeTypes.length > 0) {
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
}
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(Intent.createChooser(intent, messageTitle), OPEN_DIRECTORY_REQUEST_CODE);
} else {
Log.d("Unable to resolve Intent.ACTION_OPEN_DOCUMENT {}");
}
}
onActivityResult returned
#Override
public void onActivityResult(int requestCode, int resultCode, final Intent resultData) {
// The ACTION_OPEN_DOCUMENT intent was sent with the request code OPEN_DIRECTORY_REQUEST_CODE.
// If the request code seen here doesn't match, it's the response to some other intent,
// and the below code shouldn't run at all.
if (requestCode == OPEN_DIRECTORY_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
// The document selected by the user won't be returned in the intent.
// Instead, a URI to that document will be contained in the return intent
// provided to this method as a parameter. Pull that uri using "resultData.getData()"
if (resultData != null && resultData.getData() != null) {
new CopyFileToAppDirTask().execute(resultData.getData());
} else {
Log.d("File uri not found {}");
}
} else {
Log.d("User cancelled file browsing {}");
}
}
}
File writing to app specific path
public static final String FILE_BROWSER_CACHE_DIR = "CertCache";
#SuppressLint("StaticFieldLeak")
private class CopyFileToAppDirTask extends AsyncTask<Uri, Void, String> {
private ProgressDialog mProgressDialog;
private CopyFileToAppDirTask() {
mProgressDialog = new ProgressDialog(YourActivity.this);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog.setMessage("Please Wait..");
mProgressDialog.show();
}
protected String doInBackground(Uri... uris) {
try {
return writeFileContent(uris[0]);
} catch (IOException e) {
Log.d("Failed to copy file {}" + e.getMessage());
return null;
}
}
protected void onPostExecute(String cachedFilePath) {
mProgressDialog.dismiss();
if (cachedFilePath != null) {
Log.d("Cached file path {}" + cachedFilePath);
} else {
Log.d("Writing failed {}");
}
}
}
private String writeFileContent(final Uri uri) throws IOException {
InputStream selectedFileInputStream =
getContentResolver().openInputStream(uri);
if (selectedFileInputStream != null) {
final File certCacheDir = new File(getExternalFilesDir(null), FILE_BROWSER_CACHE_DIR);
boolean isCertCacheDirExists = certCacheDir.exists();
if (!isCertCacheDirExists) {
isCertCacheDirExists = certCacheDir.mkdirs();
}
if (isCertCacheDirExists) {
String filePath = certCacheDir.getAbsolutePath() + "/" + getFileDisplayName(uri);
OutputStream selectedFileOutPutStream = new FileOutputStream(filePath);
byte[] buffer = new byte[1024];
int length;
while ((length = selectedFileInputStream.read(buffer)) > 0) {
selectedFileOutPutStream.write(buffer, 0, length);
}
selectedFileOutPutStream.flush();
selectedFileOutPutStream.close();
return filePath;
}
selectedFileInputStream.close();
}
return null;
}
// Returns file display name.
#Nullable
private String getFileDisplayName(final Uri uri) {
String displayName = null;
try (Cursor cursor = getContentResolver()
.query(uri, null, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
displayName = cursor.getString(
cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
Log.i("Display Name {}" + displayName);
}
}
return displayName;
}
Here's a perhaps more general solution that allows the AsyncTask class to be separate, rather than embedded in an activity. It also returns a response to your activity when the task is complete, and uses a ProgressBar rather than the deprecated ProgressDialog.
The async task:
public class FileLoader extends AsyncTask<Uri, Void, String>
{
private WeakReference<Context> contextRef;
public AsyncResponse delegate = null;
public interface AsyncResponse {
void fileLoadFinish(String result);
}
FileLoader(Context ctx , AsyncResponse delegate) {
contextRef = new WeakReference<>(ctx);
this.delegate = delegate;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
protected String doInBackground(Uri... uris) {
Context context = contextRef.get();
ContentResolver contentResolver = context.getContentResolver();
Uri uri = uris[0];
try {
String mimeType = contentResolver.getType(uri);
Cursor returnCursor =
contentResolver.query(uri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
String fileName = returnCursor.getString(nameIndex);
InputStream inputStream = contentResolver.openInputStream(uri);
File downloadDir =
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
File f = new File(downloadDir + "/" + fileName);
FileOutputStream out = new FileOutputStream(f);
IOUtils.copyStream(inputStream,out);
returnCursor.close();
return f.getPath();
}
catch (Exception e){
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result) {
delegate.fileLoadFinish(result);
super.onPostExecute(result);
}
}
and in your activity:
private static final int DIR_ACCESS_REQUEST_CODE = 13;
public void performFileSearch() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/*");
String[] mimeTypes = new String[]{"application/gpx+xml","application/vnd.google-earth.kmz"};
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(Intent.createChooser(intent, "Choose KMZ or GPX file"), DIR_ACCESS_REQUEST_CODE);
} else {
Log.d("****File","Unable to resolve Intent.ACTION_OPEN_DOCUMENT");
}
}
#Override
public void onActivityResult(int requestCode, int resultCode,Intent resultData)
{
super.onActivityResult(requestCode, resultCode, resultData);
if (requestCode == DIR_ACCESS_REQUEST_CODE && resultCode == Activity.RESULT_OK)
{
if (resultData != null)
{
Uri uri = resultData.getData();
mProgressBar.setVisibility(View.VISIBLE);
new FileLoader(this,
new FileLoader.AsyncResponse(){
#Override
public void fileLoadFinish(String result){
processFile(new File(result));
mProgressBar.setVisibility(View.GONE);
}
}).execute(uri);
}
}
}
My example attempts to find either .kmz files or .gpx files. The progress bar (if you need one, for long-running file operations) needs to be initialised (and hidden) in OnCreate():
mProgressBar = findViewById(R.id.progressbar);
mProgressBar.setVisibility(View.GONE);
My 'processFile()' method takes a while manipulating a map in the main activity so I have waited until it's done before hiding the ProgressBar.
I remain surprised that it takes such a lot of code to perform such a simple operation: to copy a file and make it available for use!

Include media refresh my code?

I'm downloading image to a folder on the SDCARD. Since the images and my folder is not immediately visible in the Gallery I'm trying to get the Me update and show the folder/images in the gallery. Shows you how to do this in my code include?
private void downloadImage() {
if (future != null) {
//set the callback and start downloading
future.withResponse().setCallback(new FutureCallback<Response<InputStream>>() {
#Override
public void onCompleted(Exception e, Response<InputStream> result) {
boolean success = false;
if (e == null && result != null && result.getResult() != null) {
try {
//prepare the file name
String url = mSelectedImage.getUrl();
String fileName = url.substring(url.lastIndexOf('/') + 1, url.length());
//create a temporary directory within the cache folder
File dir = Utils.getAlbumStorageDir("wall-tx");
//create the file
File file = new File(dir, fileName);
if (!file.exists()) {
file.createNewFile();
}
//copy the image onto this file
Utils.copyInputStreamToFile(result.getResult(), file);
//animate the first elements
animateCompleteFirst(true);
//Broadcast the Media Scanner Intent to trigger it
success = true;
} catch (Exception ex) {
Log.e("walltx", ex.toString());
}
//animate after complete
animateComplete(success);
} else {
animateReset(true);
}
}
});
}
}

How to use MediaScannerConnection scanFile?

I'm downloading image to a folder on the SDCARD. Since the images and my folder is not immediately visible in the Gallery I'm trying to get the MediaScannerConnection to update and show the folder/images in the gallery.
Shows you how to do this in view code ?
private void downloadImage() {
if (future != null) {
//set the callback and start downloading
future.withResponse().setCallback(new FutureCallback<Response<InputStream>>() {
#Override
public void onCompleted(Exception e, Response<InputStream> result) {
boolean success = false;
if (e == null && result != null && result.getResult() != null) {
try {
//prepare the file name
String url = mSelectedImage.getUrl();
String fileName = url.substring(url.lastIndexOf('/') + 1, url.length());
//create a temporary directory within the cache folder
File dir = Utils.getAlbumStorageDir("wall-tx");
//create the file
File file = new File(dir, fileName);
if (!file.exists()) {
file.createNewFile();
}
//copy the image onto this file
Utils.copyInputStreamToFile(result.getResult(), file);
//animate the first elements
animateCompleteFirst(true);
//Broadcast the Media Scanner Intent to trigger it
success = true;
} catch (Exception ex) {
Log.e("walltx", ex.toString());
}
//animate after complete
animateComplete(success);
} else {
animateReset(true);
}
}
});
}
}
MediaScannerConnection.scanFile(this, new String[]{file.getPath()},
null, new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
// now visible in gallery
}
});

I can not see download image in gallery until I restart the phone

When I download an image and save it to the Android device the image does not appear in the gallery, later after the phone is restarted the images are in the gallery.
Here is the code where I download the images and save them to the device:
private void downloadImage() {
if (future != null) {
//set the callback and start downloading
future.withResponse().setCallback(new FutureCallback<Response<InputStream>>() {
#Override
public void onCompleted(Exception e, Response<InputStream> result) {
boolean success = false;
if (e == null && result != null && result.getResult() != null) {
try {
//prepare the file name
String url = mSelectedImage.getUrl();
String fileName = url.substring(url.lastIndexOf('/') + 1, url.length());
//create a temporary directory within the cache folder
File dir = Utils.getAlbumStorageDir("wall-tumbler");
//create the file
File file = new File(dir, fileName);
if (!file.exists()) {
file.createNewFile();
}
//copy the image onto this file
Utils.copyInputStreamToFile(result.getResult(), file);
//animate the first elements
animateCompleteFirst(true);
success = true;
} catch (Exception ex) {
Log.e("walltumbler", ex.toString());
}
//animate after complete
animateComplete(success);
} else {
animateReset(true);
}
}
});
}
}
#TargetApi(Build.VERSION_CODES.KITKAT)
private void downloadAndSetOrShareImage(final boolean set) {
if (future != null) {
//set the callback and start downloading
future.withResponse().setCallback(new FutureCallback<Response<InputStream>>() {
#Override
public void onCompleted(Exception e, Response<InputStream> result) {
boolean success = false;
if (e == null && result != null && result.getResult() != null) {
try {
//create a temporary directory within the cache folder
File dir = new File(DetailActivity.this.getCacheDir() + "/images");
if (!dir.exists()) {
dir.mkdirs();
}
//create the file
File file = new File(dir, "walltumbler.jpg");
if (!file.exists()) {
file.createNewFile();
}
//copy the image onto this file
Utils.copyInputStreamToFile(result.getResult(), file);
//get the contentUri for this file and start the intent
Uri contentUri = FileProvider.getUriForFile(DetailActivity.this, "com.mikepenz.fileprovider", file);
if (set) {
//get crop intent
Intent intent = WallpaperManager.getInstance(DetailActivity.this).getCropAndSetWallpaperIntent(contentUri);
//start activity for result so we can animate if we finish
DetailActivity.this.startActivityForResult(intent, ACTIVITY_CROP);
} else {
//share :D
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setData(contentUri);
shareIntent.setType("image/jpg");
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
//start activity for result so we can animate if we finish
DetailActivity.this.startActivityForResult(Intent.createChooser(shareIntent, "Share Via"), ACTIVITY_SHARE);
}
success = true;
} catch (Exception ex) {
Log.e("walltumbler", ex.toString());
}
//animate after complete
animateComplete(success);
} else {
animateReset(true);
}
}
});
}
}
Utils
/**
* http://developer.android.com/training/basics/data-storage/files.html
*
* #param albumName
* #return
*/
public static File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
boolean success = false;
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), albumName);
if (!file.exists()) {
success = file.mkdir();
}
if (!success)
Log.i("wall-tumbler", "Directory not created");
else
Log.i("wall-tumbler", "Directory created");
return file;
}
/**
* http://developer.android.com/training/basics/data-storage/files.html
*
* #return
*/
public static boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
}
ScreenShot
http://i.stack.imgur.com/6dkp0.jpg
You should use the MediaStore content provider to add an image to the gallery.
ContentValues values = new ContentValues();
values.put(Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.MediaColumns.DATA, imagePath);
context.getContentResolver().insert(Images.Media.EXTERNAL_CONTENT_URI, values);

How to upload my recorded audio on dropbox using android?

Right now i am creating application based on android and dropbox.
I want to upload my recorded audio on dropbox based on my api key but i have tried lot in it. i cant find solution so any one can help me to overcome this situation.
Here is my code. I have done image capture and video capture with help of this code. The code was working fine but when i converting into my audio recorder it does't work. Thanks for the reply.
Audio recorder function:
mAudio=(Button)findViewById(R.id.audio_button);
mAudio.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
// Picture from camera
intent.setAction(Audio.Media.RECORD_SOUND_ACTION);
Uri fileUri = getOutputMediaFileUri(MEDIA_TYPE_AUDIO);
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, fileUri);
Log.i(TAG, "Importing New Picture: " + mCameraFileName);
try {
startActivityForResult(intent, NEW_AUDIO);
} catch (ActivityNotFoundException e) {
showToast("There doesn't seem to be a camera.");
}
}
});
Upload Function:
else if(requestCode == NEW_AUDIO){
if (resultCode == Activity.RESULT_OK) {
Uri uri = null;
if (data != null) {
uri = data.getData();
}
if (uri == null && mAudioFileName != null) {
uri = Uri.fromFile(new File(mAudioFileName));
Log.v("Audio Uri", uri.toString()+" "+uri.getPath());
}
File file = new File(mAudioFileName);
Log.v("Audio file", ""+file.getPath());
if (uri != null) {
UploadFile upload = new UploadFile(Home.this, mApi, PHOTO_DIR, file);
upload.execute();
}
//showToast("till capture");
}
else if(resultCode == RESULT_CANCELED)
{
uriAudio = null;
Toast.makeText(Home.this,"Cancelled!",Toast.LENGTH_LONG).show();
}
As per official example given on site. I hope this will help you.
FileInputStream inputStream = null;
try {
File file = new File("/path/to/file.txt");
inputStream = new FileInputStream(file);
Entry newEntry = mDBApi.putFile("/testing.txt", inputStream,
file.length(), null, null);
Log.i("DbExampleLog", "The uploaded file's rev is: " + newEntry.rev);
} catch (DropboxUnlinkedException e) {
// User has unlinked, ask them to link again here.
Log.e("DbExampleLog", "User has unlinked.");
} catch (DropboxException e) {
Log.e("DbExampleLog", "Something went wrong while uploading.");
} catch (FileNotFoundException e) {
Log.e("DbExampleLog", "File not found.");
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {}
}
}

Categories

Resources