/** * 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; } }