I'm working on backup and restore SQLite Database to cloud server. I've completed the backup code and it works. However, I have a problem when I'm trying to restore it. The problem is, on Android 11, the Environment.DIRECTORY_DOWNLOADS is in Android/data/package/files/Download, but somehow I cannot access or write to Environment.DIRECTORY_DOWNLOADS, and I don't know why. Here's my code (the download from cloud method, it succeeds).
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
Uri uri = Uri.parse(response.body().getPath());
DownloadManager.Request request = new DownloadManager.Request(uri);
request.setDestinationInExternalFilesDir(getApplicationContext(), Environment.DIRECTORY_DOWNLOADS, sharedPreference.getUser().getEmail() + ".db");
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
request.setTitle(sharedPreference.getUser().getEmail() + ".db");
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
Long downloadReference = manager.enqueue(request);
When I'm trying to access them, I cannot access the Environment.DIRECTORY_DOWNLOADS. Here is the code
File internal = new File(Environment.DIRECTORY_DOWNLOADS);
if (internal.canRead()) {
File currentDB = new File("/data/data/" + getPackageName() + "/databases/", DBHelper.DATABASE_NAME);
File backupDB = new File(internal, sharedPreference.getUser().getEmail() + ".db");
Toast.makeText(getApplicationContext(),backupDB.toString(),Toast.LENGTH_SHORT).show();
if (backupDB.exists()) {
FileChannel src = new FileInputStream(backupDB).getChannel();
FileChannel dst = new FileOutputStream(currentDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
progressDialog.dismiss();
Toast.makeText(getApplicationContext(), backupDB.toString(), Toast.LENGTH_SHORT).show();
} else {
progressDialog.dismiss();
Toast.makeText(getApplicationContext(), "Error, file not exist!", Toast.LENGTH_SHORT).show();
}
} else {
progressDialog.dismiss();
Toast.makeText(getApplicationContext(), "Error, cannot read the directory!", Toast.LENGTH_SHORT).show();
}
Related
I have upgraded to android 11. I am having an issue downloading PDF files.
I have used this code:
private void createFile(Uri pickerInitialUri, String title) {
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/pdf");
intent.putExtra(Intent.EXTRA_TITLE, title);
// Optionally, specify a URI for the directory that should be opened in
// the system file picker when your app creates the document.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
}
startActivityForResult(intent, CREATE_FILE);
}
The file is created but the file is empty. I am still unable to save the downloaded pdf file.
I used to use DownloadManager request to download the pdf file from web.
DownloadManager downloadManager = (DownloadManager) this.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(uri);
if (SDK_INT > Build.VERSION_CODES.Q) {
// Uri uri1 = Uri.fromFile(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "")); //before android 11 this was working fine
// Uri uri1 = Uri.fromFile(new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), ""));
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(true).setTitle(title + strDate + ".pdf")
.setDescription(description)
//.setDestinationUri(uri1) // before android 11 it was working fine.
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, title + strDate + ".pdf") // file is not saved on this directory.
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);//to show the DOWNLOAD notification when completed
// createFile(uri , title + strDate + ".pdf"); // for new scoped storage
} else {
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(true).setTitle(title + strDate + ".pdf")
.setDescription(description)
.setDestinationInExternalPublicDir(FileUtils.downloadPdfDestination(), title + strDate + ".pdf")
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //to show the DOWNLOAD notification when completed
}
long PDF_DOWNLOAD_ID = downloadManager.enqueue(request);```
ACTION_CREATE_DOCUMENT is used to create a new document. If one already existed, it will be overwritten. If you want to view an existing document, use ACTION_VIEW.
Of course none of the code you posted actually downloads a PDF. If you need help with that, post your DownloadManager code.
Check this code snippet:
override fun startDownload(url: String, onError: (e: Exception) -> Unit) {
try {
val request = DownloadManager.Request(Uri.parse(url))
request.setDestinationInExternalPublicDir(
Environment.DIRECTORY_DOWNLOADS,
UUID.randomUUID().toString()
)
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION)
(context.getSystemService(DOWNLOAD_SERVICE) as DownloadManager).enqueue(request)
} catch (e: Exception) {
e.printStackTrace()
onError.invoke(e)
}
}
It's working fine on Android 11 by using DownloadManger API.
Use below code to download & view pdf.
First you need to apply rxjava dependency for background task.
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
Don't forgot to check WRITE_EXTERNAL_STORAGE permission before call below method. Also check INTERNET permission as well.
Then use below method to perform operation in background.
private void downloadAndOpenInvoice() {
mDialog.show();
Observable.fromCallable(() -> {
String pdfName = "Invoice_"+ Calendar.getInstance().getTimeInMillis() + ".pdf";
String pdfUrl = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf";
File file = CommonUtils.downloadFile(mActivity, pdfUrl, pdfName,mDialog);
return file;
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(file -> {
CommonUtils.viewPdf(file, mActivity, mDialog);
});
}
To download file from url use below snippet
public static File downloadFile(Activity mActivity, String url, String fileName, CustomDialog mDialog) {
// write the document content
File fileDir = new File(CommonUtils.getAppDir(mActivity, "Invoice")); //Invoice folder inside your app directory
if (!fileDir.exists()) {
boolean mkdirs = fileDir.mkdirs();
}
File pdfFile = new File(CommonUtils.getAppDir(mActivity, "Invoice"), fileName); //Invoice folder inside your app directory
try {
URL u = new URL(url);
URLConnection conn = u.openConnection();
int contentLength = conn.getContentLength();
DataInputStream stream = new DataInputStream(u.openStream());
byte[] buffer = new byte[contentLength];
stream.readFully(buffer);
stream.close();
DataOutputStream fos = new DataOutputStream(new FileOutputStream(pdfFile));
fos.write(buffer);
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
if (mDialog.isShowing()) {
mDialog.dismiss();
}
Toast.makeText(mActivity, "Something wrong: " + e.toString(), Toast.LENGTH_LONG).show();
}
return pdfFile;
}
for app directory
public static String getAppDir(Context context, String folderName) {
return context.getExternalFilesDir(null).getAbsolutePath() + File.separator + folderName + File.separator;
}
Use below code to view pdf
public static void viewPdf(File pdfFile, Activity mActivity, CustomDialog mDialog) {
Uri uri = FileProvider.getUriForFile(mActivity, mActivity.getApplicationContext().getPackageName() + ".provider", pdfFile);
// Setting the intent for pdf reader
Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
pdfIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
pdfIntent.setDataAndType(uri, "application/pdf");
//pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
mActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
if (mDialog.isShowing()) {
mDialog.dismiss();
}
}
});
mActivity.startActivity(pdfIntent);
Log.e("Invoice - PDF", pdfFile.getPath());
} catch (ActivityNotFoundException e) {
mActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
if (mDialog.isShowing()) {
mDialog.dismiss();
}
}
});
e.printStackTrace();
Log.e("Invoice - PDF", "Can't read pdf file");
Toast.makeText(mActivity, "Can't read pdf file", Toast.LENGTH_SHORT).show();
}
}
I try, to check if this file exists after i downloaded it, but its says to me that is doesnt exist
#Override
public void handleResult(Result result)
{
myResult = result;
dm = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
Uri uri = Uri.parse(result.getText());
DownloadManager.Request request = new DownloadManager.Request(uri);
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
String nameOfFile = URLUtil.guessFileName(result.getText(),null, MimeTypeMap.getFileExtensionFromUrl(result.getText()));
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, nameOfFile);
dm.enqueue(request);
String erg = "";
File mPath = new File((Environment.DIRECTORY_DOWNLOADS + "/" + nameOfFile));
if (mPath.getAbsoluteFile().exists()) {
erg = "existiert";
}else
{
erg = "existiert nicht";
}
}
The downloading process is happening on background. So after enqueue() your file doesn't exist cause it's not downloaded yet.
You just need to register BroadcastReceiver with this
ACTION_DOWNLOAD_COMPLETE intent filter. And DownloadManager will broadcast when downloads complete. See documentation here: https://developer.android.com/reference/android/app/DownloadManager.html#ACTION_DOWNLOAD_COMPLETE
I am trying to create file in internal storage and then send it via email in Android.
However, I still get file not found or similar errors.
Please, help!
String FILENAME = "TestFile.txt";
Sending file by button click
btnSendFile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
File gpxfile = getFile();
Uri path = Uri.fromFile(gpxfile);
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("message/rfc822");
Context context = v.getContext();
String email = "MYEMAILHERE";
i.putExtra(Intent.EXTRA_EMAIL, new String[]{email});
i.putExtra(Intent.EXTRA_SUBJECT, "Subject");
i.putExtra(Intent.EXTRA_TEXT, "Text");
i.putExtra(Intent.EXTRA_STREAM, path);
context.startActivity(Intent.createChooser(i, context.getString("Sending...")));
}
});
}
Creating file in internal storage
private void createTestFile() {
try {
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_APPEND);
fos.write("Your content".getBytes());
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Get file function. Return File if file exists
private File getFile() {
return new File(getFilesDir() + "/" + FILENAME);
}
Maybe you need to make
Context.openFileOutput(FILENAME, Context.MODE_APPEND);
Instead of that one you used? I think someone had similiar problem over here: android what is wrong with openFileOutput?
The question is pretty common and I have googled it but it still wont work. I'm simply trying to save a text file using the below code:
String state = Environment.getExternalStorageState();
if (!Environment.MEDIA_MOUNTED.equals(state)) {
Toast.makeText(getApplicationContext(), "Access denied", Toast.LENGTH_LONG).show();
}
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/data";
File dir = new File(path);
dir.mkdirs();
File file = new File(path + "/savedFile.txt");
String saveText = new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime());
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
try {
fos.write(saveText.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Toast.makeText(getApplicationContext(), "Saved", Toast.LENGTH_LONG).show();
break;
and in my manifest I have declared:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
However everytime I try and run the code the app crashes with the error 'Unfortunately, APP_NAME has stopped." Can anyone tell me what is wrong with my code?
if ((checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)&& Build.VERSION.SDK_INT >= 23 ) {
Log.v(TAG,"Permission is granted");
return true;}
else{
ActivityCompat.requestPermissions(this, new String[]Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
String state = Environment.getExternalStorageState();
if (!Environment.MEDIA_MOUNTED.equals(state)) {
Toast.makeText(getApplicationContext(), "Access denied", Toast.LENGTH_LONG).show();
}
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/data";
File dir = new File(path);
dir.mkdirs();
File file = new File(path + "/savedFile.txt");
String saveText = new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime());
try {
fos = new FileOutputStream(file);
OutputStreamWriter ow = new OutputStreamWriter(fos);
ow.write(saveText.getBytes());
ow.append(saveText.getText());
ow.close();
fos.close();
Toast.makeText(getBaseContext(),
"Done writing SD 'mysdfile.txt'",Toast.LENGTH_SHORT).show();
}} catch (Exception e) {
Toast.makeText(getBaseContext(), e.getMessage(),Toast.LENGTH_SHORT).show();
}
}
}
You need to use something like this code.Because you need to specify runtime permissions.Marshmallow needs you to check the permissions first to use respective resources.
Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app. This approach streamlines the app install process, since the user does not need to grant permissions when they install or update the app. It also gives the user more control over the app's functionality; for example, a user could choose to give a camera app access to the camera but not to the device location. The user can revoke the permissions at any time, by going to the app's Settings screen
I am trying to programmatically change a ringtone in API 23.
I have looked at a lot of examples on Stack Overflow and they all seem to "work" (i.e. not crash) but they do not "work" as in the mp3 doesn't become the ringtone - instead the ringtone becomes simply zero noise. So obviously /something/ happened. (no crash, now no ringtone noise)
I have split this off into a small side project to try to isolate it because it's driving me up the wall - I hope maybe you guys can see something I can't!
I have:
placed the mp3 in \res\raw
I have verified I can play the mp3 fine with this code
MediaPlayer mPlayer = MediaPlayer.create(me, R.raw.meepmeep);
mPlayer.start();
added <uses-permission android:name="android.permission.WRITE_SETTINGS"/> to the manifest
managed the api 22 permission scenario in java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.System.canWrite(this)) {
new AlertDialog.Builder(this)
.setMessage("Please Assign Meep Meep Write Permissions")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
startActivity(intent);
} catch (Exception e) {
Log.e("MainActivity", "error starting permission intent", e);
}
}
})
.show();
return;
}
used a method to carefully fetch the mp3 path from the assets folder
public String LoadFile(String fileName, boolean loadFromRawFolder) throws IOException
{
InputStream iS;
if (loadFromRawFolder)
{
int rID = resources.getIdentifier("meep.example.com.meep:raw/"+fileName, null, null);
iS = resources.openRawResource(rID);
}
else
{
iS = resources.getAssets().open(fileName);
}
byte[] buffer = new byte[iS.available()];
iS.read(buffer);
ByteArrayOutputStream oS = new ByteArrayOutputStream();
oS.write(buffer);
oS.close();
iS.close();
return oS.toString();
}
tried to carefully copy the file to the local storage (as a desperate attempt to get it to work as well as tried to assign it from the raw assets lib
String path = "";
try {
LoadFile("meepmeep", true);
} catch (IOException e) {
//display an error toast message
Toast toast = Toast.makeText(me, "File: not found!", Toast.LENGTH_LONG);
toast.show();
}
//copy file to device
File newSoundFile = new File(path);
//Uri mUri = Uri.parse("android.resource://meep.example.com.meep/R.raw.meepmeep");
Uri mUri = MediaStore.Audio.Media.getContentUriForPath(newSoundFile.getAbsolutePath());
ContentResolver mCr = getContentResolver();
AssetFileDescriptor soundFile;
try {
soundFile= mCr.openAssetFileDescriptor(mUri, "r");
try {
byte[] readData = new byte[1024];
FileInputStream fis = soundFile.createInputStream();
FileOutputStream fos = new FileOutputStream(newSoundFile);
int i = fis.read(readData);
while (i != -1) {
fos.write(readData, 0, i);
i = fis.read(readData);
}
fos.close();
} catch (IOException io) {
}
} catch (FileNotFoundException e) {
soundFile=null;
}
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DATA, newSoundFile.getAbsolutePath());
values.put(MediaStore.MediaColumns.TITLE, "Meep Meep");
values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mp3");
values.put(MediaStore.MediaColumns.SIZE, newSoundFile.length());
values.put(MediaStore.Audio.Media.ARTIST, "RoadRunner");
//values.put(MediaStore.Audio.Media.DURATION, 230);
values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true);
values.put(MediaStore.Audio.Media.IS_ALARM, true);
values.put(MediaStore.Audio.Media.IS_MUSIC, false);
//Insert it into the database
Uri uri = MediaStore.Audio.Media.getContentUriForPath(newSoundFile.getAbsolutePath());
Uri newUri = mCr.insert(uri, values);
try {
RingtoneManager.setActualDefaultRingtoneUri(
me,
RingtoneManager.TYPE_RINGTONE,
newUri
);
}
catch (Throwable t){
setMessage("meepmeep error");
}
setMessage("meepmeep set");
}
but nothing seems to work. It always fails becuase either soundFile= mCr.openAssetFileDescriptor(mUri, "r"); returns null or if I decline to use that code block and try to change ringtone direct from \res\raw\ folder then it simply gives a blank sound for ringtone.
I am totally stuck for ideas?