/**
* Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
* This file is part of CSipSimple.
*
* CSipSimple is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* If you own a pjsip commercial license you can also redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as an android library.
*
* CSipSimple is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CSipSimple. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
*/
package com.csipsimple.backup;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.backup.BackupDataInputStream;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupHelper;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import com.csipsimple.utils.Log;
import com.csipsimple.utils.PreferencesProviderWrapper;
import com.csipsimple.utils.PreferencesWrapper;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
@TargetApi(8)
public class SipSharedPreferencesHelper implements BackupHelper {
private static final String THIS_FILE = "SipSharedPreferencesHelper";
private static final String SETTINGS_BACKUP_KEY = "settings";
private final Context mContext;
private final File prefsFiles;
/**
* @param context
* @param prefGroups
*/
public SipSharedPreferencesHelper(Context context) {
mContext = context;
String sharedPrefsName = context.getPackageName() + "_preferences";
prefsFiles = getPreferenceFile(context, sharedPrefsName);
}
/* (non-Javadoc)
* @see android.app.backup.BackupHelper#performBackup(android.os.ParcelFileDescriptor, android.app.backup.BackupDataOutput, android.os.ParcelFileDescriptor)
*/
@Override
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
boolean forceBackup = (oldState == null);
long fileModified = 1;
if(prefsFiles != null) {
fileModified = prefsFiles.lastModified();
}
try {
if (!forceBackup) {
FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
DataInputStream in = new DataInputStream(instream);
long lastModified = in.readLong();
in.close();
if (lastModified < fileModified) {
forceBackup = true;
}
}
} catch (IOException e) {
Log.e(THIS_FILE, "Cannot manage previous local backup state", e);
forceBackup = true;
}
Log.d(THIS_FILE, "Will backup profiles ? " + forceBackup);
if (forceBackup) {
JSONObject settings = SipProfileJson.serializeSipSettings(mContext);
try {
writeData(data, settings.toString());
} catch (IOException e) {
Log.e(THIS_FILE, "Cannot manage remote backup", e);
}
}
try {
FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
DataOutputStream out = new DataOutputStream(outstream);
out.writeLong(fileModified);
out.close();
} catch (IOException e) {
Log.e(THIS_FILE, "Cannot manage final local backup state", e);
}
}
/* (non-Javadoc)
* @see android.app.backup.BackupHelper#restoreEntity(android.app.backup.BackupDataInputStream)
*/
@Override
public void restoreEntity(BackupDataInputStream data) {
if (SETTINGS_BACKUP_KEY.equalsIgnoreCase(data.getKey())) {
try {
String settingsStr = readData(data);
JSONObject settings = new JSONObject(settingsStr);
if (settings != null) {
SipProfileJson.restoreSipSettings(mContext, settings);
}
PreferencesWrapper pw = new PreferencesWrapper(mContext);
pw.setPreferenceBooleanValue(PreferencesProviderWrapper.HAS_ALREADY_SETUP_SERVICE, true);
pw.setPreferenceBooleanValue(PreferencesWrapper.HAS_ALREADY_SETUP, true);
} catch (IOException e) {
Log.e(THIS_FILE, "Cannot restore backup entry", e);
} catch (JSONException e) {
Log.e(THIS_FILE, "Cannot parse backup entry", e);
}
}
}
/* (non-Javadoc)
* @see android.app.backup.BackupHelper#writeNewStateDescription(android.os.ParcelFileDescriptor)
*/
@Override
public void writeNewStateDescription(ParcelFileDescriptor newState) {
long fileModified = 0;
if(prefsFiles != null) {
prefsFiles.lastModified();
}
try {
FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
DataOutputStream out = new DataOutputStream(outstream);
out.writeLong(fileModified);
out.close();
} catch (IOException e) {
Log.e(THIS_FILE, "Cannot manage final local backup state", e);
}
}
@SuppressLint("SdCardPath")
private File getPreferenceFile(Context context, String prefName) {
String finalPath = "shared_prefs/" + prefName + ".xml";
File f = new File(context.getFilesDir(), "../" + finalPath);
if (f.exists()) {
return f;
}
f = new File("/data/data/" + context.getPackageName() + "/" + finalPath);
if (f.exists()) {
return f;
}
f = new File("/dbdata/databases/" + context.getPackageName() + "/" + finalPath);
if (f.exists()) {
return f;
}
return null;
}
private void writeData(BackupDataOutput data, String value) throws IOException {
// Create buffer stream and data output stream for our data
ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
DataOutputStream outWriter = new DataOutputStream(bufStream);
// Write structured data
outWriter.writeUTF(value);
// Send the data to the Backup Manager via the BackupDataOutput
byte[] buffer = bufStream.toByteArray();
int len = buffer.length;
data.writeEntityHeader(SETTINGS_BACKUP_KEY, len);
data.writeEntityData(buffer, len);
}
/**
* Read data from the input stream
*
* @param data the input stream
* @return the data
* @throws IOException I/O error
*/
private String readData(BackupDataInputStream data) throws IOException {
String dataS;
byte[] buf = new byte[data.size()];
data.read(buf, 0, buf.length);
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
DataInputStream dis = new DataInputStream(bais);
dataS = dis.readUTF();
dis.close();
bais.close();
return dataS;
}
}