fixes to data export/import

Main problem, aside from the explanations being stubbed out, is that
zip file overwriting doesn't work: once an entry is in the file, it'll
be there when the file's overwritten even if that entry is
excluded. This happens even if I create the file in memory and then
overwrite using the bytes.
This commit is contained in:
Eric House 2022-06-11 09:29:41 -07:00
parent d73481ba9b
commit d3d702ad9e
11 changed files with 519 additions and 141 deletions

View file

@ -386,6 +386,7 @@ dependencies {
// implementation("com.hivemq:hivemq-mqtt-client:1.3.0")
implementation 'com.google.zxing:core:3.3.+'
implementation 'com.jakewharton:process-phoenix:2.1.2'
}
task mkImages(type: Exec) {

View file

@ -0,0 +1,106 @@
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
/*
* Copyright 2022 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program 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 2 of the
* License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.eehouse.android.xw4;
import android.view.ViewGroup;
import android.content.Context;
import android.net.Uri;
// import android.text.TextUtils;
import android.util.AttributeSet;
// import android.view.View;
// import android.widget.AdapterView.OnItemSelectedListener;
// import android.widget.AdapterView;
// import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
// import android.widget.RadioButton;
// import android.widget.RadioGroup;
import android.widget.CheckBox;
// import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
// import org.eehouse.android.xw4.jni.XwJNI;
import org.eehouse.android.xw4.loc.LocUtils;
import org.eehouse.android.xw4.ZipUtils.SaveWhat;
public class BackupConfigView extends LinearLayout
{
private static final String TAG = BackupConfigView.class.getSimpleName();
private boolean mIsStore;
private Uri mLoadFile;
private Map<SaveWhat, CheckBox> mCheckBoxes = new HashMap<>();
private List<SaveWhat> mShowWhats;
public BackupConfigView( Context cx, AttributeSet as )
{
super( cx, as );
}
void init( Uri uri )
{
mLoadFile = uri;
mIsStore = null == uri;
if ( null != uri ) {
mShowWhats = ZipUtils.getHasWhats( getContext(), uri );
}
}
@Override
protected void onFinishInflate()
{
Context context = getContext();
LinearLayout list = (LinearLayout)findViewById( R.id.whats_list );
for ( SaveWhat what : SaveWhat.values() ) {
if ( null == mShowWhats || mShowWhats.contains(what) ) {
CheckBox box = (CheckBox)
LocUtils.inflate( context, R.layout.invite_checkbox );
box.setText( what.toString() );
mCheckBoxes.put( what, box );
list.addView( box );
}
}
}
String getPosButtonTxt()
{
return mIsStore ? "Save" : "Load";
}
public List<SaveWhat> getSaveWhat()
{
List<SaveWhat> result = new ArrayList<>();
for ( SaveWhat what : mCheckBoxes.keySet() ) {
CheckBox box = mCheckBoxes.get( what );
if ( box.isChecked() ) {
result.add( what );
Log.d( TAG, "getSaveWhat(): added %s", what );
} else {
Log.d( TAG, "getSaveWhat(): DID NOT add %s", what );
}
}
Log.d( TAG, "getSaveWhat() => %s", result );
return result;
}
}

View file

@ -0,0 +1,5 @@
public class BackupView {
}

View file

@ -1853,41 +1853,6 @@ public class DBUtils {
}
}
public static boolean loadDB( Context context, Uri uri )
{
boolean success = false;
try ( InputStream is = context
.getContentResolver().openInputStream(uri) ) {
String name = DBHelper.getDBName();
File gamesDB = context.getDatabasePath( name );
FileOutputStream fos = new FileOutputStream( gamesDB );
success = copyStream( fos, is );
invalGroupsCache();
} catch ( Exception ex ) {
Log.ex( TAG, ex );
}
if ( success ) {
PrefsDelegate.loadPrefs( context );
}
return success;
}
public static boolean saveDB( Context context, Uri uri )
{
PrefsDelegate.savePrefs( context );
boolean success = false;
try ( OutputStream os = context.getContentResolver().openOutputStream( uri ) ) {
String name = DBHelper.getDBName();
File gamesDB = context.getDatabasePath( name );
FileInputStream fis = new FileInputStream( gamesDB );
success = copyStream( os, fis );
} catch ( Exception ex ) {
Log.ex( TAG, ex );
}
return success;
}
public static boolean copyStream( OutputStream fos, InputStream fis )
{
boolean success = false;
@ -1904,13 +1869,6 @@ public class DBUtils {
Log.d( TAG, "copyFileStream(): copied %s to %s", fis, fos );
} catch( java.io.IOException ioe ) {
Log.ex( TAG, ioe );
} finally {
try {
fos.close();
fis.close();
} catch( java.io.IOException ioe ) {
Log.ex( TAG, ioe );
}
}
return success;
}

View file

@ -24,14 +24,15 @@ import android.content.Context;
import android.content.res.AssetManager;
import android.os.Environment;
import org.eehouse.android.xw4.jni.JNIUtilsImpl;
import org.eehouse.android.xw4.jni.XwJNI;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
@ -233,9 +234,9 @@ public class DictUtils {
FileInputStream fis = context.openFileInput( name );
fis.close();
loc = DictLoc.INTERNAL;
} catch ( java.io.FileNotFoundException fnf ) {
} catch ( FileNotFoundException fnf ) {
// Log.ex( fnf );
} catch ( java.io.IOException ioe ) {
} catch ( IOException ioe ) {
Log.ex( TAG, ioe );
}
}
@ -304,8 +305,10 @@ public class DictUtils {
: new FileOutputStream( getDictFile( context, name, to ) );
success = DBUtils.copyStream( fos, fis );
} catch ( java.io.FileNotFoundException fnfe ) {
Log.ex( TAG, fnfe );
fos.close();
fis.close();
} catch ( IOException ex ) {
Log.ex( TAG, ex );
}
return success;
} // copyDict
@ -368,7 +371,7 @@ public class DictUtils {
Assert.assertTrue( -1 == dict.read() );
bytes = bas.toByteArray();
} catch ( java.io.IOException ee ){
} catch ( IOException ee ){
}
}
@ -403,9 +406,9 @@ public class DictUtils {
fis.read( bytes, 0, len );
fis.close();
Log.i( TAG, "Successfully loaded %s", name );
} catch ( java.io.FileNotFoundException fnf ) {
} catch ( FileNotFoundException fnf ) {
// Log.ex( fnf );
} catch ( java.io.IOException ioe ) {
} catch ( IOException ioe ) {
Log.ex( TAG, ioe );
}
}
@ -518,9 +521,9 @@ public class DictUtils {
if ( success ) {
invalDictList();
}
} catch ( java.io.FileNotFoundException fnf ) {
} catch ( FileNotFoundException fnf ) {
Log.ex( TAG, fnf );
} catch ( java.io.IOException ioe ) {
} catch ( IOException ioe ) {
Log.ex( TAG, ioe );
tmpFile.delete();
}
@ -607,7 +610,7 @@ public class DictUtils {
try {
AssetManager am = context.getAssets();
return am.list("");
} catch( java.io.IOException ioe ) {
} catch( IOException ioe ) {
Log.ex( TAG, ioe );
return new String[0];
}

View file

@ -21,55 +21,56 @@
package org.eehouse.android.xw4;
public enum DlgID {
NONE
, CHANGE_GROUP
, CONFIRM_CHANGE
, CONFIRM_CHANGE_PLAY
, CONFIRM_THEN
, DIALOG_NOTAGAIN
, DIALOG_OKONLY
, DIALOG_ENABLESMS
, DICT_OR_DECLINE
, DLG_CONNSTAT
, DLG_DELETED
, DLG_INVITE(true)
, DLG_OKONLY
, ENABLE_NFC
, FORCE_REMOTE
, GET_NAME
, GET_NUMBER
, INVITE_CHOICES_THEN
, MOVE_DICT
, NAME_GAME
, NEW_GROUP
, PLAYER_EDIT
, ENABLE_SMS
, QUERY_ENDGAME
, RENAME_GAME
, RENAME_GROUP
, REVERT_ALL
, REVERT_COLORS
, SET_DEFAULT
, SHOW_SUBST
, WARN_NODICT_GENERIC // the general trying-to-open case
, WARN_NODICT_INVITED // when responding to invitation
, WARN_NODICT_SUBST // when a substitution will be possible/suggested
, DLG_BADWORDS
, NOTIFY_BADWORDS
, QUERY_MOVE
, QUERY_TRADE
, ASK_PASSWORD
, DLG_RETRY
, DLG_SCORES(true)
, DLG_USEDICT
, DLG_GETDICT
, GAMES_LIST_NEWGAME
, CHANGE_CONN
, GAMES_LIST_NAME_REMATCH
, ASK_DUP_PAUSE
, CHOOSE_TILES
, SHOW_TILES
, RENAME_PLAYER
NONE,
CHANGE_GROUP,
CONFIRM_CHANGE,
CONFIRM_CHANGE_PLAY,
CONFIRM_THEN,
DIALOG_NOTAGAIN,
DIALOG_OKONLY,
DIALOG_ENABLESMS,
DICT_OR_DECLINE,
DLG_CONNSTAT,
DLG_DELETED,
DLG_INVITE(true),
DLG_OKONLY,
ENABLE_NFC,
FORCE_REMOTE,
GET_NAME,
GET_NUMBER,
INVITE_CHOICES_THEN,
MOVE_DICT,
NAME_GAME,
NEW_GROUP,
PLAYER_EDIT,
ENABLE_SMS,
QUERY_ENDGAME,
RENAME_GAME,
RENAME_GROUP,
REVERT_ALL,
REVERT_COLORS,
SET_DEFAULT,
SHOW_SUBST,
WARN_NODICT_GENERIC, // the general trying-to-open case
WARN_NODICT_INVITED, // when responding to invitation
WARN_NODICT_SUBST, // when a substitution will be possible/suggested
DLG_BADWORDS,
NOTIFY_BADWORDS,
QUERY_MOVE,
QUERY_TRADE,
ASK_PASSWORD,
DLG_RETRY,
DLG_SCORES(true),
DLG_USEDICT,
DLG_GETDICT,
GAMES_LIST_NEWGAME,
CHANGE_CONN,
GAMES_LIST_NAME_REMATCH,
ASK_DUP_PAUSE,
CHOOSE_TILES,
SHOW_TILES,
RENAME_PLAYER,
BACKUP_LOADSTORE,
;
private boolean m_addToStack;

View file

@ -47,15 +47,17 @@ import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.jakewharton.processphoenix.ProcessPhoenix;
import org.eehouse.android.xw4.DBUtils.GameChangeType;
import org.eehouse.android.xw4.DBUtils.GameGroupInfo;
import static org.eehouse.android.xw4.DBUtils.ROWID_NOTFOUND;
import org.eehouse.android.xw4.DBUtils.SentInvitesInfo;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.DlgDelegate.ActionPair;
import org.eehouse.android.xw4.DwnldDelegate.DownloadFinishedListener;
import org.eehouse.android.xw4.DwnldDelegate.OnGotLcDictListener;
import org.eehouse.android.xw4.Perms23.Perm;
import org.eehouse.android.xw4.ZipUtils.SaveWhat;
import org.eehouse.android.xw4.jni.CommonPrefs;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet;
@ -65,6 +67,7 @@ import org.eehouse.android.xw4.jni.GameSummary;
import org.eehouse.android.xw4.jni.LastMoveInfo;
import org.eehouse.android.xw4.jni.XwJNI;
import org.eehouse.android.xw4.loc.LocUtils;
import static org.eehouse.android.xw4.DBUtils.ROWID_NOTFOUND;
import java.io.File;
import java.io.Serializable;
@ -739,6 +742,11 @@ public class GamesListDelegate extends ListDelegateBase
}
break;
case BACKUP_LOADSTORE:
Uri uri = 0 == params.length ? null : Uri.parse((String)params[0]);
dialog = mkLoadStoreDlg( uri );
break;
case NEW_GROUP: {
final Renamer namer = buildRenamer( "", R.string.newgroup_label );
lstnr = new OnClickListener() {
@ -1544,10 +1552,44 @@ public class GamesListDelegate extends ListDelegateBase
return handled;
}
private void startLoadOrStore( boolean isStore )
private Dialog mkLoadStoreDlg( final Uri uri )
{
Log.d( TAG, "mkLoadStoreDlg(%s)", uri );
final BackupConfigView view = (BackupConfigView)
LocUtils.inflate( m_activity, R.layout.backup_config_view );
view.init( uri );
AlertDialog.Builder ab = makeAlertBuilder()
.setView( view )
.setPositiveButton( view.getPosButtonTxt(), new OnClickListener() {
@Override
public void onClick( DialogInterface dlg, int item ) {
if ( null == uri ) { // store case
startFileChooser( view.getSaveWhat() );
} else {
List<ZipUtils.SaveWhat> what = view.getSaveWhat();
if ( ZipUtils.load( m_activity, uri, what ) ) {
ProcessPhoenix.triggerRebirth( m_activity );
}
}
}
} )
.setNegativeButton( android.R.string.cancel, null )
;
return ab.create();
}
// This is in liu of passing through the startActivityForResult call,
// which apparently isn't supported.
private List<ZipUtils.SaveWhat> mSaveWhat;
private void startFileChooser( List<SaveWhat> what )
{
mSaveWhat = what; // will be null in load case
String intentAction = null;
RequestCode rq = null;
boolean isStore = null != what;
if ( isStore ) {
intentAction = Intent.ACTION_CREATE_DOCUMENT;
rq = RequestCode.STORE_DATA_FILE;
@ -1557,30 +1599,13 @@ public class GamesListDelegate extends ListDelegateBase
}
Intent intent = new Intent( intentAction );
intent.addCategory( Intent.CATEGORY_OPENABLE );
intent.setType( "application/octet-stream" );
intent.setType( ZipUtils.getMimeType() );
if ( isStore ) {
intent.putExtra( Intent.EXTRA_TITLE, DBHelper.getDBName() );
}
startActivityForResult( intent, rq );
}
private void handleLoadOrStoreResult( Uri uri, boolean isStore )
{
if ( isStore ) {
boolean saved = DBUtils.saveDB( m_activity, uri );
int msgID = saved ? R.string.db_store_done
: R.string.db_store_failed;
showToast( msgID );
} else {
if ( DBUtils.loadDB( m_activity, uri ) ) {
storeGroupPositions( null );
mkListAdapter();
// We really want to exit the app!!! PENDING
}
}
}
@Override
public boolean onNegButton( Action action, Object[] params )
{
@ -1625,9 +1650,23 @@ public class GamesListDelegate extends ListDelegateBase
case STORE_DATA_FILE:
case LOAD_DATA_FILE:
if ( Activity.RESULT_OK == resultCode && data != null ) {
boolean isStore = RequestCode.STORE_DATA_FILE == requestCode;
Uri uri = data.getData();
handleLoadOrStoreResult( uri, isStore );
boolean isStore = RequestCode.STORE_DATA_FILE == requestCode;
if ( isStore ) {
boolean saved =
ZipUtils.save( m_activity, uri, mSaveWhat );
int msgID = saved ? R.string.db_store_done
: R.string.db_store_failed;
showToast( msgID );
} else {
final String uriStr = uri.toString();
post( new Runnable() {
@Override
public void run() {
showDialogFragment( DlgID.BACKUP_LOADSTORE, uriStr );
}
} );
}
}
break;
}
@ -1843,9 +1882,18 @@ public class GamesListDelegate extends ListDelegateBase
Utils.emailAuthor( m_activity );
break;
case R.id.games_menu_loaddb:
// Load and store both use the same dialog, and both use the
// ContentResolver/startActivityForResult grossness, but in
// different orders. Store needs to know *what* to store before
// asking where, but load needs to know what's being loaded before
// asking what subset of that the user wants to use. So we start
// with the choose-what alert in the store case, and with the
// choose-where (OS) grossness in the load case
case R.id.games_menu_storedb:
startLoadOrStore( R.id.games_menu_storedb == itemID );
showDialogFragment( DlgID.BACKUP_LOADSTORE );
break;
case R.id.games_menu_loaddb:
startFileChooser( null );
break;
case R.id.games_menu_writegit:

View file

@ -40,6 +40,7 @@ import org.eehouse.android.xw4.jni.CommonPrefs;
import org.eehouse.android.xw4.loc.LocUtils;
import java.io.File;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
@ -367,21 +368,20 @@ public class PrefsDelegate extends DelegateBase
}
}
static void savePrefs( Context context )
static Serializable getPrefs( Context context )
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( context );
Map<String, ?> all = prefs.getAll();
HashMap<String, Object> copy = new HashMap<>();
HashMap<String, Object> result = new HashMap<>();
for ( String key : all.keySet() ) {
copy.put( key, all.get(key) );
result.put( key, all.get(key) );
}
DBUtils.setSerializableFor( context, PREFS_KEY, copy );
return result;
}
static void loadPrefs( Context context ) {
HashMap<String, Object> map = (HashMap<String, Object>)DBUtils
.getSerializableFor( context, PREFS_KEY );
if ( null != map ) {
static void loadPrefs( Context context, Serializable obj ) {
if ( null != obj ) {
HashMap<String, Object> map = (HashMap<String, Object>)obj;
SharedPreferences.Editor editor =
PreferenceManager.getDefaultSharedPreferences( context )
.edit();

View file

@ -788,29 +788,35 @@ public class Utils {
return Base64.decode( in, Base64.NO_WRAP );
}
public static Object string64ToSerializable( String str64 )
public static Serializable bytesToSerializable( byte[] bytes )
{
Object result = null;
byte[] bytes = base64Decode( str64 );
Serializable result = null;
try {
ObjectInputStream ois =
new ObjectInputStream( new ByteArrayInputStream(bytes) );
result = ois.readObject();
result = (Serializable)ois.readObject();
} catch ( Exception ex ) {
Log.d( TAG, "%s", ex.getMessage() );
}
return result;
}
public static String serializableToString64( Serializable obj )
public static Object string64ToSerializable( String str64 )
{
String result = null;
byte[] bytes = base64Decode( str64 );
Serializable result = bytesToSerializable(bytes);
return result;
}
public static byte[] serializableToBytes( Serializable obj )
{
byte[] result = null;
ByteArrayOutputStream bas = new ByteArrayOutputStream();
try {
ObjectOutputStream out = new ObjectOutputStream( bas );
out.writeObject( obj );
out.flush();
result = base64Encode( bas.toByteArray() );
result = bas.toByteArray();
} catch ( Exception ex ) {
Log.ex( TAG, ex );
Assert.failDbg();
@ -818,6 +824,13 @@ public class Utils {
return result;
}
public static String serializableToString64( Serializable obj )
{
byte[] asBytes = serializableToBytes( obj );
String result = base64Encode( asBytes );
return result;
}
public static void testSerialization( Serializable obj )
{
if ( false && BuildConfig.DEBUG ) {

View file

@ -0,0 +1,218 @@
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
/*
* Copyright 2022 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program 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 2 of the
* License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.eehouse.android.xw4;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class ZipUtils {
private static final String TAG = ZipUtils.class.getSimpleName();
public static enum SaveWhat { // COLORS,
SETTINGS,
GAMES,
;
String entryName() { return toString(); }
};
static String getMimeType() {
return "application/x-zip";
// return "application/octet-stream";
}
private interface EntryIter {
boolean withEntry( ZipInputStream zis, SaveWhat what ) throws FileNotFoundException, IOException;
}
public static List<SaveWhat> getHasWhats( Context context, Uri uri )
{
final List<SaveWhat> result = new ArrayList<>();
try {
iterate( context, uri, new EntryIter() {
@Override
public boolean withEntry( ZipInputStream zis, SaveWhat what ) {
result.add( what );
return true;
}
} );
} catch ( IOException ioe ) {
Log.ex( TAG, ioe );
}
Log.d( TAG, "getHasWhats() => %s", result );
return result;
}
public static boolean load( Context context, Uri uri,
final List<SaveWhat> whats )
{
Log.d( TAG, "load(%s)", whats );
boolean result = false;
try {
result = iterate( context, uri, new EntryIter() {
@Override
public boolean withEntry( ZipInputStream zis, SaveWhat what )
throws FileNotFoundException, IOException {
boolean success = false;
if ( whats.contains( what ) ) {
switch ( what ) {
case SETTINGS:
success = loadSettings( context, zis );
break;
case GAMES:
success = loadGames( context, zis );
break;
default:
Assert.failDbg();
break;
}
}
return success;
}
} );
} catch ( Exception ex ) {
Log.ex( TAG, ex );
result = false;
}
return result;
}
private static boolean iterate( Context context, Uri uri, EntryIter iter )
throws IOException, FileNotFoundException
{
boolean success = true;
try ( InputStream is = context
.getContentResolver().openInputStream( uri ) ) {
ZipInputStream zis = new ZipInputStream( is );
while ( success ) {
ZipEntry ze = zis.getNextEntry();
if ( null == ze ) {
break;
}
String name = ze.getName();
Log.d( TAG, "next entry name: %s", name );
SaveWhat what = SaveWhat.valueOf( name );
success = iter.withEntry( zis, what );
}
zis.close();
}
return success;
}
public static boolean save( Context context, Uri uri,
List<SaveWhat> whats )
{
Log.d( TAG, "save(%s)", whats );
boolean success = false;
ContentResolver resolver = context.getContentResolver();
// resolver.delete( uri, null, null ); // nuke the file if exists
try ( OutputStream os = resolver.openOutputStream( uri ) ) {
ZipOutputStream zos = new ZipOutputStream( os ) ;
for ( SaveWhat what : whats ) {
zos.putNextEntry( new ZipEntry( what.entryName() ) );
switch ( what ) {
// case SAVE_COLORS:
// success = saveColors( zos, ze );
// break;
case SETTINGS:
success = saveSettings( context, zos );
break;
case GAMES:
success = saveGames( context, zos );
break;
default:
Assert.failDbg();
}
if ( success ) {
zos.closeEntry();
} else {
break;
}
}
zos.close();
os.close();
} catch ( Exception ex ) {
Log.ex( TAG, ex );
}
Log.d( TAG, "save(%s) DONE", whats );
return success;
}
private static boolean saveGames( Context context, ZipOutputStream zos )
throws FileNotFoundException, IOException
{
String name = DBHelper.getDBName();
File gamesDB = context.getDatabasePath( name );
FileInputStream fis = new FileInputStream( gamesDB );
boolean success = DBUtils.copyStream( zos, fis );
return success;
}
private static boolean loadGames( Context context, ZipInputStream zis )
throws FileNotFoundException, IOException
{
String name = DBHelper.getDBName();
File gamesDB = context.getDatabasePath( name );
FileOutputStream fos = new FileOutputStream( gamesDB );
boolean success = DBUtils.copyStream( fos, zis );
return success;
}
private static boolean saveSettings( Context context, ZipOutputStream zos )
throws IOException
{
Serializable map = PrefsDelegate.getPrefs( context );
byte[] asBytes = Utils.serializableToBytes( map );
ByteArrayInputStream bis = new ByteArrayInputStream( asBytes );
boolean success = DBUtils.copyStream( zos, bis );
return success;
}
private static boolean loadSettings( Context context, ZipInputStream zis )
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
boolean success = DBUtils.copyStream( bos, zis );
if ( success ) {
Serializable map = Utils.bytesToSerializable( bos.toByteArray() );
PrefsDelegate.loadPrefs( context, map );
}
return success;
}
}

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<org.eehouse.android.xw4.BackupConfigView
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp"
>
<TextView android:id="@+id/explanation"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="replace me"
/>
<!-- Checkboxes get added here -->
<LinearLayout android:id="@+id/whats_list"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
</org.eehouse.android.xw4.BackupConfigView>