Skip to content

Commit 2a126f2

Browse files
Use SAF when available for exporting the database file
Signed-off-by: Daniele Ricci <[email protected]>
1 parent 8f48a3f commit 2a126f2

File tree

4 files changed

+121
-17
lines changed

4 files changed

+121
-17
lines changed

app/src/main/java/org/kontalk/ui/prefs/AccountFragment.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ public void onPassphraseChanged(String passphrase) {
207207
Context ctx = getContext();
208208
if (ctx != null) {
209209
new FolderChooserDialog.Builder(ctx)
210+
.tag(AccountFragment.this.getClass().getName())
210211
.initialPath(PersonalKeyPack.DEFAULT_KEYPACK.getParent())
211212
.show(getParentFragmentManager());
212213
}

app/src/main/java/org/kontalk/ui/prefs/CopyDatabasePreference.java

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,25 @@
1919
package org.kontalk.ui.prefs;
2020

2121
import android.annotation.TargetApi;
22+
import android.app.Activity;
23+
import android.content.ActivityNotFoundException;
2224
import android.content.Context;
25+
import android.net.Uri;
2326
import android.os.Build;
2427
import android.os.Environment;
28+
29+
import androidx.fragment.app.Fragment;
2530
import androidx.preference.Preference;
2631
import android.util.AttributeSet;
2732
import android.widget.Toast;
2833

34+
import org.kontalk.Kontalk;
35+
import org.kontalk.Log;
2936
import org.kontalk.R;
3037
import org.kontalk.provider.MessagesProvider;
38+
import org.kontalk.reporting.ReportingManager;
3139
import org.kontalk.util.DataUtils;
40+
import org.kontalk.util.MediaStorage;
3241

3342
import java.io.File;
3443
import java.io.FileInputStream;
@@ -37,12 +46,22 @@
3746
import java.io.InputStream;
3847
import java.io.OutputStream;
3948

49+
import com.afollestad.materialdialogs.folderselector.FolderChooserDialog;
50+
4051

4152
/**
4253
* Preference for copying the messages database to the external storage.
4354
* @author Daniele Ricci
4455
*/
4556
public class CopyDatabasePreference extends Preference {
57+
private static final String TAG = Kontalk.TAG;
58+
59+
public static final int REQUEST_COPY_DATABASE = Activity.RESULT_FIRST_USER + 4;
60+
61+
private static final String DBFILE_MIME = "application/x-sqlite3";
62+
public static final String DBFILE_NAME = "kontalk-messages.db";
63+
64+
private Fragment mFragment;
4665

4766
public CopyDatabasePreference(Context context) {
4867
super(context);
@@ -69,25 +88,80 @@ private void init() {
6988
setOnPreferenceClickListener(new OnPreferenceClickListener() {
7089
@Override
7190
public boolean onPreferenceClick(Preference preference) {
72-
copyDatabase(getContext());
91+
requestFile(getContext());
7392
return true;
7493
}
7594
});
7695
}
7796

78-
void copyDatabase(Context context) {
79-
MessagesProvider.lockForImport(context);
97+
public void setParentFragment(Fragment fragment) {
98+
mFragment = fragment;
99+
}
80100

81-
InputStream dbIn = null;
101+
void requestFile(Context context) {
102+
try {
103+
if (MediaStorage.isStorageAccessFrameworkAvailable()) {
104+
MediaStorage.createFile(mFragment, DBFILE_MIME, DBFILE_NAME,
105+
REQUEST_COPY_DATABASE);
106+
return;
107+
}
108+
}
109+
catch (ActivityNotFoundException e) {
110+
Log.w(TAG, "Storage Access Framework not working properly");
111+
ReportingManager.logException(e);
112+
}
113+
114+
// also used as a fallback if SAF is not working properly
115+
Context ctx = getContext();
116+
if (ctx != null) {
117+
new FolderChooserDialog.Builder(ctx)
118+
.tag(getClass().getName())
119+
.initialPath(Environment.getExternalStorageDirectory().toString())
120+
.show(mFragment.getParentFragmentManager());
121+
}
122+
}
123+
124+
public static void copyDatabase(Context context, File dbOutFile) {
82125
OutputStream dbOut = null;
83126
try {
84-
File dbOutFile = new File(Environment.getExternalStorageDirectory(), "kontalk-messages.db");
127+
dbOut = new FileOutputStream(dbOutFile);
128+
copyDatabase(context, dbOut, dbOut.toString());
129+
}
130+
catch (IOException e) {
131+
Toast.makeText(context, context
132+
.getString(R.string.msg_copy_database_failed, e.toString()), Toast.LENGTH_LONG)
133+
.show();
134+
}
135+
finally {
136+
DataUtils.close(dbOut);
137+
}
138+
}
139+
140+
public static void copyDatabase(Context context, Uri dbOutFile) {
141+
OutputStream dbOut = null;
142+
try {
143+
dbOut = context.getContentResolver().openOutputStream(dbOutFile);
144+
copyDatabase(context, dbOut, dbOutFile.toString());
145+
}
146+
catch (IOException e) {
147+
Toast.makeText(context, context
148+
.getString(R.string.msg_copy_database_failed, e.toString()), Toast.LENGTH_LONG)
149+
.show();
150+
}
151+
finally {
152+
DataUtils.close(dbOut);
153+
}
154+
}
85155

156+
private static void copyDatabase(Context context, OutputStream dbOut, String filename) {
157+
MessagesProvider.lockForImport(context);
158+
159+
InputStream dbIn = null;
160+
try {
86161
dbIn = new FileInputStream(MessagesProvider.getDatabaseUri(context));
87-
dbOut = new FileOutputStream(dbOutFile);
88162
DataUtils.copy(dbIn, dbOut);
89163
Toast.makeText(context, context
90-
.getString(R.string.msg_copy_database_success, dbOutFile.toString()), Toast.LENGTH_LONG)
164+
.getString(R.string.msg_copy_database_success, filename), Toast.LENGTH_LONG)
91165
.show();
92166
}
93167
catch (IOException e) {

app/src/main/java/org/kontalk/ui/prefs/MaintenanceFragment.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@
1818

1919
package org.kontalk.ui.prefs;
2020

21+
import android.app.Activity;
22+
import android.content.Context;
23+
import android.content.Intent;
2124
import android.os.Bundle;
2225
import android.widget.Toast;
2326

27+
import androidx.annotation.Nullable;
2428
import androidx.preference.CheckBoxPreference;
2529
import androidx.preference.Preference;
2630

@@ -53,6 +57,10 @@ public boolean onPreferenceClick(Preference preference) {
5357
}
5458
});
5559

60+
// send our stuff to the copy database preference
61+
final CopyDatabasePreference copyDatabase = findPreference("pref_copy_database");
62+
copyDatabase.setParentFragment(this);
63+
5664
if (Kontalk.get().getDefaultAccount() == null) {
5765
// no account, hide/disable some stuff
5866
restartMsgCenter.setEnabled(false);
@@ -74,4 +82,18 @@ public void onResume() {
7482
.setTitle(R.string.pref_maintenance);
7583
}
7684

85+
@Override
86+
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
87+
if (requestCode == CopyDatabasePreference.REQUEST_COPY_DATABASE) {
88+
if (resultCode == Activity.RESULT_OK) {
89+
Context ctx = getActivity();
90+
if (ctx != null && data != null && data.getData() != null) {
91+
CopyDatabasePreference.copyDatabase(ctx, data.getData());
92+
}
93+
}
94+
}
95+
else {
96+
super.onActivityResult(requestCode, resultCode, data);
97+
}
98+
}
7799
}

app/src/main/java/org/kontalk/ui/prefs/PreferencesActivity.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -134,17 +134,24 @@ public void onNestedPreferenceSelected(int key) {
134134

135135
@Override
136136
public void onFolderSelection(@NonNull FolderChooserDialog folderChooserDialog, @NonNull File folder) {
137-
try {
138-
AccountFragment f = (AccountFragment) getSupportFragmentManager()
139-
.findFragmentById(R.id.container);
140-
f.exportPersonalKey(this,
141-
new FileOutputStream(new File(folder, PersonalKeyPack.KEYPACK_FILENAME)));
137+
final String tag = folderChooserDialog.getTag();
138+
if (tag.equals(CopyDatabasePreference.class.getName())) {
139+
CopyDatabasePreference.copyDatabase(this,
140+
new File(folder, CopyDatabasePreference.DBFILE_NAME));
142141
}
143-
catch (FileNotFoundException e) {
144-
Log.e(PreferencesFragment.TAG, "error exporting keys", e);
145-
Toast.makeText(this,
146-
R.string.err_keypair_export_write,
147-
Toast.LENGTH_LONG).show();
142+
else if (tag.equals(AccountFragment.class.getName())) {
143+
try {
144+
AccountFragment f = (AccountFragment) getSupportFragmentManager()
145+
.findFragmentById(R.id.container);
146+
f.exportPersonalKey(this,
147+
new FileOutputStream(new File(folder, PersonalKeyPack.KEYPACK_FILENAME)));
148+
}
149+
catch (FileNotFoundException e) {
150+
Log.e(PreferencesFragment.TAG, "error exporting keys", e);
151+
Toast.makeText(this,
152+
R.string.err_keypair_export_write,
153+
Toast.LENGTH_LONG).show();
154+
}
148155
}
149156
}
150157

0 commit comments

Comments
 (0)