mirror of
https://github.com/moparisthebest/open-keychain
synced 2025-02-17 07:30:14 -05:00
Improve file more, Part 1
- Use Uris where it makes sense, Use File class to clarify it's a file (and not whatever else a string could be) - Show sdcard in side menu in storage API #665 - Propose filename with gpg ending when storing it using the storage API #665 - Don't show output dialog on Android 4.4 #665 - Only show filename on Android < 4.4 #665 TODO: - File deletion for Android < 4.4 - Testing (especially with Android < 4.4) - Batch-encryption - UI - Temporary content provider (see #665 discussion)
This commit is contained in:
parent
313e571a61
commit
79fb23b095
@ -27,6 +27,8 @@ import org.sufficientlysecure.keychain.ui.DecryptActivity;
|
||||
import org.sufficientlysecure.keychain.ui.EncryptActivity;
|
||||
import org.sufficientlysecure.keychain.ui.KeyListActivity;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public final class Constants {
|
||||
|
||||
public static final boolean DEBUG = BuildConfig.DEBUG;
|
||||
@ -52,9 +54,8 @@ public final class Constants {
|
||||
public static boolean KITKAT = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
||||
|
||||
public static final class Path {
|
||||
public static final String APP_DIR = Environment.getExternalStorageDirectory()
|
||||
+ "/OpenKeychain";
|
||||
public static final String APP_DIR_FILE = APP_DIR + "/export.asc";
|
||||
public static final File APP_DIR = new File(Environment.getExternalStorageDirectory(), "OpenKeychain");
|
||||
public static final File APP_DIR_FILE = new File(APP_DIR, "export.asc");
|
||||
}
|
||||
|
||||
public static final class Pref {
|
||||
|
@ -26,11 +26,9 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Environment;
|
||||
|
||||
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.sufficientlysecure.keychain.helper.ContactHelper;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.PRNGFixes;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
|
||||
@ -70,8 +68,7 @@ public class KeychainApplication extends Application {
|
||||
|
||||
// Create APG directory on sdcard if not existing
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
File dir = new File(Constants.Path.APP_DIR);
|
||||
if (!dir.exists() && !dir.mkdirs()) {
|
||||
if (!Constants.Path.APP_DIR.exists() && !Constants.Path.APP_DIR.mkdirs()) {
|
||||
// ignore this for now, it's not crucial
|
||||
// that the directory doesn't exist at this point
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ import android.widget.Toast;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||
@ -39,9 +38,10 @@ import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class ExportHelper {
|
||||
protected FileDialogFragment mFileDialog;
|
||||
protected String mExportFilename;
|
||||
protected File mExportFile;
|
||||
|
||||
ActionBarActivity mActivity;
|
||||
|
||||
@ -68,47 +68,30 @@ public class ExportHelper {
|
||||
/**
|
||||
* Show dialog where to export keys
|
||||
*/
|
||||
public void showExportKeysDialog(final long[] masterKeyIds, final String exportFilename,
|
||||
public void showExportKeysDialog(final long[] masterKeyIds, final File exportFile,
|
||||
final boolean showSecretCheckbox) {
|
||||
mExportFilename = exportFilename;
|
||||
mExportFile = exportFile;
|
||||
|
||||
// Message is received after file is selected
|
||||
Handler returnHandler = new Handler() {
|
||||
String title = null;
|
||||
if (masterKeyIds == null) {
|
||||
// export all keys
|
||||
title = mActivity.getString(R.string.title_export_keys);
|
||||
} else {
|
||||
// export only key specified at data uri
|
||||
title = mActivity.getString(R.string.title_export_key);
|
||||
}
|
||||
|
||||
String message = mActivity.getString(R.string.specify_file_to_export_to);
|
||||
String checkMsg = showSecretCheckbox ?
|
||||
mActivity.getString(R.string.also_export_secret_keys) : null;
|
||||
|
||||
FileHelper.saveFile(new FileHelper.FileDialogCallback() {
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
if (message.what == FileDialogFragment.MESSAGE_OKAY) {
|
||||
Bundle data = message.getData();
|
||||
mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
|
||||
|
||||
exportKeys(masterKeyIds, data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED));
|
||||
}
|
||||
public void onFileSelected(File file, boolean checked) {
|
||||
mExportFile = file;
|
||||
exportKeys(masterKeyIds, checked);
|
||||
}
|
||||
};
|
||||
|
||||
// Create a new Messenger for the communication back
|
||||
final Messenger messenger = new Messenger(returnHandler);
|
||||
|
||||
DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
|
||||
public void run() {
|
||||
String title = null;
|
||||
if (masterKeyIds == null) {
|
||||
// export all keys
|
||||
title = mActivity.getString(R.string.title_export_keys);
|
||||
} else {
|
||||
// export only key specified at data uri
|
||||
title = mActivity.getString(R.string.title_export_key);
|
||||
}
|
||||
|
||||
String message = mActivity.getString(R.string.specify_file_to_export_to);
|
||||
String checkMsg = showSecretCheckbox ?
|
||||
mActivity.getString(R.string.also_export_secret_keys) : null;
|
||||
|
||||
mFileDialog = FileDialogFragment.newInstance(messenger, title, message,
|
||||
exportFilename, checkMsg);
|
||||
|
||||
mFileDialog.show(mActivity.getSupportFragmentManager(), "fileDialog");
|
||||
}
|
||||
});
|
||||
}, mActivity.getSupportFragmentManager() ,title, message, exportFile, checkMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,7 +108,7 @@ public class ExportHelper {
|
||||
// fill values for this action
|
||||
Bundle data = new Bundle();
|
||||
|
||||
data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename);
|
||||
data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFile.getAbsolutePath());
|
||||
data.putBoolean(KeychainIntentService.EXPORT_SECRET, exportSecret);
|
||||
|
||||
if (masterKeyIds == null) {
|
||||
|
@ -26,12 +26,19 @@ import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class FileHelper {
|
||||
|
||||
@ -55,25 +62,18 @@ public class FileHelper {
|
||||
* Opens the preferred installed file manager on Android and shows a toast if no manager is
|
||||
* installed.
|
||||
*
|
||||
* @param activity
|
||||
* @param filename default selected file, not supported by all file managers
|
||||
* @param fragment
|
||||
* @param last default selected Uri, not supported by all file managers
|
||||
* @param mimeType can be text/plain for example
|
||||
* @param requestCode requestCode used to identify the result coming back from file manager to
|
||||
* onActivityResult() in your activity
|
||||
*/
|
||||
public static void openFile(Activity activity, String filename, String mimeType, int requestCode) {
|
||||
Intent intent = buildFileIntent(filename, mimeType);
|
||||
public static void openFile(Fragment fragment, Uri last, String mimeType, int requestCode) {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
|
||||
try {
|
||||
activity.startActivityForResult(intent, requestCode);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
// No compatible file manager was found.
|
||||
Toast.makeText(activity, R.string.no_filemanager_installed, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
public static void openFile(Fragment fragment, String filename, String mimeType, int requestCode) {
|
||||
Intent intent = buildFileIntent(filename, mimeType);
|
||||
intent.setData(last);
|
||||
intent.setType(mimeType);
|
||||
|
||||
try {
|
||||
fragment.startActivityForResult(intent, requestCode);
|
||||
@ -84,19 +84,62 @@ public class FileHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveFile(final FileDialogCallback callback, final FragmentManager fragmentManager,
|
||||
final String title, final String message, final File defaultFile,
|
||||
final String checkMsg) {
|
||||
// Message is received after file is selected
|
||||
Handler returnHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
if (message.what == FileDialogFragment.MESSAGE_OKAY) {
|
||||
callback.onFileSelected(
|
||||
new File(message.getData().getString(FileDialogFragment.MESSAGE_DATA_FILE)),
|
||||
message.getData().getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Create a new Messenger for the communication back
|
||||
final Messenger messenger = new Messenger(returnHandler);
|
||||
|
||||
DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FileDialogFragment fileDialog = FileDialogFragment.newInstance(messenger, title, message,
|
||||
defaultFile, checkMsg);
|
||||
|
||||
fileDialog.show(fragmentManager, "fileDialog");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void saveFile(Fragment fragment, String title, String message, File defaultFile, int requestCode) {
|
||||
saveFile(fragment, title, message, defaultFile, requestCode, null);
|
||||
}
|
||||
|
||||
public static void saveFile(final Fragment fragment, String title, String message, File defaultFile,
|
||||
final int requestCode, String checkMsg) {
|
||||
saveFile(new FileDialogCallback() {
|
||||
@Override
|
||||
public void onFileSelected(File file, boolean checked) {
|
||||
Intent intent = new Intent();
|
||||
intent.setData(Uri.fromFile(file));
|
||||
fragment.onActivityResult(requestCode, Activity.RESULT_OK, intent);
|
||||
}
|
||||
}, fragment.getActivity().getSupportFragmentManager(), title, message, defaultFile, checkMsg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens the storage browser on Android 4.4 or later for opening a file
|
||||
* @param fragment
|
||||
* @param last default selected file
|
||||
* @param mimeType can be text/plain for example
|
||||
* @param requestCode used to identify the result coming back from storage browser onActivityResult() in your
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
public static void openDocument(Fragment fragment, Uri last, String mimeType, int requestCode) {
|
||||
public static void openDocument(Fragment fragment, String mimeType, int requestCode) {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setData(last);
|
||||
intent.setType(mimeType);
|
||||
fragment.startActivityForResult(intent, requestCode);
|
||||
}
|
||||
@ -104,66 +147,42 @@ public class FileHelper {
|
||||
/**
|
||||
* Opens the storage browser on Android 4.4 or later for saving a file
|
||||
* @param fragment
|
||||
* @param last default selected file
|
||||
* @param mimeType can be text/plain for example
|
||||
* @param suggestedName a filename desirable for the file to be saved
|
||||
* @param requestCode used to identify the result coming back from storage browser onActivityResult() in your
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
public static void saveDocument(Fragment fragment, Uri last, String mimeType, int requestCode) {
|
||||
public static void saveDocument(Fragment fragment, String mimeType, String suggestedName, int requestCode) {
|
||||
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setData(last);
|
||||
intent.setType(mimeType);
|
||||
intent.putExtra("android.content.extra.SHOW_ADVANCED", true); // Note: This is not documented, but works
|
||||
intent.putExtra(Intent.EXTRA_TITLE, suggestedName);
|
||||
fragment.startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
private static Intent buildFileIntent(String filename, String mimeType) {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
public static String getFilename(Context context, Uri uri) {
|
||||
String filename = null;
|
||||
try {
|
||||
Cursor cursor = context.getContentResolver().query(uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
|
||||
|
||||
intent.setData(Uri.parse("file://" + filename));
|
||||
intent.setType(mimeType);
|
||||
|
||||
return intent;
|
||||
if (cursor != null) {
|
||||
if (cursor.moveToNext()) {
|
||||
filename = cursor.getString(0);
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
// This happens in rare cases (eg: document deleted since selection) and should not cause a failure
|
||||
}
|
||||
if (filename == null) {
|
||||
String[] split = uri.toString().split("/");
|
||||
filename = split[split.length - 1];
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a file path from a Uri.
|
||||
* <p/>
|
||||
* from https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/
|
||||
* afilechooser/utils/FileUtils.java
|
||||
*
|
||||
* @param context
|
||||
* @param uri
|
||||
* @return
|
||||
* @author paulburke
|
||||
*/
|
||||
public static String getPath(Context context, Uri uri) {
|
||||
Log.d(Constants.TAG + " File -",
|
||||
"Authority: " + uri.getAuthority() + ", Fragment: " + uri.getFragment()
|
||||
+ ", Port: " + uri.getPort() + ", Query: " + uri.getQuery() + ", Scheme: "
|
||||
+ uri.getScheme() + ", Host: " + uri.getHost() + ", Segments: "
|
||||
+ uri.getPathSegments().toString());
|
||||
|
||||
if ("content".equalsIgnoreCase(uri.getScheme())) {
|
||||
String[] projection = {"_data"};
|
||||
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
|
||||
try {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int columnIndex = cursor.getColumnIndexOrThrow("_data");
|
||||
return cursor.getString(columnIndex);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Eat it
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
|
||||
return uri.getPath();
|
||||
}
|
||||
|
||||
return null;
|
||||
public static interface FileDialogCallback {
|
||||
public void onFileSelected(File file, boolean checked);
|
||||
}
|
||||
}
|
||||
|
@ -139,6 +139,7 @@ public class KeychainIntentService extends IntentService
|
||||
// export key
|
||||
public static final String EXPORT_OUTPUT_STREAM = "export_output_stream";
|
||||
public static final String EXPORT_FILENAME = "export_filename";
|
||||
public static final String EXPORT_URI = "export_uri";
|
||||
public static final String EXPORT_SECRET = "export_secret";
|
||||
public static final String EXPORT_ALL = "export_all";
|
||||
public static final String EXPORT_KEY_RING_MASTER_KEY_ID = "export_key_ring_id";
|
||||
@ -393,13 +394,16 @@ public class KeychainIntentService extends IntentService
|
||||
boolean exportSecret = data.getBoolean(EXPORT_SECRET, false);
|
||||
long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
|
||||
String outputFile = data.getString(EXPORT_FILENAME);
|
||||
Uri outputUri = data.getParcelable(EXPORT_URI);
|
||||
|
||||
// If not exporting all keys get the masterKeyIds of the keys to export from the intent
|
||||
boolean exportAll = data.getBoolean(EXPORT_ALL);
|
||||
|
||||
// check if storage is ready
|
||||
if (!FileHelper.isStorageMounted(outputFile)) {
|
||||
throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
|
||||
if (outputFile != null) {
|
||||
// check if storage is ready
|
||||
if (!FileHelper.isStorageMounted(outputFile)) {
|
||||
throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<Long> publicMasterKeyIds = new ArrayList<Long>();
|
||||
@ -431,12 +435,19 @@ public class KeychainIntentService extends IntentService
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream outStream;
|
||||
if (outputFile != null) {
|
||||
outStream = new FileOutputStream(outputFile);
|
||||
} else {
|
||||
outStream = getContentResolver().openOutputStream(outputUri);
|
||||
}
|
||||
|
||||
PgpImportExport pgpImportExport = new PgpImportExport(this, this, this);
|
||||
Bundle resultData = pgpImportExport
|
||||
.exportKeyRings(publicMasterKeyIds, secretMasterKeyIds,
|
||||
new FileOutputStream(outputFile));
|
||||
outStream);
|
||||
|
||||
if (mIsCanceled) {
|
||||
if (mIsCanceled && outputFile != null) {
|
||||
boolean isDeleted = new File(outputFile).delete();
|
||||
}
|
||||
|
||||
|
@ -23,11 +23,9 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.view.PagerTabStrip;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.FileHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
@ -114,7 +112,7 @@ public class DecryptActivity extends DrawerActivity {
|
||||
} else {
|
||||
// Binary via content provider (could also be files)
|
||||
// override uri to get stream from send
|
||||
uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
||||
uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
||||
action = ACTION_DECRYPT;
|
||||
}
|
||||
} else if (Intent.ACTION_VIEW.equals(action)) {
|
||||
@ -155,21 +153,8 @@ public class DecryptActivity extends DrawerActivity {
|
||||
}
|
||||
}
|
||||
} else if (ACTION_DECRYPT.equals(action) && uri != null) {
|
||||
// get file path from uri
|
||||
String path = FileHelper.getPath(this, uri);
|
||||
|
||||
if (path != null) {
|
||||
mFileFragmentBundle.putString(DecryptFileFragment.ARG_FILENAME, path);
|
||||
mSwitchToTab = PAGER_TAB_FILE;
|
||||
} else {
|
||||
Log.e(Constants.TAG,
|
||||
"Direct binary data without actual file in filesystem is not supported. " +
|
||||
"Please use the Remote Service API!");
|
||||
Toast.makeText(this, R.string.error_only_files_are_supported, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
// end activity
|
||||
finish();
|
||||
}
|
||||
mFileFragmentBundle.putParcelable(DecryptFileFragment.ARG_URI, uri);
|
||||
mSwitchToTab = PAGER_TAB_FILE;
|
||||
} else {
|
||||
Log.e(Constants.TAG,
|
||||
"Include the extra 'text' or an Uri with setData() in your Intent!");
|
||||
|
@ -20,21 +20,17 @@ package org.sufficientlysecure.keychain.ui;
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
import com.devspark.appmsg.AppMsg;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
@ -44,29 +40,26 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||
import org.sufficientlysecure.keychain.util.Notify;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class DecryptFileFragment extends DecryptFragment {
|
||||
public static final String ARG_FILENAME = "filename";
|
||||
public static final String ARG_URI = "uri";
|
||||
|
||||
private static final int RESULT_CODE_FILE = 0x00007003;
|
||||
private static final int REQUEST_CODE_INPUT = 0x00007003;
|
||||
private static final int REQUEST_CODE_OUTPUT = 0x00007007;
|
||||
|
||||
// view
|
||||
private EditText mFilename;
|
||||
private TextView mFilename;
|
||||
private CheckBox mDeleteAfter;
|
||||
private BootstrapButton mBrowse;
|
||||
private View mDecryptButton;
|
||||
|
||||
private String mInputFilename = null;
|
||||
// model
|
||||
private Uri mInputUri = null;
|
||||
private String mOutputFilename = null;
|
||||
private Uri mOutputUri = null;
|
||||
|
||||
private FileDialogFragment mFileDialog;
|
||||
|
||||
/**
|
||||
* Inflate the layout for this fragment
|
||||
*/
|
||||
@ -74,17 +67,17 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.decrypt_file_fragment, container, false);
|
||||
|
||||
mFilename = (EditText) view.findViewById(R.id.decrypt_file_filename);
|
||||
mFilename = (TextView) view.findViewById(R.id.decrypt_file_filename);
|
||||
mBrowse = (BootstrapButton) view.findViewById(R.id.decrypt_file_browse);
|
||||
mDeleteAfter = (CheckBox) view.findViewById(R.id.decrypt_file_delete_after_decryption);
|
||||
mDecryptButton = view.findViewById(R.id.decrypt_file_action_decrypt);
|
||||
mBrowse.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
if (Constants.KITKAT) {
|
||||
FileHelper.openDocument(DecryptFileFragment.this, mInputUri, "*/*", RESULT_CODE_FILE);
|
||||
FileHelper.openDocument(DecryptFileFragment.this, "*/*", REQUEST_CODE_INPUT);
|
||||
} else {
|
||||
FileHelper.openFile(DecryptFileFragment.this, mFilename.getText().toString(), "*/*",
|
||||
RESULT_CODE_FILE);
|
||||
FileHelper.openFile(DecryptFileFragment.this, mInputUri, "*/*",
|
||||
REQUEST_CODE_INPUT);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -102,78 +95,48 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
String filename = getArguments().getString(ARG_FILENAME);
|
||||
if (filename != null) {
|
||||
mFilename.setText(filename);
|
||||
}
|
||||
setInputUri(getArguments().<Uri>getParcelable(ARG_URI));
|
||||
}
|
||||
|
||||
private String guessOutputFilename() {
|
||||
File file = new File(mInputFilename);
|
||||
String filename = file.getName();
|
||||
if (filename.endsWith(".asc") || filename.endsWith(".gpg") || filename.endsWith(".pgp")) {
|
||||
filename = filename.substring(0, filename.length() - 4);
|
||||
private void setInputUri(Uri inputUri) {
|
||||
if (inputUri == null) {
|
||||
mInputUri = null;
|
||||
mFilename.setText("");
|
||||
return;
|
||||
}
|
||||
return Constants.Path.APP_DIR + "/" + filename;
|
||||
|
||||
mInputUri = inputUri;
|
||||
mFilename.setText(FileHelper.getFilename(getActivity(), mInputUri));
|
||||
}
|
||||
|
||||
private void decryptAction() {
|
||||
String currentFilename = mFilename.getText().toString();
|
||||
if (mInputFilename == null || !mInputFilename.equals(currentFilename)) {
|
||||
mInputUri = null;
|
||||
mInputFilename = mFilename.getText().toString();
|
||||
}
|
||||
|
||||
if (mInputUri == null) {
|
||||
mOutputFilename = guessOutputFilename();
|
||||
}
|
||||
|
||||
if (mInputFilename.equals("")) {
|
||||
//AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
|
||||
Notify.showNotify(getActivity(), R.string.no_file_selected, Notify.Style.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mInputUri == null && mInputFilename.startsWith("file")) {
|
||||
File file = new File(mInputFilename);
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
AppMsg.makeText(
|
||||
getActivity(),
|
||||
getString(R.string.error_message,
|
||||
getString(R.string.error_file_not_found)), AppMsg.STYLE_ALERT)
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
askForOutputFilename();
|
||||
}
|
||||
|
||||
private String removeEncryptedAppend(String name) {
|
||||
if (name.endsWith(".asc") || name.endsWith(".gpg") || name.endsWith(".pgp")) {
|
||||
return name.substring(0, name.length() - 4);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private void askForOutputFilename() {
|
||||
// Message is received after passphrase is cached
|
||||
Handler returnHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
if (message.what == FileDialogFragment.MESSAGE_OKAY) {
|
||||
Bundle data = message.getData();
|
||||
if (data.containsKey(FileDialogFragment.MESSAGE_DATA_URI)) {
|
||||
mOutputUri = data.getParcelable(FileDialogFragment.MESSAGE_DATA_URI);
|
||||
} else {
|
||||
mOutputFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
|
||||
}
|
||||
decryptStart(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Create a new Messenger for the communication back
|
||||
Messenger messenger = new Messenger(returnHandler);
|
||||
|
||||
mFileDialog = FileDialogFragment.newInstance(messenger,
|
||||
getString(R.string.title_decrypt_to_file),
|
||||
getString(R.string.specify_file_to_decrypt_to), mOutputFilename, null);
|
||||
|
||||
mFileDialog.show(getActivity().getSupportFragmentManager(), "fileDialog");
|
||||
String targetName = removeEncryptedAppend(FileHelper.getFilename(getActivity(), mInputUri));
|
||||
if (!Constants.KITKAT) {
|
||||
File file = new File(mInputUri.getPath());
|
||||
File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR;
|
||||
File targetFile = new File(parentDir, targetName);
|
||||
FileHelper.saveFile(this, getString(R.string.title_decrypt_to_file),
|
||||
getString(R.string.specify_file_to_decrypt_to), targetFile, REQUEST_CODE_OUTPUT);
|
||||
} else {
|
||||
FileHelper.saveDocument(this, "*/*", targetName, REQUEST_CODE_OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -189,25 +152,13 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY);
|
||||
|
||||
// data
|
||||
Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename="
|
||||
+ mOutputFilename + ",mInputUri=" + mInputUri + ", mOutputUri="
|
||||
+ mOutputUri);
|
||||
Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri);
|
||||
|
||||
if (mInputUri != null) {
|
||||
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URI);
|
||||
data.putParcelable(KeychainIntentService.ENCRYPT_INPUT_URI, mInputUri);
|
||||
} else {
|
||||
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_FILE);
|
||||
data.putString(KeychainIntentService.ENCRYPT_INPUT_FILE, mInputFilename);
|
||||
}
|
||||
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URI);
|
||||
data.putParcelable(KeychainIntentService.ENCRYPT_INPUT_URI, mInputUri);
|
||||
|
||||
if (mOutputUri != null) {
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URI);
|
||||
data.putParcelable(KeychainIntentService.ENCRYPT_OUTPUT_URI, mOutputUri);
|
||||
} else {
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_FILE);
|
||||
data.putString(KeychainIntentService.ENCRYPT_OUTPUT_FILE, mOutputFilename);
|
||||
}
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URI);
|
||||
data.putParcelable(KeychainIntentService.ENCRYPT_OUTPUT_URI, mOutputUri);
|
||||
|
||||
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase);
|
||||
|
||||
@ -238,14 +189,9 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
|
||||
if (mDeleteAfter.isChecked()) {
|
||||
// Create and show dialog to delete original file
|
||||
DeleteFileDialogFragment deleteFileDialog;
|
||||
if (mInputUri != null) {
|
||||
deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri);
|
||||
} else {
|
||||
deleteFileDialog = DeleteFileDialogFragment
|
||||
.newInstance(mInputFilename);
|
||||
}
|
||||
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri);
|
||||
deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
|
||||
setInputUri(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -266,28 +212,17 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case RESULT_CODE_FILE: {
|
||||
case REQUEST_CODE_INPUT: {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
if (Constants.KITKAT) {
|
||||
mInputUri = data.getData();
|
||||
Cursor cursor = getActivity().getContentResolver().query(mInputUri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
|
||||
if (cursor != null) {
|
||||
if (cursor.moveToNext()) {
|
||||
mInputFilename = cursor.getString(0);
|
||||
mFilename.setText(mInputFilename);
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
String path = FileHelper.getPath(getActivity(), data.getData());
|
||||
Log.d(Constants.TAG, "path=" + path);
|
||||
|
||||
mFilename.setText(path);
|
||||
} catch (NullPointerException e) {
|
||||
Log.e(Constants.TAG, "Nullpointer while retrieving path!");
|
||||
}
|
||||
}
|
||||
setInputUri(data.getData());
|
||||
}
|
||||
return;
|
||||
}
|
||||
case REQUEST_CODE_OUTPUT: {
|
||||
// This happens after output file was selected, so start our operation
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
mOutputUri = data.getData();
|
||||
decryptStart(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -23,11 +23,9 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.view.PagerTabStrip;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.FileHelper;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
@ -98,11 +96,7 @@ public class EncryptActivity extends DrawerActivity implements
|
||||
|
||||
@Override
|
||||
public boolean isModeSymmetric() {
|
||||
if (PAGER_MODE_SYMMETRIC == mViewPagerMode.getCurrentItem()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return PAGER_MODE_SYMMETRIC == mViewPagerMode.getCurrentItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -201,7 +195,7 @@ public class EncryptActivity extends DrawerActivity implements
|
||||
}
|
||||
} else {
|
||||
// Files via content provider, override uri and action
|
||||
uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
||||
uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
||||
action = ACTION_ENCRYPT;
|
||||
}
|
||||
}
|
||||
@ -232,23 +226,8 @@ public class EncryptActivity extends DrawerActivity implements
|
||||
mSwitchToContent = PAGER_CONTENT_MESSAGE;
|
||||
} else if (ACTION_ENCRYPT.equals(action) && uri != null) {
|
||||
// encrypt file based on Uri
|
||||
|
||||
// get file path from uri
|
||||
String path = FileHelper.getPath(this, uri);
|
||||
|
||||
if (path != null) {
|
||||
mFileFragmentBundle.putString(EncryptFileFragment.ARG_FILENAME, path);
|
||||
mSwitchToContent = PAGER_CONTENT_FILE;
|
||||
} else {
|
||||
Log.e(Constants.TAG,
|
||||
"Direct binary data without actual file in filesystem is not supported " +
|
||||
"by Intents. Please use the Remote Service API!"
|
||||
);
|
||||
Toast.makeText(this, R.string.error_only_files_are_supported,
|
||||
Toast.LENGTH_LONG).show();
|
||||
// end activity
|
||||
finish();
|
||||
}
|
||||
mFileFragmentBundle.putParcelable(EncryptFileFragment.ARG_URI, uri);
|
||||
mSwitchToContent = PAGER_CONTENT_FILE;
|
||||
} else {
|
||||
Log.e(Constants.TAG,
|
||||
"Include the extra 'text' or an Uri with setData() in your Intent!");
|
||||
|
@ -20,21 +20,19 @@ package org.sufficientlysecure.keychain.ui;
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
import com.devspark.appmsg.AppMsg;
|
||||
@ -47,7 +45,6 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
|
||||
import org.sufficientlysecure.keychain.util.Choice;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
@ -55,28 +52,25 @@ import org.sufficientlysecure.keychain.util.Log;
|
||||
import java.io.File;
|
||||
|
||||
public class EncryptFileFragment extends Fragment {
|
||||
public static final String ARG_FILENAME = "filename";
|
||||
public static final String ARG_URI = "uri";
|
||||
public static final String ARG_ASCII_ARMOR = "ascii_armor";
|
||||
|
||||
private static final int RESULT_CODE_FILE = 0x00007003;
|
||||
private static final int REQUEST_CODE_INPUT = 0x00007003;
|
||||
private static final int REQUEST_CODE_OUTPUT = 0x00007007;
|
||||
|
||||
private EncryptActivityInterface mEncryptInterface;
|
||||
|
||||
// view
|
||||
private CheckBox mAsciiArmor = null;
|
||||
private Spinner mFileCompression = null;
|
||||
private EditText mFilename = null;
|
||||
private TextView mFilename = null;
|
||||
private CheckBox mDeleteAfter = null;
|
||||
private CheckBox mShareAfter = null;
|
||||
private BootstrapButton mBrowse = null;
|
||||
private View mEncryptFile;
|
||||
|
||||
private FileDialogFragment mFileDialog;
|
||||
|
||||
// model
|
||||
private String mInputFilename = null;
|
||||
private Uri mInputUri = null;
|
||||
private String mOutputFilename = null;
|
||||
private Uri mOutputUri = null;
|
||||
|
||||
@Override
|
||||
@ -104,15 +98,15 @@ public class EncryptFileFragment extends Fragment {
|
||||
}
|
||||
});
|
||||
|
||||
mFilename = (EditText) view.findViewById(R.id.filename);
|
||||
mFilename = (TextView) view.findViewById(R.id.filename);
|
||||
mBrowse = (BootstrapButton) view.findViewById(R.id.btn_browse);
|
||||
mBrowse.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
if (Constants.KITKAT) {
|
||||
FileHelper.openDocument(EncryptFileFragment.this, mInputUri, "*/*", RESULT_CODE_FILE);
|
||||
FileHelper.openDocument(EncryptFileFragment.this, "*/*", REQUEST_CODE_INPUT);
|
||||
} else {
|
||||
FileHelper.openFile(EncryptFileFragment.this, mFilename.getText().toString(), "*/*",
|
||||
RESULT_CODE_FILE);
|
||||
FileHelper.openFile(EncryptFileFragment.this, mInputUri, "*/*",
|
||||
REQUEST_CODE_INPUT);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -154,84 +148,43 @@ public class EncryptFileFragment extends Fragment {
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
String filename = getArguments().getString(ARG_FILENAME);
|
||||
if (filename != null) {
|
||||
mFilename.setText(filename);
|
||||
}
|
||||
setInputUri(getArguments().<Uri>getParcelable(ARG_URI));
|
||||
boolean asciiArmor = getArguments().getBoolean(ARG_ASCII_ARMOR);
|
||||
if (asciiArmor) {
|
||||
mAsciiArmor.setChecked(asciiArmor);
|
||||
mAsciiArmor.setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess output filename based on input path
|
||||
*
|
||||
* @param path
|
||||
* @return Suggestion for output filename
|
||||
*/
|
||||
private String guessOutputFilename(String path) {
|
||||
// output in the same directory but with additional ending
|
||||
File file = new File(path);
|
||||
String ending = (mAsciiArmor.isChecked() ? ".asc" : ".gpg");
|
||||
String outputFilename = file.getParent() + File.separator + file.getName() + ending;
|
||||
|
||||
return outputFilename;
|
||||
}
|
||||
|
||||
private void showOutputFileDialog() {
|
||||
// Message is received after file is selected
|
||||
Handler returnHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
if (message.what == FileDialogFragment.MESSAGE_OKAY) {
|
||||
Bundle data = message.getData();
|
||||
if (data.containsKey(FileDialogFragment.MESSAGE_DATA_URI)) {
|
||||
mOutputUri = data.getParcelable(FileDialogFragment.MESSAGE_DATA_URI);
|
||||
} else {
|
||||
mOutputFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
|
||||
}
|
||||
encryptStart();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Create a new Messenger for the communication back
|
||||
Messenger messenger = new Messenger(returnHandler);
|
||||
|
||||
mFileDialog = FileDialogFragment.newInstance(messenger,
|
||||
getString(R.string.title_encrypt_to_file),
|
||||
getString(R.string.specify_file_to_encrypt_to), mOutputFilename, null);
|
||||
|
||||
mFileDialog.show(getActivity().getSupportFragmentManager(), "fileDialog");
|
||||
}
|
||||
|
||||
private void encryptClicked() {
|
||||
String currentFilename = mFilename.getText().toString();
|
||||
if (mInputFilename == null || !mInputFilename.equals(currentFilename)) {
|
||||
private void setInputUri(Uri inputUri) {
|
||||
if (inputUri == null) {
|
||||
mInputUri = null;
|
||||
mInputFilename = mFilename.getText().toString();
|
||||
}
|
||||
|
||||
if (mInputUri == null) {
|
||||
mOutputFilename = guessOutputFilename(mInputFilename);
|
||||
}
|
||||
|
||||
if (mInputFilename.equals("")) {
|
||||
AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
|
||||
mFilename.setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mInputUri == null && !mInputFilename.startsWith("content")) {
|
||||
File file = new File(mInputFilename);
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
AppMsg.makeText(
|
||||
getActivity(),
|
||||
getString(R.string.error_message,
|
||||
getString(R.string.error_file_not_found)), AppMsg.STYLE_ALERT)
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
mInputUri = inputUri;
|
||||
mFilename.setText(FileHelper.getFilename(getActivity(), mInputUri));
|
||||
}
|
||||
|
||||
private void showOutputFileDialog() {
|
||||
if (!Constants.KITKAT) {
|
||||
File file = new File(mInputUri.getPath());
|
||||
File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR;
|
||||
String targetName = FileHelper.getFilename(
|
||||
getActivity(), mInputUri) + (mAsciiArmor.isChecked() ? ".asc" : ".gpg");
|
||||
File targetFile = new File(parentDir, targetName);
|
||||
FileHelper.saveFile(this, getString(R.string.title_encrypt_to_file),
|
||||
getString(R.string.specify_file_to_encrypt_to), targetFile, REQUEST_CODE_OUTPUT);
|
||||
} else {
|
||||
FileHelper.saveDocument(this, "*/*", FileHelper.getFilename(getActivity(), mInputUri) +
|
||||
(mAsciiArmor.isChecked() ? ".asc" : ".gpg"), REQUEST_CODE_OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
private void encryptClicked() {
|
||||
if (mInputUri == null) {
|
||||
AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEncryptInterface.isModeSymmetric()) {
|
||||
@ -287,6 +240,10 @@ public class EncryptFileFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void encryptStart() {
|
||||
if (mInputUri == null || mOutputUri == null) {
|
||||
throw new IllegalStateException("Something went terribly wrong if this happens!");
|
||||
}
|
||||
|
||||
// Send all information needed to service to edit key in other thread
|
||||
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
|
||||
|
||||
@ -295,25 +252,13 @@ public class EncryptFileFragment extends Fragment {
|
||||
// fill values for this action
|
||||
Bundle data = new Bundle();
|
||||
|
||||
Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename="
|
||||
+ mOutputFilename + ",mInputUri=" + mInputUri + ", mOutputUri="
|
||||
+ mOutputUri);
|
||||
Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri);
|
||||
|
||||
if (mInputUri != null) {
|
||||
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URI);
|
||||
data.putParcelable(KeychainIntentService.ENCRYPT_INPUT_URI, mInputUri);
|
||||
} else {
|
||||
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_FILE);
|
||||
data.putString(KeychainIntentService.ENCRYPT_INPUT_FILE, mInputFilename);
|
||||
}
|
||||
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URI);
|
||||
data.putParcelable(KeychainIntentService.ENCRYPT_INPUT_URI, mInputUri);
|
||||
|
||||
if (mOutputUri != null) {
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URI);
|
||||
data.putParcelable(KeychainIntentService.ENCRYPT_OUTPUT_URI, mOutputUri);
|
||||
} else {
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_FILE);
|
||||
data.putString(KeychainIntentService.ENCRYPT_OUTPUT_FILE, mOutputFilename);
|
||||
}
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URI);
|
||||
data.putParcelable(KeychainIntentService.ENCRYPT_OUTPUT_URI, mOutputUri);
|
||||
|
||||
if (mEncryptInterface.isModeSymmetric()) {
|
||||
Log.d(Constants.TAG, "Symmetric encryption enabled!");
|
||||
@ -350,25 +295,16 @@ public class EncryptFileFragment extends Fragment {
|
||||
|
||||
if (mDeleteAfter.isChecked()) {
|
||||
// Create and show dialog to delete original file
|
||||
DeleteFileDialogFragment deleteFileDialog;
|
||||
if (mInputUri != null) {
|
||||
deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri);
|
||||
} else {
|
||||
deleteFileDialog = DeleteFileDialogFragment
|
||||
.newInstance(mInputFilename);
|
||||
}
|
||||
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri);
|
||||
deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
|
||||
setInputUri(null);
|
||||
}
|
||||
|
||||
if (mShareAfter.isChecked()) {
|
||||
// Share encrypted file
|
||||
Intent sendFileIntent = new Intent(Intent.ACTION_SEND);
|
||||
sendFileIntent.setType("*/*");
|
||||
if (mOutputUri != null) {
|
||||
sendFileIntent.putExtra(Intent.EXTRA_STREAM, mOutputUri);
|
||||
} else {
|
||||
sendFileIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(mOutputFilename));
|
||||
}
|
||||
sendFileIntent.putExtra(Intent.EXTRA_STREAM, mOutputUri);
|
||||
startActivity(Intent.createChooser(sendFileIntent,
|
||||
getString(R.string.title_share_file)));
|
||||
}
|
||||
@ -390,28 +326,17 @@ public class EncryptFileFragment extends Fragment {
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case RESULT_CODE_FILE: {
|
||||
case REQUEST_CODE_INPUT: {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
if (Constants.KITKAT) {
|
||||
mInputUri = data.getData();
|
||||
Cursor cursor = getActivity().getContentResolver().query(mInputUri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
|
||||
if (cursor != null) {
|
||||
if (cursor.moveToNext()) {
|
||||
mInputFilename = cursor.getString(0);
|
||||
mFilename.setText(mInputFilename);
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
String path = FileHelper.getPath(getActivity(), data.getData());
|
||||
Log.d(Constants.TAG, "path=" + path);
|
||||
|
||||
mFilename.setText(path);
|
||||
} catch (NullPointerException e) {
|
||||
Log.e(Constants.TAG, "Nullpointer while retrieving path!");
|
||||
}
|
||||
}
|
||||
setInputUri(data.getData());
|
||||
}
|
||||
return;
|
||||
}
|
||||
case REQUEST_CODE_OUTPUT: {
|
||||
// This happens after output file was selected, so start our operation
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
mOutputUri = data.getData();
|
||||
encryptStart();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ public class ImportKeysFileFragment extends Fragment {
|
||||
// open .asc or .gpg files
|
||||
// setting it to text/plain prevents Cyanogenmod's file manager from selecting asc
|
||||
// or gpg types!
|
||||
FileHelper.openFile(ImportKeysFileFragment.this, Constants.Path.APP_DIR + "/",
|
||||
FileHelper.openFile(ImportKeysFileFragment.this, Uri.fromFile(Constants.Path.APP_DIR),
|
||||
"*/*", REQUEST_CODE_FILE);
|
||||
}
|
||||
});
|
||||
|
@ -181,8 +181,8 @@ public class KeyListFragment extends LoaderFragment
|
||||
case R.id.menu_key_list_multi_export: {
|
||||
ids = mAdapter.getCurrentSelectedMasterKeyIds();
|
||||
ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity());
|
||||
mExportHelper.showExportKeysDialog(
|
||||
ids, Constants.Path.APP_DIR_FILE, mAdapter.isAnySecretSelected());
|
||||
mExportHelper.showExportKeysDialog(ids, Constants.Path.APP_DIR_FILE,
|
||||
mAdapter.isAnySecretSelected());
|
||||
break;
|
||||
}
|
||||
case R.id.menu_key_list_multi_select_all: {
|
||||
@ -205,7 +205,7 @@ public class KeyListFragment extends LoaderFragment
|
||||
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
|
||||
boolean checked) {
|
||||
if (checked) {
|
||||
mAdapter.setNewSelection(position, checked);
|
||||
mAdapter.setNewSelection(position, true);
|
||||
} else {
|
||||
mAdapter.removeSelection(position);
|
||||
}
|
||||
@ -452,7 +452,7 @@ public class KeyListFragment extends LoaderFragment
|
||||
ItemViewHolder holder = new ItemViewHolder();
|
||||
holder.mMainUserId = (TextView) view.findViewById(R.id.mainUserId);
|
||||
holder.mMainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
|
||||
holder.mStatusDivider = (View) view.findViewById(R.id.status_divider);
|
||||
holder.mStatusDivider = view.findViewById(R.id.status_divider);
|
||||
holder.mStatusLayout = (FrameLayout) view.findViewById(R.id.status_layout);
|
||||
holder.mButton = (ImageButton) view.findViewById(R.id.edit);
|
||||
holder.mRevoked = (TextView) view.findViewById(R.id.revoked);
|
||||
|
@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
@ -312,8 +311,7 @@ public class ViewKeyActivity extends ActionBarActivity implements
|
||||
|
||||
exportHelper.showExportKeysDialog(
|
||||
new long[]{(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)},
|
||||
Constants.Path.APP_DIR_FILE,
|
||||
((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) == 1)
|
||||
Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) == 1)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -18,40 +18,20 @@
|
||||
package org.sufficientlysecure.keychain.ui.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||
import org.sufficientlysecure.keychain.helper.FileHelper;
|
||||
|
||||
public class DeleteFileDialogFragment extends DialogFragment {
|
||||
private static final String ARG_DELETE_FILE = "delete_file";
|
||||
private static final String ARG_DELETE_URI = "delete_uri";
|
||||
|
||||
/**
|
||||
* Creates new instance of this delete file dialog fragment
|
||||
*/
|
||||
public static DeleteFileDialogFragment newInstance(String deleteFile) {
|
||||
DeleteFileDialogFragment frag = new DeleteFileDialogFragment();
|
||||
Bundle args = new Bundle();
|
||||
|
||||
args.putString(ARG_DELETE_FILE, deleteFile);
|
||||
|
||||
frag.setArguments(args);
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new instance of this delete file dialog fragment
|
||||
*/
|
||||
@ -74,14 +54,14 @@ public class DeleteFileDialogFragment extends DialogFragment {
|
||||
final FragmentActivity activity = getActivity();
|
||||
|
||||
final Uri deleteUri = getArguments().containsKey(ARG_DELETE_URI) ? getArguments().<Uri>getParcelable(ARG_DELETE_URI) : null;
|
||||
final String deleteFile = getArguments().getString(ARG_DELETE_FILE);
|
||||
String deleteFilename = FileHelper.getFilename(getActivity(), deleteUri);
|
||||
|
||||
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
|
||||
|
||||
|
||||
alert.setIcon(R.drawable.ic_dialog_alert_holo_light);
|
||||
alert.setTitle(R.string.warning);
|
||||
alert.setMessage(this.getString(R.string.file_delete_confirmation, deleteFile));
|
||||
alert.setMessage(this.getString(R.string.file_delete_confirmation, deleteFilename));
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
|
||||
@ -89,12 +69,14 @@ public class DeleteFileDialogFragment extends DialogFragment {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dismiss();
|
||||
|
||||
if (deleteUri != null) {
|
||||
if (Constants.KITKAT) {
|
||||
// We can not securely delete Documents, so just use usual delete on them
|
||||
DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri);
|
||||
return;
|
||||
if (DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri)) return;
|
||||
}
|
||||
|
||||
// TODO!!! We can't delete files from Uri without trying to find it's real path
|
||||
|
||||
/*
|
||||
// Send all information needed to service to edit key in other thread
|
||||
Intent intent = new Intent(activity, KeychainIntentService.class);
|
||||
|
||||
@ -102,7 +84,6 @@ public class DeleteFileDialogFragment extends DialogFragment {
|
||||
Bundle data = new Bundle();
|
||||
|
||||
intent.setAction(KeychainIntentService.ACTION_DELETE_FILE_SECURELY);
|
||||
data.putString(KeychainIntentService.DELETE_FILE, deleteFile);
|
||||
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||
|
||||
ProgressDialogFragment deletingDialog = ProgressDialogFragment.newInstance(
|
||||
@ -134,6 +115,7 @@ public class DeleteFileDialogFragment extends DialogFragment {
|
||||
|
||||
// start service with intent
|
||||
activity.startService(intent);
|
||||
*/
|
||||
}
|
||||
});
|
||||
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
|
@ -23,13 +23,11 @@ import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@ -39,11 +37,17 @@ import android.widget.TextView;
|
||||
|
||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
|
||||
import com.devspark.appmsg.AppMsg;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.FileHelper;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* This is a file chooser dialog no longer used with KitKat
|
||||
*/
|
||||
public class FileDialogFragment extends DialogFragment {
|
||||
private static final String ARG_MESSENGER = "messenger";
|
||||
private static final String ARG_TITLE = "title";
|
||||
@ -53,8 +57,7 @@ public class FileDialogFragment extends DialogFragment {
|
||||
|
||||
public static final int MESSAGE_OKAY = 1;
|
||||
|
||||
public static final String MESSAGE_DATA_URI = "uri";
|
||||
public static final String MESSAGE_DATA_FILENAME = "filename";
|
||||
public static final String MESSAGE_DATA_FILE = "file";
|
||||
public static final String MESSAGE_DATA_CHECKED = "checked";
|
||||
|
||||
private Messenger mMessenger;
|
||||
@ -64,8 +67,7 @@ public class FileDialogFragment extends DialogFragment {
|
||||
private CheckBox mCheckBox;
|
||||
private TextView mMessageTextView;
|
||||
|
||||
private String mOutputFilename;
|
||||
private Uri mOutputUri;
|
||||
private File mFile;
|
||||
|
||||
private static final int REQUEST_CODE = 0x00007004;
|
||||
|
||||
@ -73,14 +75,14 @@ public class FileDialogFragment extends DialogFragment {
|
||||
* Creates new instance of this file dialog fragment
|
||||
*/
|
||||
public static FileDialogFragment newInstance(Messenger messenger, String title, String message,
|
||||
String defaultFile, String checkboxText) {
|
||||
File defaultFile, String checkboxText) {
|
||||
FileDialogFragment frag = new FileDialogFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable(ARG_MESSENGER, messenger);
|
||||
|
||||
args.putString(ARG_TITLE, title);
|
||||
args.putString(ARG_MESSAGE, message);
|
||||
args.putString(ARG_DEFAULT_FILE, defaultFile);
|
||||
args.putString(ARG_DEFAULT_FILE, defaultFile.getAbsolutePath());
|
||||
args.putString(ARG_CHECKBOX_TEXT, checkboxText);
|
||||
|
||||
frag.setArguments(args);
|
||||
@ -99,7 +101,11 @@ public class FileDialogFragment extends DialogFragment {
|
||||
|
||||
String title = getArguments().getString(ARG_TITLE);
|
||||
String message = getArguments().getString(ARG_MESSAGE);
|
||||
mOutputFilename = getArguments().getString(ARG_DEFAULT_FILE);
|
||||
mFile = new File(getArguments().getString(ARG_DEFAULT_FILE));
|
||||
if (!mFile.isAbsolute()) {
|
||||
// We use OK dir by default
|
||||
mFile = new File(Constants.Path.APP_DIR.getAbsolutePath(), mFile.getName());
|
||||
}
|
||||
String checkboxText = getArguments().getString(ARG_CHECKBOX_TEXT);
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) activity
|
||||
@ -113,18 +119,14 @@ public class FileDialogFragment extends DialogFragment {
|
||||
mMessageTextView.setText(message);
|
||||
|
||||
mFilename = (EditText) view.findViewById(R.id.input);
|
||||
mFilename.setText(mOutputFilename);
|
||||
mFilename.setText(mFile.getName());
|
||||
mBrowse = (BootstrapButton) view.findViewById(R.id.btn_browse);
|
||||
mBrowse.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
// only .asc or .gpg files
|
||||
// setting it to text/plain prevents Cynaogenmod's file manager from selecting asc
|
||||
// or gpg types!
|
||||
if (Constants.KITKAT) {
|
||||
FileHelper.saveDocument(FileDialogFragment.this, mOutputUri, "*/*", REQUEST_CODE);
|
||||
} else {
|
||||
FileHelper.openFile(FileDialogFragment.this, mOutputFilename, "*/*", REQUEST_CODE);
|
||||
}
|
||||
FileHelper.openFile(FileDialogFragment.this, Uri.fromFile(mFile), "*/*", REQUEST_CODE);
|
||||
}
|
||||
});
|
||||
|
||||
@ -147,19 +149,23 @@ public class FileDialogFragment extends DialogFragment {
|
||||
dismiss();
|
||||
|
||||
String currentFilename = mFilename.getText().toString();
|
||||
if (mOutputFilename == null || !mOutputFilename.equals(currentFilename)) {
|
||||
mOutputUri = null;
|
||||
mOutputFilename = mFilename.getText().toString();
|
||||
if (currentFilename == null || currentFilename.isEmpty()) {
|
||||
// No file is like pressing cancel, UI: maybe disable positive button in this case?
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFile == null || currentFilename.startsWith("/")) {
|
||||
mFile = new File(currentFilename);
|
||||
} else if (!mFile.getName().equals(currentFilename)) {
|
||||
// We update our File object if user changed name!
|
||||
mFile = new File(mFile.getParentFile(), currentFilename);
|
||||
}
|
||||
|
||||
boolean checked = mCheckBox.isEnabled() && mCheckBox.isChecked();
|
||||
|
||||
// return resulting data back to activity
|
||||
Bundle data = new Bundle();
|
||||
if (mOutputUri != null) {
|
||||
data.putParcelable(MESSAGE_DATA_URI, mOutputUri);
|
||||
}
|
||||
data.putString(MESSAGE_DATA_FILENAME, mFilename.getText().toString());
|
||||
data.putString(MESSAGE_DATA_FILE, mFile.getAbsolutePath());
|
||||
data.putBoolean(MESSAGE_DATA_CHECKED, checked);
|
||||
|
||||
sendMessageToHandler(MESSAGE_OKAY, data);
|
||||
@ -176,44 +182,17 @@ public class FileDialogFragment extends DialogFragment {
|
||||
return alert.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates filename in dialog, normally called in onActivityResult in activity using the
|
||||
* FileDialog
|
||||
*/
|
||||
private void setFilename(String filename) {
|
||||
AlertDialog dialog = (AlertDialog) getDialog();
|
||||
EditText filenameEditText = (EditText) dialog.findViewById(R.id.input);
|
||||
|
||||
if (filenameEditText != null) {
|
||||
filenameEditText.setText(filename);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode & 0xFFFF) {
|
||||
case REQUEST_CODE: {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
if (Constants.KITKAT) {
|
||||
mOutputUri = data.getData();
|
||||
Cursor cursor = getActivity().getContentResolver().query(mOutputUri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
|
||||
if (cursor != null) {
|
||||
if (cursor.moveToNext()) {
|
||||
mOutputFilename = cursor.getString(0);
|
||||
mFilename.setText(mOutputFilename);
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
File file = new File(data.getData().getPath());
|
||||
if (file.getParentFile().exists()) {
|
||||
mFile = file;
|
||||
mFilename.setText(mFile.getName());
|
||||
} else {
|
||||
try {
|
||||
String path = data.getData().getPath();
|
||||
Log.d(Constants.TAG, "path=" + path);
|
||||
|
||||
// set filename used in export/import dialogs
|
||||
setFilename(path);
|
||||
} catch (NullPointerException e) {
|
||||
Log.e(Constants.TAG, "Nullpointer while retrieving path!", e);
|
||||
}
|
||||
AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,6 +195,7 @@
|
||||
<string name="wrong_passphrase">Wrong passphrase.</string>
|
||||
<string name="set_a_passphrase">Set a passphrase first.</string>
|
||||
<string name="no_filemanager_installed">No compatible file manager installed.</string>
|
||||
<string name="filemanager_no_write">The file manager does not support saving.</string>
|
||||
<string name="passphrases_do_not_match">The passphrases didn\'t match.</string>
|
||||
<string name="passphrase_must_not_be_empty">Please enter a passphrase.</string>
|
||||
<string name="passphrase_for_symmetric_encryption">Symmetric encryption.</string>
|
||||
|
Loading…
Reference in New Issue
Block a user