/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.content.ContentTypeIds;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.maps.mytracks.R;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
/**
* Helper for backing up and restoring shared preferences.
*
* @author Rodrigo Damazio
*/
public class PreferenceBackupHelper {
private static final int BUFFER_SIZE = 2048;
private final HashSet<String> doNotBackup;
public PreferenceBackupHelper(Context context) {
doNotBackup = new HashSet<String>();
doNotBackup.add(context.getString(R.string.activity_recognition_type_key));
doNotBackup.add(context.getString(R.string.ant_bike_cadence_sensor_id_key));
doNotBackup.add(context.getString(R.string.ant_combined_bike_sensor_id_key));
doNotBackup.add(context.getString(R.string.ant_heart_rate_monitor_id_key));
doNotBackup.add(context.getString(R.string.ant_speed_distance_monitor_id_key));
doNotBackup.add(context.getString(R.string.auto_resume_track_current_retry_key));
doNotBackup.add(context.getString(R.string.bluetooth_sensor_key));
doNotBackup.add(context.getString(R.string.drive_deleted_list_key));
doNotBackup.add(context.getString(R.string.drive_edited_list_key));
doNotBackup.add(context.getString(R.string.drive_largest_change_id_key));
doNotBackup.add(context.getString(R.string.drive_sync_key));
doNotBackup.add(context.getString(R.string.google_account_key));
doNotBackup.add(context.getString(R.string.recording_track_id_key));
doNotBackup.add(context.getString(R.string.recording_track_paused_key));
doNotBackup.add(context.getString(R.string.share_track_account_key));
doNotBackup.add(context.getString(R.string.weight_key));
}
/**
* Exports all shared preferences from the given object as a byte array.
*
* @param preferences the preferences to export
* @return the corresponding byte array
* @throws IOException if there are any errors while writing to the byte array
*/
public byte[] exportPreferences(SharedPreferences preferences) throws IOException {
ByteArrayOutputStream bufStream = new ByteArrayOutputStream(BUFFER_SIZE);
DataOutputStream outWriter = new DataOutputStream(bufStream);
exportPreferences(preferences, outWriter);
return bufStream.toByteArray();
}
/**
* Exports all shared preferences from the given object into the given output
* stream.
*
* @param preferences the preferences to export
* @param outWriter the stream to write them to
* @throws IOException if there are any errors while writing the output
*/
public void exportPreferences(SharedPreferences preferences, DataOutputStream outWriter)
throws IOException {
Map<String, ?> values = preferences.getAll();
for (String name : doNotBackup) {
values.remove(name);
}
outWriter.writeInt(values.size());
for (Map.Entry<String, ?> entry : values.entrySet()) {
writePreference(entry.getKey(), entry.getValue(), outWriter);
}
outWriter.flush();
}
/**
* Imports all preferences from the given byte array.
*
* @param data the byte array to read preferences from
* @param preferences the shared preferences to edit
* @throws IOException if there are any errors while reading
*/
public void importPreferences(byte[] data, SharedPreferences preferences) throws IOException {
ByteArrayInputStream bufStream = new ByteArrayInputStream(data);
DataInputStream reader = new DataInputStream(bufStream);
importPreferences(reader, preferences);
}
/**
* Imports all preferences from the given stream.
*
* @param reader the stream to read from
* @param preferences the shared preferences to edit
* @throws IOException if there are any errors while reading
*/
@SuppressLint("CommitPrefEdits")
public void importPreferences(DataInputStream reader, SharedPreferences preferences)
throws IOException {
Editor editor = preferences.edit();
editor.clear();
int numPreferences = reader.readInt();
for (int i = 0; i < numPreferences; i++) {
String name = reader.readUTF();
byte typeId = reader.readByte();
readAndSetPreference(name, typeId, reader, editor);
}
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
}
/**
* Reads a single preference and sets it into the given editor.
*
* @param name the name of the preference to read
* @param typeId the type ID of the preference to read
* @param reader the reader to read from
* @param editor the editor to set the preference in
* @throws IOException if there are errors while reading
*/
private void readAndSetPreference(String name, byte typeId, DataInputStream reader, Editor editor)
throws IOException {
boolean save = true;
if (doNotBackup.contains(name)) {
save = false;
}
switch (typeId) {
case ContentTypeIds.BOOLEAN_TYPE_ID:
boolean booleanValue = reader.readBoolean();
if (save) {
editor.putBoolean(name, booleanValue);
}
return;
case ContentTypeIds.LONG_TYPE_ID:
long longValue = reader.readLong();
if (save) {
editor.putLong(name, longValue);
}
return;
case ContentTypeIds.FLOAT_TYPE_ID:
float floatValue = reader.readFloat();
if (save) {
editor.putFloat(name, floatValue);
}
return;
case ContentTypeIds.INT_TYPE_ID:
int intValue = reader.readInt();
if (save) {
editor.putInt(name, intValue);
}
return;
case ContentTypeIds.STRING_TYPE_ID:
String utfValue = reader.readUTF();
if (save) {
editor.putString(name, utfValue);
}
return;
}
}
/**
* Writes a single preference.
*
* @param name the name of the preference to write
* @param value the correctly-typed value of the preference
* @param writer the writer to write to
* @throws IOException if there are errors while writing
*/
private void writePreference(String name, Object value, DataOutputStream writer)
throws IOException {
writer.writeUTF(name);
if (value instanceof Boolean) {
writer.writeByte(ContentTypeIds.BOOLEAN_TYPE_ID);
writer.writeBoolean((Boolean) value);
} else if (value instanceof Integer) {
writer.writeByte(ContentTypeIds.INT_TYPE_ID);
writer.writeInt((Integer) value);
} else if (value instanceof Long) {
writer.writeByte(ContentTypeIds.LONG_TYPE_ID);
writer.writeLong((Long) value);
} else if (value instanceof Float) {
writer.writeByte(ContentTypeIds.FLOAT_TYPE_ID);
writer.writeFloat((Float) value);
} else if (value instanceof String) {
writer.writeByte(ContentTypeIds.STRING_TYPE_ID);
writer.writeUTF((String) value);
} else {
throw new IllegalArgumentException("Type " + value.getClass().getName() + " not supported");
}
}
}