(to make things clearer :) I am using WebView. The idea is that users can visit any page and download any file, the idea is to support as many basic features as i can to get closer feel to built in web browser.
As the title says, i am trying to make my app download files and open them once theyre downloaded. There are some bullet points i want to mention :
user should be able to download any kind of file (i guess its called mimeType), as they would in they default internet browser app
since users download items from webview, it would only make sense if downloads would appear in downloads folder
would be awesome if every users device could decide on itself which app to use to open downloaded file, but, for example, my samsung s9 asks which app to use, thats not a bad option either
i ran across some problems like sucessful download, but the file was empty/corrupted, the downlaoded file was missing in file browser even if app told me that the download is completed
So i have been on not 2nd, not 3rd but even 5th page of google search results, so ive seen a lot, these are couple versions of my code so far, every single one of them are not working as i expected them in my dreams.
Just to be clear, the code you are about to see is under webview setDownloadListener(new DownloadListener() ...
So my latest version, without file opening after download :
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
//used to call a class to in previous code version to make some downloads
//new DownloadTask(webview_base.this, url, mimeType);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)).setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |
DownloadManager.Request.NETWORK_MOBILE);
// in order for this if to run, you must use the android 3.2 to compile your app
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, url.substring(url.lastIndexOf('/')));
// get download service and enqueue file
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
}
});
the problem with ^ this version was that i was able to download files, but it downlaoded pages HTML instead of actual pdf or whatever i was aiming for, thats weird.
previous version was a bit smoother, i was able to download files, and i used a dialog to offer to open a file. Everything worked fine, but documents were empty/corrupted and i got offered to open them with weird apps, for example, once i got asked to open pdf with my smartwatch app, but that mustve gone away since i edited a code time by time. The problem i landed here was that even after couple of ctrl+z i wasnt able to get my app back on feets - i was stuck at download screen and logcat shout at me that it couldnt fine a download directory. at that point i got mad and started the version you can see above. Anyway, here is the whole class :
package com.example.viaapp_v2;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import androidx.core.content.FileProvider;
public class DownloadTask extends FileProvider {
private static final String TAG = "Download Task";
private Context context;
String mimeType;
private String downloadUrl = "", downloadFileName = "";
private ProgressDialog progressDialog;
public DownloadTask() {
//required empty constructor
}
public DownloadTask(Context context, String downloadUrl, String mime) {
this.context = context;
this.downloadUrl = downloadUrl;
this.mimeType = mime;
//Create file name by picking download file name from URL
downloadFileName = downloadUrl.substring(downloadUrl.lastIndexOf('/'));
//Start Downloading Task
new DownloadingTask().execute();
}
private class DownloadingTask extends AsyncTask<Void, Void, Void> {
File apkStorage = null;
File outputFile = null;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(context);
progressDialog.setMessage("Downloading...");
progressDialog.setCancelable(false);
progressDialog.show();
}
#Override
protected void onPostExecute(Void result) {
try {
if (outputFile != null) {
progressDialog.dismiss();
final ContextThemeWrapper ctw = new ContextThemeWrapper( context, R.style.Theme_AppCompat_Light_Dialog);
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ctw);
alertDialogBuilder.setTitle("Document ");
alertDialogBuilder.setMessage(downloadFileName+" Downloaded Successfully ");
alertDialogBuilder.setCancelable(false);
alertDialogBuilder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
});
alertDialogBuilder.setNegativeButton("Open file",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
try {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString()
+ downloadFileName);//name here is the name of any string you want to pass to the method
if (!file.isDirectory())
file.mkdir();
Intent testIntent = new Intent();
testIntent.setType(mimeType);
testIntent.setAction(Intent.ACTION_VIEW);
Uri uri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", file);
testIntent.setDataAndType(uri, mimeType);
ctw.startActivity(testIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
});
alertDialogBuilder.show();
} else {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
}
}, 3000);
Log.e(TAG, "Download Failed");
}
} catch (Exception e) {
e.printStackTrace();
//Change button text if exception occurs
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
}
}, 3000);
Log.e(TAG, "Download Failed with Exception - " + e.getLocalizedMessage());
}
super.onPostExecute(result);
}
#Override
protected Void doInBackground(Void... arg0) {
try {
URL url = new URL(downloadUrl);//Create Download URl
HttpURLConnection c = (HttpURLConnection) url.openConnection();//Open Url Connection
c.setRequestMethod("GET");//Set Request Method to "GET" since we are grtting data
c.connect();//connect the URL Connection
//If Connection response is not OK then show Logs
if (c.getResponseCode() != HttpURLConnection.HTTP_OK) {
Log.e(TAG, "Server returned HTTP " + c.getResponseCode()
+ " " + c.getResponseMessage());
}
//Get File if SD card is present
if (new CheckForSDCard().isSDCardPresent()) {
apkStorage = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString());
} else
Toast.makeText(context, "Oops!! There is no SD Card.", Toast.LENGTH_SHORT).show();
//If File is not present create directory
if (!apkStorage.exists()) {
apkStorage.mkdir();
Log.e(TAG, "Directory Created.");
}
outputFile = new File(apkStorage, downloadFileName);//Create Output file in Main File
//Create New File if not present
if (!outputFile.exists()) {
outputFile.createNewFile();
Log.e(TAG, "File Created");
}
FileOutputStream fos = new FileOutputStream(outputFile);//Get OutputStream for NewFile Location
InputStream is = c.getInputStream();//Get InputStream for connection
byte[] buffer = new byte[1024];//Set buffer type
int len1 = 0;//init length
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);//Write new file
}
//Close all connection after doing task
fos.close();
is.close();
} catch (Exception e) {
//Read exception if something went wrong
e.printStackTrace();
outputFile = null;
Log.e(TAG, "Download Error Exception " + e.getMessage());
}
return null;
}
}
private class CheckForSDCard {
//Check If SD Card is present or not method
boolean isSDCardPresent() {
return Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED);
}
}
}
Looking for my manifest file ? Well here it goes .. ive put in some support for file upload, file download, internet acces, ect
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.CAMERA"/>
i even tried to put some provider stuff in application
<provider
android:name=".DownloadTask"
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>
But deep inside i had no idea what to put in provider path file
<paths><external-path name="external_files" path="."/></paths>
Sorry that this text is so long. Im just desperate and almost done with my project, but i have to seek for help somewhere to keep going. I hope ive explained my problem enough and provided enough code, would be happy to know which code is better / more possible ( make a class or write everything down right under listener ).
--- EDIT ---
So.. i tried to run my old version of code, which is that long block of code above, class file "DownloadTask.java", which is called by constructor, passing utl, mimetype and context. You can see the line commented in the first block of code in this post, 3rd line. Here is what happened : i visited a page, clicked on a link to download pdf file, but then i got stuck on dialog that shows "downloading.." while logcat said this :
D/ViewRootImpl#19478bd[webview_base]: MSG_RESIZED: frame=Rect(18, 617 - 701, 821) ci=Rect(0, 0 - 0, 0) vi=Rect(0, 0 - 0, 0) or=1
D/ViewRootImpl#c47c382[webview_base]: Relayout returned: old=[0,0][720,1480] new=[0,0][720,1480] result=0x1 surface={valid=true 484837122048} changed=false
I/ample.viaapp_v: Compiler allocated 4MB to compile void android.widget.TextView.<init>(android.content.Context, android.util.AttributeSet, int, int)
I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
W/System.err: java.io.FileNotFoundException: /storage/emulated/0/Download/Datu%20p%C4%81rraides%20t%C4%ABkli-III_LV.pdf (Is a directory)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:308)
at java.io.FileOutputStream.<init>(FileOutputStream.java:238)
at java.io.FileOutputStream.<init>(FileOutputStream.java:180)
at com.example.viaapp_v2.DownloadTask$DownloadingTask.doInBackground(DownloadTask.java:173)
at com.example.viaapp_v2.DownloadTask$DownloadingTask.doInBackground(DownloadTask.java:54)
W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
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)
E/Download Task: Download Error Exception /storage/emulated/0/Download/Datu%20p%C4%81rraides%20t%C4%ABkli-III_LV.pdf (Is a directory)
E/Download Task: Download Failed
D/ViewRootImpl#19478bd[webview_base]: MSG_WINDOW_FOCUS_CHANGED 1 1
And yes, as you can see, the file name contais accented letters, thats why its so weird, 99% of users which are willing to use the app, will work around content which uses accented letters so im wondering mayeb i should replace filenames without all these letters like "āēīģčķ" to "aeigck".
Related
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
//activity A intent
Intent intent = new Intent(Intent.ACTION_PICK,null);
intent.setType("image/*");
intent.putExtra("return-data", true);
startActivityForResult(intent,Constant.ACTION.LOAD_GALLERY_ACTION);
//this is onActicityResult function
case Constant.ACTION.LOAD_GALLERY_ACTION:
Uri uri = data.getData();
if(mImage.size()<maxAddPic) {
mImage.add(copyGalleryPic(uri));
adapter.notifyDataSetChanged();
}
break;
//to copy the gallery photo,return the new file uri.
private Uri copyGalleryPic(Uri uri) {
String filePath = Environment.getExternalStorageDirectory() + "/images/"+"diary"+System.currentTimeMillis()+".jpg";
File outputFile = new File(filePath);
if (!outputFile.getParentFile().exists()) {
outputFile.getParentFile().mkdirs();
}
Bitmap bitmap;
try (FileOutputStream fos = new FileOutputStream(outputFile)) {
bitmap=MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
bitmap.compress(Bitmap.CompressFormat.JPEG,100,fos);
} catch (IOException e) {
// ... handle IO exception
}
Uri newUri = FileProvider.getUriForFile(CreateDiaryActivity.this,"com.example.diary.cr",outputFile);
return newUri;
}
but there are some errors
the intent returns uri
"content://com.google.android.apps.photos.contentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F29/ORIGINAL/NONE/41130179"
but debug info shows the code
"bitmap=MediaStore.Images.Media.getBitmap(getContentResolver(),
uri);" error : java.io.FileNotFoundException: open failed: ENOENT
(No such file or directory)
please help me ! Love you guys!
My English is not well. please use Simple words. Thank you!
which android version and which sdk-version are you using? I have an android-2.2 app that cannot receive intent permissions under android 7 see: https://github.com/k3b/intent-intercept/issues/4. I assume that recompiling with a more recent android-sdk might help.
Does you program work if you use an InputStream to read the picked image via getContentResolver().openInputStream(data.getData(uri)).
Since android-4.4 ACTION_PICK was replaced by ACTION_OPEN_DOCUMENT. My recent apps that use ACTION_OPEN_DOCUMENT together with openInputStream work as expected
I have a method that tries to extract m3u files, but it doesn't work at api level 29. I get the following error on the Logcat screen:
2019-10-03 20:46:53.165 32591-417/? E/Google: java.io.IOException: Cleartext HTTP traffic to mysite.tk not permitted
My Method:
#SuppressLint("StaticFieldLeak")
class _loadFile extends AsyncTask<String, Void, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
spinner.setVisibility(View.VISIBLE);
}
#Override
protected Boolean doInBackground(String... strings) {
try { //new FileInputStream (new File(name)
is = new FileInputStream(new File(strings[0])); // if u r trying to open file from asstes InputStream is = getassets.open(); InputStream
M3UPlaylist playlist = parser.parseFile(is);
mAdapter.update(playlist.getPlaylistItems());
return true;
} catch (Exception e) {
Log.d("Google", "_loadFile: " + e.toString());
return false;
}
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
spinner.setVisibility(View.GONE);
}
}
EDİT:
I gave ClearText permission, but a new error appeared.
Google: _loadFile: java.io.FileNotFoundException: /storage/emulated/0/Netuptv/data.m3u: open failed: ENOENT (No such file or directory)
EDİT:
My file path. I think the problem is here. But I don't have the information to solve it.
static final File DEFA = Environment.getExternalStorageDirectory();
public static final File dir = new File(DEFA.getPath() + "/Netuptv");
static final File filepath = new File(dir.getPath() + "/data.m3u");
Please check if you added this line android:usesCleartextTraffic="true" to your Manifest.
Since the file access API is deprecated on Android Q, I highly recommend to you to read this article by CommaneWare , as mention on this article, try to use android:requestLegacyExternalStorage="true" to avoid the file access issues
Try the following :
String fileName = "data.m3u";
File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
+ "/Netuptv");
boolean success = true;
if (!storageDir.exists()) {
success = storageDir.mkdirs();
}
if (success) {
File file = new File(storageDir,fileName);
filepath = file.getAbsolutePath();
}
With Android 10 (api level 29) file access is deprecated, it's called scoped storage.
A quick but not permanent fix for testing on Android 11:
Adding android:requestLegacyExternalStorage="true"
and changing
compileSdkVersion 29
targetSdkVersion 29
both to 29 in build.gradle
Good evening, I'm developing an android app, it has SQLite database, I need a way to copy the database to the external storage of the device, where I can copy to another device and so I can import the database into the another device.
For example:
Suppose the application calls "example", the database is in the "/data/data/com.gnd.example/databases" folder and it is called data.db, need to copy it to the "example / backup" folder ", for example" / storage / emulated / 0 / Example / Backup ". This is the first part.
The second part is the import, where the application should copy the file from the "example / import" folder to the folder "/data/data/com.gnd.example/databases"
For this I have a two button activity, btn_export and btn_import.
I have already relied on the following solutions:
import / export to android sqlite database
Simple export and import of SQLite database on Android
I already inserted it in AndroidManifest
How do I ask the user for permission?
I tried copying using this code that I took in one of the examples
private void backupDatabase () throws IOException {
String inFileName = "/data/data/com.gnd.example/databases/dados.db";
File dbFile = new File (inFileName);
FileInputStream fis = new FileInputStream (dbFile);
String outFileName = Environment.getExternalStorageDirectory () + "/ example / backup / data.db";
OutputStream output = new FileOutputStream (outFileName);
byte [] buffer = new byte [1024];
int length;
while ((length = fis.read (buffer))> 0) {
output.write (buffer, 0, length);
}
output.flush ();
output.close ();
fis.close ();
}
The button looks like this:
#Override
public void onClick (View view) {
try {
backupDatabase ();
} catch (IOException e1) {
e1.printStackTrace ();
}
});
Log when I press the button:
07/01 19:35:39: Launching app
$ adb shell am start -n "com.gnd.keepkey / com.gnd.keepkey.Telephone" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Client not ready yet..Waiting for process to come online
Waiting for process to come online
Connected to process 27724 on device motorola-moto_z2_play-0039635857
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I / zygote: Do partial code cache collection, code = 20KB, data = 29KB
I / zygote: After code cache collection, code = 20KB, data = 29KB
Increasing code cache capacity to 128KB
I / zygote: Do partial code cache collection, code = 20KB, data = 47KB
I / zygote: After code cache collection, code = 20KB, data = 47KB
Increasing code cache capacity to 256KB
I / zygote: Compiler allocated 4MB to compile void android.widget.TextView. <Init> (android.content.Context, android.util.AttributeSet, int, int)
I / zygote: Full code cache collection, code = 120KB, data = 82KB
I / zygote: After code cache collection, code = 117KB, data = 62KB
I / zygote: Do partial code cache collection, code = 125KB, date = 79KB
I / zygote: After code cache collection, code = 125KB, data = 79KB
Increasing code cache capacity to 512KB
W / System.err: java.io.FileNotFoundException: /storage/emulated/0/teste/dados.db (No such file or directory)
at java.io.FileOutputStream.open0 (Native Method)
W / System.err: at java.io.FileOutputStream.open (FileOutputStream.java:287)
at java.io.FileOutputStream. <init> (FileOutputStream.java:223)
at java.io.FileOutputStream. <init> (FileOutputStream.java:110)
at com.gnd.keepkey.funcoes.Exportar_Importar.backupDatabase (Export_Importar.java:87)
at com.gnd.keepkey.funcoes.Exportar_Importar.access $ 000 (Export_Importar.java:42)
at com.gnd.keepkey.funcoes.Export_Import $ 1.onClick (Export_Import.java:69)
W / System.err: at android.view.View.performClick (View.java:6259)
at android.view.View $ PerformClick.run (View.java:24732)
at android.os.Handler.handleCallback (Handler.java:789)
at android.os.Handler.dispatchMessage (Handler.java:98)
at android.os.Looper.loop (Looper.java:164)
at android.app.ActivityThread.main (ActivityThread.java:6592)
at java.lang.reflect.Method.invoke (Native Method)
W / System.err: at com.android.internal.os.Zygote $ MethodAndArgsCaller.run (Zygote.java:240)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:769)
FileNotFoundException is likely due to the directory teste not existing, perhaps due to permissions.
Using :-
private void backupDatabase () throws IOException {
String inFileName = "/data/data/com.gnd.example/databases/dados.db";
File dbFile = new File (inFileName);
FileInputStream fis = new FileInputStream (dbFile);
String outFileName = Environment.getExternalStorageDirectory () + "/ example / backup / data.db";
//<<<<<<<<<<< CODE ADDED >>>>>>>>>>
File os = new File(outFileName);
if (!os.getParentFile().exists()) {
os.getParentFile().mkdirs();
}
//<<<<<<<<<< END Of ADDED CODE >>>>>>>>>>
OutputStream output = new FileOutputStream(os); //<<<<<<<<<< CHANGED
byte [] buffer = new byte [1024];
int length;
while ((length = fis.read (buffer))> 0) {
output.write (buffer, 0, length);
}
output.flush ();
output.close ();
fis.close ();
}
will create the directories if they do not exist (assuming permissions are correct)
Working Example :-
The following is a working app
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="aso.so56843045backup">
<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/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Note the <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> (for earlier devices)
ExternalStoragePermissions.java
class ExternalStoragePermissions {
public int API_VERSION = Build.VERSION.SDK_INT;
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
//Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public static final String THISCLASS = ExternalStoragePermissions.class.getSimpleName();
private static final String LOGTAG = "SW_ESP";
public ExternalStoragePermissions() {}
// Note call this method
public static void verifyStoragePermissions(Activity activity) {
int permission = ActivityCompat.checkSelfPermission(
activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
}
If permissions not given then the directories cannot be created resulting in FileNotFoundException.
DBHelper.java
public class DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "dados.db";
public static final int DBVERSION = 1;
public DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
this.getWritableDatabase();
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
A Very basic empty database (exception android_metadata table), enough to check backup.
MainActivity.java
public class MainActivity extends AppCompatActivity {
DBHelper mDBHlpr;
Button mBackup;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBackup = this.findViewById(R.id.backup);
mBackup.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mDBHlpr.close();
try {
backupDatabase();
} catch (IOException e) {
e.printStackTrace();
}
}
});
ExternalStoragePermissions.verifyStoragePermissions(this);
mDBHlpr = new DBHelper(this);
}
private void backupDatabase () throws IOException {
FileInputStream fis = new FileInputStream (this.getDatabasePath("dados.db").getPath());
String outFileName = Environment.getExternalStorageDirectory () + "/example/backup/" + String.valueOf(System.currentTimeMillis()) + "data.db";
Log.d("OSFILEPATH",outFileName);
File os = new File(outFileName);
if (!os.getParentFile().exists()) {
os.getParentFile().mkdirs();
}
OutputStream output = new FileOutputStream(os);
byte [] buffer = new byte [1024];
int length;
while ((length = fis.read (buffer))> 0) {
output.write (buffer, 0, length);
}
output.flush ();
output.close ();
fis.close ();
}
}
Notes
When first run after install permission will be requested for later devices (click allow).
Backup has been named with a timestamp so multiple backups can exist.
Database is closed, (this should cope with Android Pie+ wehere default is WAL mode, the close should empty (commit the changes) the -wal and -shm files, thus negating the need to backup the additional files).
Result
With respect to your crash:
You have not created the directory, at least not via your code. Create a File object pointing to the directory that you want, then call mkdirs() on that object.
You might not be holding the WRITE_EXTERNAL_STORAGE permission, including requesting it at runtime. See https://developer.android.com/training/permissions/requesting.
Other problems here include:
You will not have the ability to write to your requested location in Android Q (by default) and Android R (for all apps). I recommend that you write to getExternalFilesDir() (found on Context) or use the Storage Access Framework.
You are doing disk I/O on the main application thread. This will cause your UI to freeze while that I/O is occurring. Users may think that your app is broken. There are many ways to address this, though the Jetpack approach would be to use a ViewModel and LiveData.
You are not arranging to get your file indexed by the MediaStore, so the user will not be able to see it in their desktop file manager. Use MediaScannerConnection.scanFile() to index the file.
"/data/data/com.gnd.example/databases/dados.db" is the wrong path on many Android devices. Never hardcode paths. Use getDatabasePath() on Context to get the path to your database.
This sample Java app shows how a lot of this is done, in the context of a text editor instead of a database backup solution.
In general, I recommend that you put this project aside for a while and read an up-to-date book on Android app development. Most of the problems that I mention here are on topics that would be covered in a decent book on Android.
I'm in the process of trying to create a backup/restore (export/import) process for an SQLite Database App.
Although I appear to have created and populated the file (OK I now know that I have). I cannot see the file in DDMS nor in Windows Explorer. I'd really like to be able to do the latter (see the bottom for a more specific question).
I've successfully written the file and read the file using the following code:
package mjt.sqlitetutorial;
import android.database.Cursor; //+++++ Added
import android.os.Build;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log; //+++++ Added
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class MainActivity extends AppCompatActivity {
public int API_VERSION = Build.VERSION.SDK_INT;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (API_VERSION >= 23) {
ExternalStoragePermissions.verifyStoragePermissions(this);
}
final String EXTSTGTAG = "EXTERNSTG";
File file = getExternalFilesDir("File");
Log.i(EXTSTGTAG,file.toString());
//String extstgdirabs = Environment.getExternalStorageDirectory().getAbsolutePath();
String extstgdirpth = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
Log.i(EXTSTGTAG,"<=\nEXTERN STG PUB DIR=>" + extstgdirpth);
String filepath = extstgdirpth + File.separator + "myfile.txt";
Log.i(EXTSTGTAG,"Full File Path and name is\n\t" + filepath);
File f = new File(filepath);
if(!f.exists() ) {
Log.i(EXTSTGTAG,"File did not exist (path=" + filepath + ")");
try {
f.createNewFile();
}
catch (IOException e) {
Log.e(EXTSTGTAG,"Failure Creating New File MSG=" + e.getMessage());
}
}
if(f.exists()) {
Log.i(EXTSTGTAG,"File Already Exists (" + filepath + ")");
try {
Log.i(EXTSTGTAG,"Creating FileOutputStream instance.");
FileOutputStream fos = new FileOutputStream(f);
Log.i(EXTSTGTAG,"Creating OutputStreamWriter instance from FileOutputStream.");
OutputStreamWriter osw = new OutputStreamWriter(fos);
Log.i(EXTSTGTAG,"Adding Data to OutputStreamWriter.");
osw.append("My Test Data.");
Log.i(EXTSTGTAG,"Closing OutputStreamWriter.");
osw.close();
Log.i(EXTSTGTAG,"Flushing FileOutputStream.");
fos.flush();
Log.i(EXTSTGTAG,"Closing FileOutputStream");
fos.close();
Log.i(EXTSTGTAG,"All Done OK.");
} catch (IOException e) {
Log.e(EXTSTGTAG, "Failure Trying to write to file." + e.getMessage());
e.printStackTrace();
}
} else {
Log.i(EXTSTGTAG,"File doesn't appear to exist when it should????");
}
f.setReadable(true);
f.setWritable(true);
if(f.exists()) {
try {
byte[] bytes;
FileInputStream fis = new FileInputStream(f);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String line = null;
while((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
br.close();
Log.i(EXTSTGTAG,"Read the following data:\n" + sb.toString());
}
catch (IOException e) {
Log.e(EXTSTGTAG,"Failure trying to read file." + e.getMessage());
e.printStackTrace();
}
}
}
}
Output to the log (using EXTERN as the filter) shows (note the first run when installing the App run fails but requests and sets permissions. I don't believe this is an issue/cause) :-
10-18 12:54:40.159 32393-32393/? I/EXTERNSTG: /storage/emulated/0/Android/data/mjt.sqlitetutorial/files/File
10-18 12:54:40.159 32393-32393/? I/EXTERNSTG: <=
EXTERN STG PUB DIR=>/storage/emulated/0/Download
10-18 12:54:40.159 32393-32393/? I/EXTERNSTG: Full File Path and name is
/storage/emulated/0/Download/myfile.txt
10-18 12:54:40.159 32393-32393/? I/EXTERNSTG: File Already Exists (/storage/emulated/0/Download/myfile.txt)
10-18 12:54:40.159 32393-32393/? I/EXTERNSTG: Creating FileOutputStream instance.
10-18 12:54:40.159 32393-32393/? I/EXTERNSTG: Creating OutputStreamWriter instance from FileOutputStream.
10-18 12:54:40.159 32393-32393/? I/EXTERNSTG: Adding Data to OutputStreamWriter.
10-18 12:54:40.159 32393-32393/? I/EXTERNSTG: Closing OutputStreamWriter.
10-18 12:54:40.159 32393-32393/? I/EXTERNSTG: Flushing FileOutputStream.
10-18 12:54:40.159 32393-32393/? I/EXTERNSTG: Closing FileOutputStream
10-18 12:54:40.169 32393-32393/? I/EXTERNSTG: All Done OK.
10-18 12:54:40.169 32393-32393/? I/EXTERNSTG: Read the following data:
My Test Data.
The last line indicating that it has read the file (I assume). There are no other log messages during the provided messages (many before and after though).
the device that I'm testing this on is a non-rooted HTC One M8s with an SDcard. However, I believe that /storage/emulated/0/Download, the directory where the file is being written to is on the internal memory.
With DDMS I don't appear to be able to see this (the actual SD card has a Downloads directory as opposed to a Download directory).
In Windows explorer I can see both Internal Storage and SD card as devices under the HTC_0PKV1 device.
In Windows Explorer the Download directory has (via properties) 0 Directories and Files. Neither read only nor hidden are ticked.
I've tried both with and without the setReadable and setWritable().
I've just tried using the file manager on the phone and can now see the file. So more specifically, the question is; Is there any way excluding rooting the phone and moving the file via file manager on the phone, to access the file via Windows Explorer?
I should also state that the App will run on tablets, so the method should be generic rather than specific to a device.
The file becomes visible in Windows explorer after disconnecting and re-connecting the USB cable. I'm not sure if this how MTP is meant to work or it could perhaps be due to ADB as per this snippet:-
However, if you’ve ever attempted to unlock your device such as to
install a new ROM or root it, then you may have at one time or another
installed the Android Debug Bridge (ADB) driver on your computer. This
driver works great for being able to use the computer to send commands
to your device, but it may mess up your easy-peasy file manipulation.
found at How to Get Your Android Device to Show up in File Explorer (If It Isn’t)
I am new to android development. I downloaded source file from the following link
"http://android-er.blogspot.in/2012/07/implement-custom-linearlayout-for.html", but while trying to run in emulator it shows
java.lang.NullPointerException at com.example.androidhorizontalscrollviewgallery.MainActivity.onCreate(MainActivity.java:27)
My MainActivity.java code is below:
package com.example.androidhorizontalscrollviewgallery;
import java.io.File;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
public class MainActivity extends Activity {
MyHorizontalLayout myHorizontalLayout;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myHorizontalLayout = (MyHorizontalLayout)findViewById(R.id.mygallery);
File targetDir=getDir("Pictures",Context.MODE_PRIVATE);
String targetPath=targetDir+ "/homepage/";
File targetDirector = new File(targetPath);
File[] files = targetDirector.listFiles();
for(File f : files){
myHorizontalLayout.add(f.getAbsolutePath());
}
}
}
Here I have stored my images in my computer in "Libraries\Pictures\homepage" path. I wanted to get the images in gallery but I could not. I don know what causes this exception can anyone please tell the solution
try this..
File targetDir=getDir("Libraries\Pictures\homepage",Context.MODE_PRIVATE);
String targetPath=targetDir.toString();
From the exception, you have a null pointer on line 27, which means that the files object that you are iterating is null. You use the listFiles method to obtain that object, but the listFiles method can return null. You have to check whether you have null or not to avoid your app crashing. See example below. Also, refer to the File class documentation.
if (files == null) {
// handle case where the file object is not a directory
}
else {
for(File f : files){
myHorizontalLayout.add(f.getAbsolutePath());
}
}
I think you can't directly get images from your computer path.
You have to copy that images in your drawable or assests folder of the application.
Or your images should reside in either your device or emulator gallery or any other folders. But it should be in device or emulator in whichever you are testing.
See this line in tutorial you used.
String ExternalStorageDirectoryPath = Environment
.getExternalStorageDirectory()
.getAbsolutePath();
String targetPath = ExternalStorageDirectoryPath + "/test/";
So this is your device's sdcard path - external storage path.