//
// Copyright (C) 2009 RerWare, LLC
// This code is the property of RerWare, LLC. You are not allowed to change or use this code
// outside of the described usage below.
// v2.2.1
// This is a sample Content Provider for applications that want to provide an interface
// to MyBackup Pro application
// Instructions:
// - Add this file to your project
// - Change the package name to your package name
// - Change the CONTENT_AUTHORITY to match your URI ex: aTrackDog.MyBackupPro
// this must be named YourPackageName.MyBackupPro,
// make sure the CONTENT_AUTHORITY ends with MyBackupPro
// - Add your files that need to be backed up to the filedirpath array below
// - Only change where it says "CHANGE_THIS" , nothing else
// - Add the following tag:
// <provider android:name="YourPackageName.MyBackupPro"
// android:authorities="YourPackageName.MyBackupPro"/>
//
// to your manifest file under the <application> tag. Make sure you change
// android:name and android:authorities to be YourPackageName.MyBackupPro
//
// If you have other content provider(s), this will not affect it, because you can have
// one or more content providers
// Once you finish and compile your application, use MyBackup Pro to test it:
// Backup=>SDCard=>Data you should see your application at the bottom of the list
// backup your files, change something and try to restore them
// Thanks for your cooperation
// if you have any questions please email support@rerware.com
//
package com.google.code.appsorganizer;
//********** Expand the help above *********************
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
public class MyBackupPro extends ContentProvider {
// CHANGE_THIS: This is the URI name for MyBackup, this has to be
// YourPackageName.MyBackupPro
// Make sure the CONTENT_AUTHORITY ends with MyBackupPro
// Make sure you put the <provider> tag in the AndroidManifest.xml file as
// described above
private final String CONTENT_AUTHORITY = "com.google.code.appsorganizer.MyBackupPro";
// CHANGE_THIS: This is a list of files and their paths that you want to
// backup up
// this could be an SQLite DB, an xml preference file in the shared_prefs
// directory or any other data file
// if you want to backup up a whole directory, look at the third example
// The directory could have sub-directories and files underneath
// Make sure the directory name ends with /
// you can have a mix and match of any of these types and as many files as
// you want
private String[] filedirpath = new String[] { "/data/data/com.google.code.appsorganizer/databases/data",
"/data/data/com.google.code.appsorganizer/shared_prefs/appsOrganizer_pref.xml" };
// CHANGE_THIS: This is the minimum supported version code that your program
// supports;
// If you are not sure leave this -1
// This flag is used to prevent crashes with older backup files
// ex: if user backups v1.0.0 of your App, then
// you update the App to v1.0.1 and your DB doesn't change, then
// you can leave the MinSupportedVersion to v1.0.0 or integer equivalent(ex
// 1)
// lets say now you update to v2.0.0 , and you do database changes that are
// not compatible with older files
// now you change MinSupportedVersion to v2.0.0 or integer equivalent(ex 2),
// this will prevent MyBackup from restoring older backups
private int MinSupportedVersion = -1;
// Use this method if you want to do some extra work before the backup is
// done (most of the times this is not needed)
private void backupStarted() {
}
// Use this method if you want to do some extra work after the backup is
// done (most of the times this is not needed)
private void backupDone() {
}
// Use this method if you want to do some extra work before the restore is
// done (most of the times this is not needed)
private void restoreStarted() {
}
// Use this method if you want to do some extra work after the restore is
// done (most of the times this is not needed)
private void restoreDone() {
}
/************************* Don't change anything else in this file ***********************************/
private final String MybackupContentPro = "content://com.rerware.android.MyBackupPro";
private final String MybackupContentTrial = "content://com.rerware.android.MyBackup";
private final int MyBackupQuery = 1000;
private final int MyBackupQueryVersion = 1001;
private final int MyBackupQueryInflate = 1002;
private final int MyBackupBackupStarted = 1003;
private final int MyBackupBackupDone = 1004;
private final int MyBackupRestoreStarted = 1005;
private final int MyBackupRestoreDone = 1006;
private UriMatcher sURIMatcher;
private String tempFile = "";
private List<fileInfo> listUris;
private fileInfo fi;
public MyBackupPro() {
listUris = new ArrayList<fileInfo>();
for (int i = 0; i < filedirpath.length; i++) {
fi = new fileInfo();
fi.filepath = filedirpath[i];
listUris.add(fi);
}
sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
tempFile = "/sdcard/MyBackupTemp.zip";
sURIMatcher.addURI(CONTENT_AUTHORITY, "MyBackupQuery", MyBackupQuery);
sURIMatcher.addURI(CONTENT_AUTHORITY, "MyBackupQueryVersion/#", MyBackupQueryVersion);
sURIMatcher.addURI(CONTENT_AUTHORITY, "MyBackupQueryInflate/#", MyBackupQueryInflate);
sURIMatcher.addURI(CONTENT_AUTHORITY, "MyBackupBackupStarted", MyBackupBackupStarted);
sURIMatcher.addURI(CONTENT_AUTHORITY, "MyBackupBackupDone", MyBackupBackupDone);
sURIMatcher.addURI(CONTENT_AUTHORITY, "MyBackupRestoreStarted", MyBackupRestoreStarted);
sURIMatcher.addURI(CONTENT_AUTHORITY, "MyBackupRestoreDone", MyBackupRestoreDone);
int intUnique = -1;
for (int i = 0; i < listUris.size(); i++) {
++intUnique;
sURIMatcher.addURI(CONTENT_AUTHORITY, "getfile" + i + "/#", intUnique);
++intUnique;
sURIMatcher.addURI(CONTENT_AUTHORITY, "putfile" + i + "/#", intUnique);
}
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
int match = sURIMatcher.match(uri);
switch (match) {
case MyBackupQuery:
Object[] rowObject;
String[] Uris = new String[1];
Uris[0] = "URI_NAME";
MatrixCursor mc = new MatrixCursor(Uris);
for (int i = 0; i < listUris.size(); i++) {
rowObject = new Object[1];
rowObject[0] = "file" + i;
mc.addRow(rowObject);
}
return mc;
case MyBackupQueryVersion:
int BackupVersionCode = Integer.parseInt(uri.getPathSegments().get(1));
int intOk;
// if version is compatible
if (BackupVersionCode >= MinSupportedVersion) {
intOk = 1;
} else {
intOk = 0;
}
Object[] rowObject2;
String[] Uris2 = new String[1];
Uris2[0] = "VERSION_COMPATIBLE";
MatrixCursor mc2 = new MatrixCursor(Uris2);
rowObject2 = new Object[1];
rowObject2[0] = intOk;
mc2.addRow(rowObject2);
return mc2;
case MyBackupQueryInflate:
int inflateFile = Integer.parseInt(uri.getPathSegments().get(1));
fi = listUris.get(inflateFile);
if (fi.filepath.endsWith("/")) {
utilities.deleteEverythingInDir(fi.filepath);
File dir = new File(fi.filepath);
if (!dir.exists()) {
dir.mkdirs();
}
utilities.Unzip(tempFile, fi.filepath);
File temp = new File(tempFile);
temp.delete();
}
return null;
case MyBackupBackupStarted:
try {
backupStarted();
} catch (Exception ex) {
}
return null;
case MyBackupBackupDone:
try {
backupDone();
} catch (Exception ex) {
}
return null;
case MyBackupRestoreStarted:
try {
restoreStarted();
} catch (Exception ex) {
}
return null;
case MyBackupRestoreDone:
try {
restoreDone();
} catch (Exception ex) {
}
return null;
}
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
ParcelFileDescriptor parcel = null;
int match = sURIMatcher.match(uri);
int authCode = Integer.parseInt(uri.getPathSegments().get(1));
if (auth(MybackupContentPro, authCode) == 1 || auth(MybackupContentTrial, authCode) == 1) {
// GET FILE
if (match % 2 == 0) {
String getfile = "";
fi = listUris.get((int) (Math.floor(match / 2)));
if (fi.filepath.endsWith("/")) {
getfile = tempFile;
} else {
getfile = fi.filepath;
}
if (fi.filepath.endsWith("/")) {
try {
// zip the directory into the one file before the backup
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tempFile));
utilities.zipDir(fi.filepath, fi.filepath, zos);
// close the stream
zos.close();
} catch (Exception ex) {
System.out.print(ex.getMessage());
}
}
File getFile = new File(getfile);
parcel = ParcelFileDescriptor.open(getFile, ParcelFileDescriptor.MODE_READ_WRITE);
if (fi.filepath.endsWith("/")) {
File temp = new File(tempFile);
temp.delete();
}
}
// PUT FILE
else {
String putfile = "";
fi = listUris.get((int) (Math.floor(match / 2)));
if (fi.filepath.endsWith("/")) {
putfile = tempFile;
} else {
putfile = fi.filepath;
}
File putFile = new File(putfile);
putFile.delete();
File parentputFile = new File(putFile.getParent());
if (!parentputFile.exists()) {
parentputFile.mkdirs();
}
if (!putFile.exists()) {
try {
putFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
parcel = ParcelFileDescriptor.open(putFile, ParcelFileDescriptor.MODE_READ_WRITE);
}
}
return parcel;
}
private int auth(String content, int authcode) {
int intRet = 0;
Cursor uriCur;
try {
uriCur = this.getContext().getContentResolver().query(Uri.parse(content + "/MyBackupAuth/" + authcode), null, null, null, null);
if (uriCur != null) {
if (uriCur.moveToFirst()) {
do {
intRet = uriCur.getInt(0);
} while (uriCur.moveToNext());
}
uriCur.close();
}
} catch (Exception ex) {
System.out.print(ex.getMessage());
}
return intRet;
}
public class fileInfo {
public String filepath;
}
private static class utilities {
// here is the code for the method
private static void zipDir(String dir2zip, String originalDir, ZipOutputStream zos) {
try {
// create a new File object based on the directory we have to
// zip File
File zipDir = new File(dir2zip);
// get a listing of the directory content
String[] dirList = zipDir.list();
byte[] readBuffer = new byte[2156];
int bytesIn = 0;
// loop through dirList, and zip the files
for (int i = 0; i < dirList.length; i++) {
File f = new File(zipDir, dirList[i]);
if (f.isDirectory()) {
// if the File object is a directory, call this
// function again to add its content recursively
String filePath = f.getPath();
zipDir(filePath, originalDir, zos);
// loop again
continue;
}
// if we reached here, the File object f was not a directory
// create a FileInputStream on top of f
FileInputStream fis = new FileInputStream(f);
// create a new zip entry
ZipEntry anEntry = new ZipEntry(f.getPath().substring(originalDir.length()));
// place the zip entry in the ZipOutputStream object
zos.putNextEntry(anEntry);
// now write the content of the file to the ZipOutputStream
while ((bytesIn = fis.read(readBuffer)) != -1) {
zos.write(readBuffer, 0, bytesIn);
}
// close the Stream
fis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void Unzip(String zipFile, String targetDir) {
int BUFFER = 2048;
String strEntry;
try {
BufferedOutputStream dest = null;
FileInputStream fis = new FileInputStream(zipFile);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
try {
System.out.println("Extracting: " + entry);
int count;
byte data[] = new byte[BUFFER];
// write the files to the disk
strEntry = entry.getName();
File entryFile = new File(targetDir + strEntry);
File entryDir = new File(entryFile.getParent());
if (!entryDir.exists()) {
entryDir.mkdirs();
}
FileOutputStream fos = new FileOutputStream(entryFile);
dest = new BufferedOutputStream(fos, BUFFER);
while ((count = zis.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
}
dest.flush();
dest.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
zis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static boolean deleteEverythingInDir(String strdir) {
File dir = null;
try {
dir = new File(strdir);
if (dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteEverythingInDir(dir.getPath() + "/" + children[i]);
if (!success) {
return false;
}
}
}
} catch (Exception ex) {
}
// The directory is now empty so delete it
return dir.delete();
}
}
}