I'm fairly new to apk development. So far, after a book purchase and with a lot of Googling I've managed to make an application that controls some features of my custom ROM. I'm currently trying to implement 2 backup features. I want to backup /data/system/batterystats.bin to /sdcard and also i want to backup launcher.db of my touchwiz launcher to /sdcard.
For the first part i haven't actually found anything. I've searched a lot about how to restore a file, not much has come up. It's mostly about SQL .db files. I've also looked for the possibility to run a shell script via the apk just to perform this backup. With a shell script it's easy work, but doing this via .java, i honestly have no clue.
Also, i've tried quite a lot of code to get my sqlite database file to backup, but i was quite unsuccessful. Here's my code for you to look at:
public class Backup extends Activity {
public void exportDB(){
try {
File sd = Environment.getExternalStorageDirectory();
if (sd.canWrite()) {
String currentDBPath = "data/data/com.sec.android.app.twlauncher/databases/launcher.db";
String backupDBPath = sd + "/launcher.db";
File currentDB = new File(currentDBPath);
File backupDB = new File(backupDBPath);
if (currentDB.exists()) {
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
I have added permissions for external storage write, of course in the androidmanifest, but nothing happens. No FC, it just sits there doing nothing. And when I check my sdcard, there's nothing there.
Any help would be greatly appreciated. Thanks
Download RootTools (the jar file).
You can then run linux commands like this:
RootTools.sendShell(command);
For example to backup, you could do:
RootTools.sendShell("cp -f /data/data/com.sec.android.app.twlauncher/databases/launcher.db /sdcard/directory/");
And to restore the file:
RootTools.sendShell("cp -f /sdcard/directory/launcher.db /data/data/com.sec.android.app.twlauncher/databases/");
cp is the copy command, and -f is what allows it to overwite the file if it already exists.
RootTools are great, and for the commands, just google how to do linux commands and then place them into the sendShell
I have no idea how to do it with java. I personally think that using the linux commands are 10 times easier, though.
And to note, it is actually good to get sdcard location like this:
Environment.getExternalStorageDirectory();
and then append the rest of the storage location info to the end of that.
Related
I'm writing logs using slf4android (https://github.com/bright/slf4android) but it is not obvious how to read them (ideally I would just like to download them to my computer). The internal storage of the app is not accessible to other apps. Can I configure the slf4android to log to a shared directory? I've tried this but I get NOENT:
FileLogHandlerConfiguration fileHandler = LoggerConfiguration.fileLogHandler(this);
File lol = this.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
fileHandler.setFullFilePathPattern(fileHandler.toString() + "/my_log.%g.%u.log");
LoggerConfiguration.configuration().addHandlerToRootLogger(fileHandler);
Once you configured logging to a file by:
FileLogHandlerConfiguration fileHandler = LoggerConfiguration.fileLogHandler(this);
fileHandler.setFullFilePathPattern("/sdcard/your.package/my_log.log");
LoggerConfiguration.configuration().addHandlerToRootLogger(fileHandler);
There are two (both simple) ways to get a log file:
Using NotifyDeveloperHandler (my favourite)
slf4android has a very nice feature (for some reason undocumented) which allows sending an email to a given address with logs and screenshot included in an attachment.
NotifyDeveloperHandler handler = LoggerConfiguration.configuration().notifyDeveloperHandler(this, "example#gmail.com");
handler.notifyWhenDeviceIsShaken();
LoggerConfiguration.configuration().addHandlerToRootLogger(handler);
it's really handy to use (literally) because you can trigger a send action by shaking your device.
Using adb
Run adb pull /sdcard/your.package/my_log.log ~/my_log.log in terminal to copy log file from the device to home directory.
The official docs says you can do this:
FileLogHandlerConfiguration fileHandler = LoggerConfiguration.fileLogHandler(this);
fileHandler.setFullFilePathPattern(SOMEPATH);
LoggerConfiguration.configuration().addHandlerToRootLogger(fileHandler);
and the log file would be located into SOMEPATH. I would recommend you use a regular environment directory instead of an arbitrary string, like
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getPath()+File.pathSeparator+"appLogs"
Now, if you want to copy some existing logs to an outher destination, you can just copy the files.
if(BuildConfig.DEBUG) {
File logs = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getPath(), "logs");
FileLogHandlerConfiguration fileHandler = LoggerConfiguration.fileLogHandler(this);
LoggerConfiguration.configuration().addHandlerToRootLogger(fileHandler);
File currentLogs = fileHandler.getCurrentFileName();
if (currentLogs.exists()) {
FileChannel src = new FileInputStream(currentLogs).getChannel();
FileChannel dst = new FileOutputStream(logs).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
}
}
Finally, keep in mind nothing will work if you don't get the proper storage permissions!
Hope it helps. Happy coding!
In code example your provided you don't actually use "File lol" you've defined.
So it probably fails because you try to create another log on top of the first one (e.g. in "/sdcard/your.package/my_log.%g.%u.log/my_log.%g.%u.log");
Try:
File lol = this.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
fileHandler.setFullFilePathPattern(lol.getAbsolutePath() + "/my_log.%g.%u.log");
But you can also just add a menu option clicking which would find the logs, may be zip them (together with db or whatever) and send by email, upload to server or just copy to another folder.
I'm sorry to take your time, so I'll try to make it short. Before all, I apologize if my English is wrong or if I'm making dumb mistake, English is not my mother tong. I'm sorry if the answer is silly I'm still not experimented with the making of android apps. I'm making a android application and I'm trying to store some files on a public folder on the external storage. I'm having an issue and I have no idea what might be happening.
The issue is so :
I have a file in the 'download' directory. Then I'm moving the file to my public folder, then I rename it (all this through code). Everything seems to happens fine, the file is correctly moved, is readable and writeable. The file is then visible through app like 'File commander'. Although, when I connect my phone with my computer the file is nowhere to be seen with nautilus (ubuntu folder app), even with the terminal (sudo ls -a doesn't change a thing).
String path = (Environment.getExternalStoragePublicDirectory("myAppFolder").getAbsolutePath() + "/inside_folder/" + fileToMove.getName())
File folder = new File(path);
folder.mkdir();
File thatFile = new File (folder.getAbsolutePath() + "/downloading");
if (thatFile.exist()) thatFile.delete();
try {
FileInputStream instream = new FileInputStream(fileToMove);
FileOutputStream outstream = new FileOutputStream(thatFile);
FileChannel inChannel = instream.getChannel();
FileChannel outChannel = outstream.getChannel();
inChannel.transferTo(0, inChannel.size(), outChannel);
instream.close();
outstream.close();
outChannel.close();
inChannel.close();
} catch (IOException e1) {
e1.printStackTrace();
}
thatFile.renameTo(new File(folder.getAbsolutePath + "/coucou"));
For some reason, if the file is rename with 'file commander', the file will now be visible through nautilus. Also, if no other file than the one invisible named 'coucou' then, I will have no way to explore to myAppFolder/inside_folder/imafile/coucou , myAppFolder (and so inside_folder) being unreachable. How can I change that ? How can I make it visible without File Commander. Also, I wonder how can a file be invisible ... anyway thank you for your time and help :-).
edit: Rebooting the device clear the issue. Yet, if new file are created, the won't appear until new reboot (or for now it seems so). I don't want the user to do so each time. Does anyone know how to fix that ? Thank you :).
Having a problem writing out to a file, this code is taken directly from the android developer page and then tweaked a bit by me. Is there something i am missing? Quite new to Android development so sorry if it's something blatantly obvious.
send.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FileOutputStream outputStream;
String data = "hello";
File fileDir = new File("data.txt");
if (!fileDir.exists())
fileDir.mkdirs();
try {
outputStream = openFileOutput("data.txt",Context.MODE_PRIVATE);
outputStream.write(data.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
Basically, your problem is that you are trying to do it twice, once in a way that won't work, and once in a way that will, but hides the result.
File fileDir = new File("data.txt");
if (!fileDir.exists())
fileDir.mkdirs();
This would create a Java File object connected to a hypothetical file called "data.txt" located in the current working directory, which for an Android app is the root directory of the device - a place you most definitely are not allowed to write to. However, this may not obviously cause any errors, as the root directory exists so mkdirs() will do nothing, and you only create a File object, you don't actually try to create a file on "disk". Effectively this code does nothing for you - get rid of it.
Next you try something basically workable:
try {
outputStream = openFileOutput("data.txt",Context.MODE_PRIVATE);
outputStream.write(data.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
openFileOutput() is a method of a Context (Activity or Service) which creates an output stream to write to an actual file located in the private internal storage area of your app. This is all fine and good, and normally a good choice for storing typical data. However, it is not a place that you will be able to examine when running a release app on a secured device, as neither ADB based tools nor Mass Storage or MTP access over USB have rights to it. So it's entirely possible that this code worked, but you had no way to discover that fact. If you are on an emulator, you can access this location with ADB or the DDMS browser, and if your apk is a debug one, you can use the run-as command line tool in the shell.
If you want to share the data, you might consider putting it on the External Storage instead.
I have written code to back up my sqlite db to a file on my Android phone (Sony Ericsson X-8 w/ version 2.1.1 of Android).
I have put the code below for reference, but before reading it, I stress that it works fine on the X-8. [Any suggestions for improvement are still most welcome!] It is when I run it on a Sony Ericsson Xperia Arc w/ version 4.0.4 of Android that I have problems.
The file is not written to the SD card. It's very hard to debug, because as you may know, hooking up the phone to the computer via USB card can stop the file from being written anyhow (see for example: Android FileWriter not working on Sony Ericsson Arc but works on another phone).
In any case, going through the code in the debugger results in no problems and one is led to believe the file is written. In my manifest, I do have:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I am stumped as to what is going on. Did something change between versions 2 and 4 of Android in regards to the file system? Is it phone specific?
Any ideas would be much appreciated.
-Dave
String packageName = "com.xxx.receiver";
String dbName = "Receiver";
//File sd = Environment.getExternalStorageDirectory();
File sd = new File(Environment.getExternalStorageDirectory(), "xxx"); // "xxx" is never created on Arc!
if (!sd.exists()) {
sd.mkdirs();
}
File data = Environment.getDataDirectory();
if (sd.canWrite())
{
String currentDBPath = "//data//"+ packageName +"//databases//"+ dbName;
String backupDBPath = dbName;
File currentDB = new File(data, currentDBPath);
File backupDB = new File(sd, backupDBPath);
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
//Toast.makeText(SettingsAdapter.this.getContext(), backupDB.toString(), Toast.LENGTH_LONG).show();
}
In Android starting with ICS, USB connections offer the devices as a media device by default, not a USB Mass Storage device. The advantage of that is that external storage doesn't "disappear" when you plug in the USB cable, which of course makes debugging much easier. The disadvantage is that you'll need to let Android know explicitly when you've added a file (or files).
However, it's not terribly hard:
File sd = new File(Environment.getExternalStorageDirectory(), "xxx" );
...
// create your file in xxx
...
sendBroadcast(
new Intent( Intent.ACTION_MEDIA_MOUNTED,
Uri.fromFile( sd ) )
)
);
As a side-note, rather than hard coding the database path, you can use this:
context.getDatabasePath( dbName );
I am using Sql database in my appliaction,in that i want to take backup of the database.I have the following doubts:
1.I am running the application in emulator,for checking whether i have to plug some external storage to check ,if not in my system how can i check.
2.I am using the following code in my application,in that sdcard.write option is showing false,what wrong in this.
Follwing is my code:
try {
File sd = Environment.getExternalStorageDirectory();
File data = Environment.getDataDirectory();
java.lang.System.out.println("data="+sd.getAbsolutePath());
java.lang.System.out.println("data="+sd.canWrite());--->Showing as false
if (sd.canWrite()) {
String currentDBPath = "\\data\\com.budget\\databases\\budget";
String backupDBPath = "budget";
File currentDB = new File(data, currentDBPath);
File backupDB = new File(sd, backupDBPath);
java.lang.System.out.println("backup="+backupDB.getAbsolutePath());
if (currentDB.exists()) {
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
}
}
} catch (Exception e) {
}
Data Backup Documentation in android.
If your Android application has a database and you want your users to be able to backup the database and restore it as they see fit, you’ll need to mess about with database files.
Below is a class called DbExportImport. Once you’ve set it up with the correct values, all you need to do is call exportDb(), importDb() or restoreDb() from your application to perform the necessary operations.
This is also useful as a temporary measure when changing your package name or key for application signing, as your application will be newly installed and you will lose your database.(More).
However, you might want to extend BackupAgent directly if you need to: * Back up data in a database. If you have an SQLite database that you want to restore when the user re-installs your application, you need to build a custom BackupAgent that reads the appropriate data during a backup operation, then create your table and insert the data during a restore operation(More).
Now your can also backup from sdcard Backup and restore SQLite database to sdcard
Here is the another solution just like your problem.
If you are using Eclipse, go to Window - Android Virtual Device Manager, select the AVD you are using and click Edit, in the Hardware options select New and then select the SD Card Support. Then just define the storage size and click Edit AVD, to save the changes.
To check if sd is mounted use:
if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
//code for sd mounted
}else{
//code for sd not mounted
}
Check if you have setted the permission in the manifest.
<manifest ...
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
The file extension (.db) is missing in the excerpt above:
currentDBPath = "\\\data\\\com.budget\\\databases\\\budget.db";