aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure
diff options
context:
space:
mode:
authorAdithya Abraham Philip <adithyaphilip@gmail.com>2015-06-30 22:12:16 +0530
committerAdithya Abraham Philip <adithyaphilip@gmail.com>2015-06-30 22:12:16 +0530
commita5257ec71d41532ac62594f59c10ba47d6a9ca38 (patch)
tree6771ba3e13df96574e093668c77e34678511b5f7 /OpenKeychain/src/main/java/org/sufficientlysecure
parent51d3daeccdc697d948c597931d804d738132b8ed (diff)
parent677afa90fce133b81c195488e07f07a5a83e2f0b (diff)
downloadopen-keychain-a5257ec71d41532ac62594f59c10ba47d6a9ca38.tar.gz
open-keychain-a5257ec71d41532ac62594f59c10ba47d6a9ca38.tar.bz2
open-keychain-a5257ec71d41532ac62594f59c10ba47d6a9ca38.zip
Merge branch 'master' of github.com:open-keychain/open-keychain
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java11
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/AppCompatPreferenceActivity.java127
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java15
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java73
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java63
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java13
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java81
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java154
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyBlankFragment.java90
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyImportFragment.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyWaitFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java24
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java51
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java34
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java252
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java2
22 files changed, 678 insertions, 351 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
index 8d43c0155..627623f47 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
@@ -33,6 +33,7 @@ import android.provider.ContactsContract;
import android.widget.Toast;
import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity;
@@ -101,7 +102,10 @@ public class KeychainApplication extends Application {
TemporaryStorageProvider.cleanUp(this);
- checkConsolidateRecovery();
+ if (!checkConsolidateRecovery()) {
+ // force DB upgrade, https://github.com/open-keychain/open-keychain/issues/1334
+ new KeychainDatabase(this).getReadableDatabase().close();
+ }
}
public static HashMap<String,Bitmap> qrCodeCache = new HashMap<>();
@@ -118,12 +122,15 @@ public class KeychainApplication extends Application {
/**
* Restart consolidate process if it has been interruped before
*/
- public void checkConsolidateRecovery() {
+ public boolean checkConsolidateRecovery() {
if (Preferences.getPreferences(this).getCachedConsolidate()) {
Intent consolidateIntent = new Intent(this, ConsolidateDialogActivity.class);
consolidateIntent.putExtra(ConsolidateDialogActivity.EXTRA_CONSOLIDATE_RECOVERY, true);
consolidateIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(consolidateIntent);
+ return true;
+ } else {
+ return false;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/AppCompatPreferenceActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/AppCompatPreferenceActivity.java
new file mode 100644
index 000000000..5200b8ced
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/AppCompatPreferenceActivity.java
@@ -0,0 +1,127 @@
+
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sufficientlysecure.keychain.compatibility;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.Nullable;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatDelegate;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
+ * to be used with AppCompat.
+ * <p/>
+ * This technique can be used with an {@link android.app.Activity} class, not just
+ * {@link android.preference.PreferenceActivity}.
+ */
+public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
+ private AppCompatDelegate mDelegate;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ getDelegate().installViewFactory();
+ getDelegate().onCreate(savedInstanceState);
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ getDelegate().onPostCreate(savedInstanceState);
+ }
+
+ public ActionBar getSupportActionBar() {
+ return getDelegate().getSupportActionBar();
+ }
+
+ public void setSupportActionBar(@Nullable Toolbar toolbar) {
+ getDelegate().setSupportActionBar(toolbar);
+ }
+
+ @Override
+ public MenuInflater getMenuInflater() {
+ return getDelegate().getMenuInflater();
+ }
+
+ @Override
+ public void setContentView(@LayoutRes int layoutResID) {
+ getDelegate().setContentView(layoutResID);
+ }
+
+ @Override
+ public void setContentView(View view) {
+ getDelegate().setContentView(view);
+ }
+
+ @Override
+ public void setContentView(View view, ViewGroup.LayoutParams params) {
+ getDelegate().setContentView(view, params);
+ }
+
+ @Override
+ public void addContentView(View view, ViewGroup.LayoutParams params) {
+ getDelegate().addContentView(view, params);
+ }
+
+ @Override
+ protected void onPostResume() {
+ super.onPostResume();
+ getDelegate().onPostResume();
+ }
+
+ @Override
+ protected void onTitleChanged(CharSequence title, int color) {
+ super.onTitleChanged(title, color);
+ getDelegate().setTitle(title);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ getDelegate().onConfigurationChanged(newConfig);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ getDelegate().onStop();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ getDelegate().onDestroy();
+ }
+
+ public void invalidateOptionsMenu() {
+ getDelegate().invalidateOptionsMenu();
+ }
+
+ private AppCompatDelegate getDelegate() {
+ if (mDelegate == null) {
+ mDelegate = AppCompatDelegate.create(this, null);
+ }
+ return mDelegate;
+ }
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java
index 0ac27833c..403e654e4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java
@@ -38,7 +38,7 @@ public class ClipboardReflection {
}
- public static CharSequence getClipboardText(Context context) {
+ public static String getClipboardText(Context context) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = clipboard.getPrimaryClip();
@@ -48,6 +48,10 @@ public class ClipboardReflection {
}
ClipData.Item item = clip.getItemAt(0);
- return item.coerceToText(context);
+ CharSequence seq = item.coerceToText(context);
+ if (seq != null) {
+ return seq.toString();
+ }
+ return null;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
index 6a85ce251..a6d260d22 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -70,7 +70,6 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.URLConnection;
import java.security.SignatureException;
import java.util.Date;
import java.util.Iterator;
@@ -676,8 +675,6 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
|| literalData.getFormat() == PGPLiteralData.UTF8) {
mimeType = "text/plain";
} else {
- // TODO: better would be: https://github.com/open-keychain/open-keychain/issues/753
-
// try to guess from file ending
String extension = MimeTypeMap.getFileExtensionFromUrl(originalFilename);
if (extension != null) {
@@ -685,10 +682,7 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
mimeType = mime.getMimeTypeFromExtension(extension);
}
if (mimeType == null) {
- mimeType = URLConnection.guessContentTypeFromName(originalFilename);
- }
- if (mimeType == null) {
- mimeType = "*/*";
+ mimeType = "application/octet-stream";
}
}
@@ -944,7 +938,14 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
log.add(LogType.MSG_DC_OK, indent);
+ OpenPgpMetadata metadata = new OpenPgpMetadata(
+ "",
+ "text/plain",
+ -1,
+ clearText.length);
+
DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log);
+ result.setDecryptMetadata(metadata);
result.setSignatureResult(signatureResultBuilder.build());
return result;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
index 1351e0cbc..3ed9b1da9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
@@ -520,7 +520,6 @@ public class KeychainProvider extends ContentProvider {
}
break;
-
}
case KEY_RINGS_PUBLIC:
@@ -607,23 +606,26 @@ public class KeychainProvider extends ContentProvider {
break;
}
- case API_APPS:
+ case API_APPS: {
qb.setTables(Tables.API_APPS);
break;
- case API_APPS_BY_PACKAGE_NAME:
+ }
+ case API_APPS_BY_PACKAGE_NAME: {
qb.setTables(Tables.API_APPS);
qb.appendWhere(ApiApps.PACKAGE_NAME + " = ");
qb.appendWhereEscapeString(uri.getLastPathSegment());
break;
- case API_ACCOUNTS:
+ }
+ case API_ACCOUNTS: {
qb.setTables(Tables.API_ACCOUNTS);
qb.appendWhere(Tables.API_ACCOUNTS + "." + ApiAccounts.PACKAGE_NAME + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
break;
- case API_ACCOUNTS_BY_ACCOUNT_NAME:
+ }
+ case API_ACCOUNTS_BY_ACCOUNT_NAME: {
qb.setTables(Tables.API_ACCOUNTS);
qb.appendWhere(Tables.API_ACCOUNTS + "." + ApiAccounts.PACKAGE_NAME + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
@@ -632,14 +634,17 @@ public class KeychainProvider extends ContentProvider {
qb.appendWhereEscapeString(uri.getLastPathSegment());
break;
- case API_ALLOWED_KEYS:
+ }
+ case API_ALLOWED_KEYS: {
qb.setTables(Tables.API_ALLOWED_KEYS);
qb.appendWhere(Tables.API_ALLOWED_KEYS + "." + ApiAccounts.PACKAGE_NAME + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
break;
- default:
+ }
+ default: {
throw new IllegalArgumentException("Unknown URI " + uri + " (" + match + ")");
+ }
}
@@ -684,47 +689,47 @@ public class KeychainProvider extends ContentProvider {
final int match = mUriMatcher.match(uri);
switch (match) {
- case KEY_RING_PUBLIC:
+ case KEY_RING_PUBLIC: {
db.insertOrThrow(Tables.KEY_RINGS_PUBLIC, null, values);
keyId = values.getAsLong(KeyRings.MASTER_KEY_ID);
break;
-
- case KEY_RING_SECRET:
+ }
+ case KEY_RING_SECRET: {
db.insertOrThrow(Tables.KEY_RINGS_SECRET, null, values);
keyId = values.getAsLong(KeyRings.MASTER_KEY_ID);
break;
-
- case KEY_RING_KEYS:
+ }
+ case KEY_RING_KEYS: {
db.insertOrThrow(Tables.KEYS, null, values);
keyId = values.getAsLong(Keys.MASTER_KEY_ID);
break;
-
- case KEY_RING_USER_IDS:
+ }
+ case KEY_RING_USER_IDS: {
// iff TYPE is null, user_id MUST be null as well
- if ( ! (values.get(UserPacketsColumns.TYPE) == null
+ if (!(values.get(UserPacketsColumns.TYPE) == null
? (values.get(UserPacketsColumns.USER_ID) != null && values.get(UserPacketsColumns.ATTRIBUTE_DATA) == null)
: (values.get(UserPacketsColumns.ATTRIBUTE_DATA) != null && values.get(UserPacketsColumns.USER_ID) == null)
- )) {
+ )) {
throw new AssertionError("Incorrect type for user packet! This is a bug!");
}
- if (((Number)values.get(UserPacketsColumns.RANK)).intValue() == 0 && values.get(UserPacketsColumns.USER_ID) == null) {
+ if (((Number) values.get(UserPacketsColumns.RANK)).intValue() == 0 && values.get(UserPacketsColumns.USER_ID) == null) {
throw new AssertionError("Rank 0 user packet must be a user id!");
}
db.insertOrThrow(Tables.USER_PACKETS, null, values);
keyId = values.getAsLong(UserPackets.MASTER_KEY_ID);
break;
-
- case KEY_RING_CERTS:
+ }
+ case KEY_RING_CERTS: {
// we replace here, keeping only the latest signature
// TODO this would be better handled in savePublicKeyRing directly!
db.replaceOrThrow(Tables.CERTS, null, values);
keyId = values.getAsLong(Certs.MASTER_KEY_ID);
break;
-
- case API_APPS:
+ }
+ case API_APPS: {
db.insertOrThrow(Tables.API_APPS, null, values);
break;
-
+ }
case API_ACCOUNTS: {
// set foreign key automatically based on given uri
// e.g., api_apps/com.example.app/accounts/
@@ -743,8 +748,9 @@ public class KeychainProvider extends ContentProvider {
db.insertOrThrow(Tables.API_ALLOWED_KEYS, null, values);
break;
}
- default:
+ default: {
throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
}
if (keyId != null) {
@@ -802,20 +808,24 @@ public class KeychainProvider extends ContentProvider {
break;
}
- case API_APPS_BY_PACKAGE_NAME:
+ case API_APPS_BY_PACKAGE_NAME: {
count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, additionalSelection),
selectionArgs);
break;
- case API_ACCOUNTS_BY_ACCOUNT_NAME:
+ }
+ case API_ACCOUNTS_BY_ACCOUNT_NAME: {
count = db.delete(Tables.API_ACCOUNTS, buildDefaultApiAccountsSelection(uri, additionalSelection),
selectionArgs);
break;
- case API_ALLOWED_KEYS:
+ }
+ case API_ALLOWED_KEYS: {
count = db.delete(Tables.API_ALLOWED_KEYS, buildDefaultApiAllowedKeysSelection(uri, additionalSelection),
selectionArgs);
break;
- default:
+ }
+ default: {
throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
}
// notify of changes in db
@@ -851,16 +861,19 @@ public class KeychainProvider extends ContentProvider {
count = db.update(Tables.KEYS, values, actualSelection, selectionArgs);
break;
}
- case API_APPS_BY_PACKAGE_NAME:
+ case API_APPS_BY_PACKAGE_NAME: {
count = db.update(Tables.API_APPS, values,
buildDefaultApiAppsSelection(uri, selection), selectionArgs);
break;
- case API_ACCOUNTS_BY_ACCOUNT_NAME:
+ }
+ case API_ACCOUNTS_BY_ACCOUNT_NAME: {
count = db.update(Tables.API_ACCOUNTS, values,
buildDefaultApiAccountsSelection(uri, selection), selectionArgs);
break;
- default:
+ }
+ default: {
throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
}
// notify of changes in db
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java
index b1f1a7d9e..7e9b24989 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java
@@ -19,23 +19,15 @@
package org.sufficientlysecure.keychain.provider;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.UUID;
-
import android.content.ClipDescription;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
-import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
-import android.os.Bundle;
-import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.provider.OpenableColumns;
@@ -43,6 +35,30 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.DatabaseUtil;
import org.sufficientlysecure.keychain.util.Log;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.UUID;
+
+/**
+ * TemporaryStorageProvider stores decrypted files inside the app's cache directory previously to
+ * sharing them with other applications.
+ *
+ * Security:
+ * - It is writable by OpenKeychain only (see Manifest), but exported for reading files
+ * - It uses UUIDs as identifiers which makes predicting files from outside impossible
+ * - Querying a number of files is not allowed, only querying single files
+ * -> You can only open a file if you know the Uri containing the precise UUID, this Uri is only
+ * revealed when the user shares a decrypted file with another app.
+ *
+ * Why is support lib's FileProvider not used?
+ * Because granting Uri permissions temporarily does not work correctly. See
+ * - https://code.google.com/p/android/issues/detail?id=76683
+ * - https://github.com/nmr8acme/FileProvider-permission-bug
+ * - http://stackoverflow.com/q/24467696
+ * - http://stackoverflow.com/q/18249007
+ * - Comments at http://www.blogc.at/2014/03/23/share-private-files-with-other-apps-fileprovider/
+ */
public class TemporaryStorageProvider extends ContentProvider {
private static final String DB_NAME = "tempstorage.db";
@@ -143,6 +159,10 @@ public class TemporaryStorageProvider extends ContentProvider {
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+ if (uri.getLastPathSegment() == null) {
+ throw new SecurityException("Listing temporary files is not allowed, only querying single files.");
+ }
+
File file;
try {
file = getFile(uri);
@@ -153,9 +173,15 @@ public class TemporaryStorageProvider extends ContentProvider {
new String[]{uri.getLastPathSegment()}, null, null, null);
if (fileName != null) {
if (fileName.moveToNext()) {
- MatrixCursor cursor =
- new MatrixCursor(new String[]{OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE, "_data"});
- cursor.newRow().add(fileName.getString(0)).add(file.length()).add(file.getAbsolutePath());
+ MatrixCursor cursor = new MatrixCursor(new String[]{
+ OpenableColumns.DISPLAY_NAME,
+ OpenableColumns.SIZE,
+ "_data"
+ });
+ cursor.newRow()
+ .add(fileName.getString(0))
+ .add(file.length())
+ .add(file.getAbsolutePath());
fileName.close();
return cursor;
}
@@ -167,8 +193,8 @@ public class TemporaryStorageProvider extends ContentProvider {
@Override
public String getType(Uri uri) {
Cursor cursor = db.getReadableDatabase().query(TABLE_FILES,
- new String[]{ COLUMN_TYPE }, COLUMN_ID + "=?",
- new String[]{ uri.getLastPathSegment() }, null, null, null);
+ new String[]{COLUMN_TYPE}, COLUMN_ID + "=?",
+ new String[]{uri.getLastPathSegment()}, null, null, null);
if (cursor != null) {
try {
if (cursor.moveToNext()) {
@@ -180,14 +206,14 @@ public class TemporaryStorageProvider extends ContentProvider {
cursor.close();
}
}
- return "*/*";
+ return "application/octet-stream";
}
@Override
public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
String type = getType(uri);
if (ClipDescription.compareMimeTypes(type, mimeTypeFilter)) {
- return new String[] { type };
+ return new String[]{type};
}
return null;
}
@@ -200,9 +226,14 @@ public class TemporaryStorageProvider extends ContentProvider {
String uuid = UUID.randomUUID().toString();
values.put(COLUMN_ID, uuid);
int insert = (int) db.getWritableDatabase().insert(TABLE_FILES, null, values);
+ if (insert == -1) {
+ Log.e(Constants.TAG, "Insert failed!");
+ return null;
+ }
try {
getFile(uuid).createNewFile();
} catch (IOException e) {
+ Log.e(Constants.TAG, "File creation failed!");
return null;
}
return Uri.withAppendedPath(BASE_URI, uuid);
@@ -238,7 +269,7 @@ public class TemporaryStorageProvider extends ContentProvider {
throw new UnsupportedOperationException("Update supported only for plain uri!");
}
return db.getWritableDatabase().update(TABLE_FILES, values,
- COLUMN_ID + " = ?", new String[]{ uri.getLastPathSegment() });
+ COLUMN_ID + " = ?", new String[]{uri.getLastPathSegment()});
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
index 0d2d3256d..ac66bd097 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -167,7 +167,7 @@ public class OpenPgpService extends RemoteService {
Intent data, RequiredInputParcel requiredInput) {
switch (requiredInput.mType) {
- case NFC_KEYTOCARD:
+ case NFC_MOVE_KEY_TO_CARD:
case NFC_DECRYPT:
case NFC_SIGN: {
// build PendingIntent for YubiKey NFC operations
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
index a0b470add..7c0b7eaef 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -459,11 +459,16 @@ public class PassphraseCacheService extends Service {
* Called when one specific passphrase for keyId timed out
*/
private void timeout(long keyId) {
+
CachedPassphrase cPass = mPassphraseCache.get(keyId);
- // clean internal char[] from memory!
- cPass.getPassphrase().removeFromMemory();
- // remove passphrase object
- mPassphraseCache.remove(keyId);
+ if (cPass != null) {
+ if (cPass.getPassphrase() != null) {
+ // clean internal char[] from memory!
+ cPass.getPassphrase().removeFromMemory();
+ }
+ // remove passphrase object
+ mPassphraseCache.remove(keyId);
+ }
Log.d(Constants.TAG, "PassphraseCacheService Timeout of keyId " + keyId + ", removed from memory!");
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
index 930c2ee4f..efe844145 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
@@ -12,7 +12,7 @@ import android.os.Parcelable;
public class RequiredInputParcel implements Parcelable {
public enum RequiredInputType {
- PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_KEYTOCARD
+ PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_MOVE_KEY_TO_CARD
}
public Date mSignatureTime;
@@ -226,7 +226,7 @@ public class RequiredInputParcel implements Parcelable {
ByteBuffer buf = ByteBuffer.wrap(mSubkeysToExport.get(0));
// We need to pass in a subkey here...
- return new RequiredInputParcel(RequiredInputType.NFC_KEYTOCARD,
+ return new RequiredInputParcel(RequiredInputType.NFC_MOVE_KEY_TO_CARD,
inputHashes, null, null, mMasterKeyId, buf.getLong());
}
@@ -241,7 +241,7 @@ public class RequiredInputParcel implements Parcelable {
if (!mMasterKeyId.equals(input.mMasterKeyId)) {
throw new AssertionError("Master keys must match, this is a programming error!");
}
- if (input.mType != RequiredInputType.NFC_KEYTOCARD) {
+ if (input.mType != RequiredInputType.NFC_MOVE_KEY_TO_CARD) {
throw new AssertionError("Operation types must match, this is a programming error!");
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
index 68a809b69..505638c7c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
@@ -17,9 +17,8 @@
package org.sufficientlysecure.keychain.ui;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
import android.content.Intent;
+import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
@@ -64,6 +63,23 @@ public class CreateKeyActivity extends BaseNfcActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ // React on NDEF_DISCOVERED from Manifest
+ // NOTE: ACTION_NDEF_DISCOVERED and not ACTION_TAG_DISCOVERED like in BaseNfcActivity
+ if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
+ try {
+ handleTagDiscoveredIntent(getIntent());
+ } catch (CardException e) {
+ handleNfcError(e);
+ } catch (IOException e) {
+ handleNfcError(e);
+ }
+
+ setTitle(R.string.title_manage_my_keys);
+
+ // done
+ return;
+ }
+
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
@@ -89,17 +105,25 @@ public class CreateKeyActivity extends BaseNfcActivity {
String nfcUserId = intent.getStringExtra(EXTRA_NFC_USER_ID);
byte[] nfcAid = intent.getByteArrayExtra(EXTRA_NFC_AID);
- Fragment frag2 = CreateKeyYubiKeyImportFragment.createInstance(
- nfcFingerprints, nfcAid, nfcUserId);
- loadFragment(frag2, FragAction.START);
+ if (containsKeys(nfcFingerprints)) {
+ Fragment frag = CreateKeyYubiKeyImportFragment.newInstance(
+ nfcFingerprints, nfcAid, nfcUserId);
+ loadFragment(frag, FragAction.START);
+
+ setTitle(R.string.title_import_keys);
+ } else {
+ Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance();
+ loadFragment(frag, FragAction.START);
+ setTitle(R.string.title_manage_my_keys);
+ }
- setTitle(R.string.title_import_keys);
+ // done
return;
- } else {
- CreateKeyStartFragment frag = CreateKeyStartFragment.newInstance();
- loadFragment(frag, FragAction.START);
}
+ // normal key creation
+ CreateKeyStartFragment frag = CreateKeyStartFragment.newInstance();
+ loadFragment(frag, FragAction.START);
}
if (mFirstTime) {
@@ -122,16 +146,7 @@ public class CreateKeyActivity extends BaseNfcActivity {
byte[] nfcAid = nfcGetAid();
String userId = nfcGetUserId();
- // If all fingerprint bytes are 0, the card contains no keys.
- boolean cardContainsKeys = false;
- for (byte b : scannedFingerprints) {
- if (b != 0) {
- cardContainsKeys = true;
- break;
- }
- }
-
- if (cardContainsKeys) {
+ if (containsKeys(scannedFingerprints)) {
try {
long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(scannedFingerprints);
CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId);
@@ -146,25 +161,29 @@ public class CreateKeyActivity extends BaseNfcActivity {
finish();
} catch (PgpKeyNotFoundException e) {
- Fragment frag = CreateKeyYubiKeyImportFragment.createInstance(
+ Fragment frag = CreateKeyYubiKeyImportFragment.newInstance(
scannedFingerprints, nfcAid, userId);
loadFragment(frag, FragAction.TO_RIGHT);
}
} else {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.first_time_blank_smartcard_title)
- .setMessage(R.string.first_time_blank_smartcard_message)
- .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int button) {
- CreateKeyActivity.this.mUseSmartCardSettings = true;
- }
- })
- .setNegativeButton(android.R.string.no, null).show();
+ Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance();
+ loadFragment(frag, FragAction.TO_RIGHT);
}
}
+ private boolean containsKeys(byte[] scannedFingerprints) {
+ // If all fingerprint bytes are 0, the card contains no keys.
+ boolean cardContainsKeys = false;
+ for (byte b : scannedFingerprints) {
+ if (b != 0) {
+ cardContainsKeys = true;
+ break;
+ }
+ }
+ return cardContainsKeys;
+ }
+
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@@ -182,7 +201,7 @@ public class CreateKeyActivity extends BaseNfcActivity {
setContentView(R.layout.create_key_activity);
}
- public static enum FragAction {
+ public enum FragAction {
START,
TO_RIGHT,
TO_LEFT
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
index c420e5af9..52083a552 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
@@ -18,9 +18,13 @@
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.Message;
+import android.os.Messenger;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -28,25 +32,32 @@ import android.widget.CheckBox;
import android.widget.TextView;
import org.spongycastle.bcpg.sig.KeyFlags;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.ExportResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.KeyRing;
+import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
+import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
+import org.sufficientlysecure.keychain.service.KeychainService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
+import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
+import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Preferences;
import java.util.Iterator;
-public class CreateKeyFinalFragment
- extends CryptoOperationFragment<SaveKeyringParcel, EditKeyResult> {
+public class CreateKeyFinalFragment extends CryptoOperationFragment<SaveKeyringParcel, OperationResult> {
public static final int REQUEST_EDIT_KEY = 0x00008007;
@@ -61,6 +72,7 @@ public class CreateKeyFinalFragment
SaveKeyringParcel mSaveKeyringParcel;
private CryptoOperationHelper<ExportKeyringParcel, ExportResult> mUploadOpHelper;
+ private CryptoOperationHelper<SaveKeyringParcel, EditKeyResult> mCreateOpHelper;
public static CreateKeyFinalFragment newInstance() {
CreateKeyFinalFragment frag = new CreateKeyFinalFragment();
@@ -128,14 +140,16 @@ public class CreateKeyFinalFragment
}
});
+ // If this is a debug build, don't upload by default
+ if (Constants.DEBUG) {
+ mUploadCheckbox.setChecked(false);
+ }
+
return view;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (mUploadOpHelper != null) {
- mUploadOpHelper.handleActivityResult(requestCode, resultCode, data);
- }
switch (requestCode) {
case REQUEST_EDIT_KEY: {
if (resultCode == Activity.RESULT_OK) {
@@ -151,30 +165,6 @@ public class CreateKeyFinalFragment
}
@Override
- public SaveKeyringParcel createOperationInput() {
- return mSaveKeyringParcel;
- }
-
- @Override
- public void onCryptoOperationSuccess(EditKeyResult result) {
- if (result.mMasterKeyId != null && mUploadCheckbox.isChecked()) {
- // result will be displayed after upload
- uploadKey(result);
- } else {
- Intent data = new Intent();
- data.putExtra(OperationResult.EXTRA_RESULT, result);
- getActivity().setResult(Activity.RESULT_OK, data);
- getActivity().finish();
- }
- }
-
- @Override
- protected void onCryptoOperationResult(EditKeyResult result) {
- // do something else?
- super.onCryptoOperationResult(result);
- }
-
- @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -190,6 +180,7 @@ public class CreateKeyFinalFragment
mSaveKeyringParcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Algorithm.RSA,
2048, null, KeyFlags.AUTHENTICATION, 0L));
mEditText.setText(R.string.create_key_custom);
+ mEditButton.setEnabled(false);
} else {
mSaveKeyringParcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Algorithm.RSA,
4096, null, KeyFlags.CERTIFY_OTHER, 0L));
@@ -218,15 +209,112 @@ public class CreateKeyFinalFragment
}
}
-
private void createKey() {
- super.setProgressMessageResource(R.string.progress_building_key);
- super.cryptoOperation();
+ final CreateKeyActivity createKeyActivity = (CreateKeyActivity) getActivity();
+
+ CryptoOperationHelper.Callback<SaveKeyringParcel, EditKeyResult> createKeyCallback
+ = new CryptoOperationHelper.Callback<SaveKeyringParcel, EditKeyResult>() {
+ @Override
+ public SaveKeyringParcel createOperationInput() {
+ return mSaveKeyringParcel;
+ }
+
+ @Override
+ public void onCryptoOperationSuccess(EditKeyResult result) {
+
+ if (createKeyActivity.mUseSmartCardSettings) {
+ // save key id in between
+ mSaveKeyringParcel.mMasterKeyId = result.mMasterKeyId;
+ // calls cryptoOperation corresponding to moveToCard
+ cryptoOperation(new CryptoInputParcel());
+ return;
+ }
+
+ if (result.mMasterKeyId != null && mUploadCheckbox.isChecked()) {
+ // result will be displayed after upload
+ uploadKey(result);
+ return;
+ }
+
+ Intent data = new Intent();
+ data.putExtra(OperationResult.EXTRA_RESULT, result);
+ getActivity().setResult(Activity.RESULT_OK, data);
+ getActivity().finish();
+ }
+
+ @Override
+ public void onCryptoOperationCancelled() {
+
+ }
+
+ @Override
+ public void onCryptoOperationError(EditKeyResult result) {
+ result.createNotify(getActivity()).show();
+ }
+
+ @Override
+ public boolean onCryptoSetProgress(String msg, int progress, int max) {
+ return false;
+ }
+ };
+
+ mCreateOpHelper = new CryptoOperationHelper<>(this, createKeyCallback,
+ R.string.progress_building_key);
+
+ mCreateOpHelper.cryptoOperation();
+ }
+
+ // currently only used for moveToCard
+ @Override
+ public SaveKeyringParcel createOperationInput() {
+ CachedPublicKeyRing key = (new ProviderHelper(getActivity()))
+ .getCachedPublicKeyRing(mSaveKeyringParcel.mMasterKeyId);
+
+ // overwrite mSaveKeyringParcel!
+ try {
+ mSaveKeyringParcel = new SaveKeyringParcel(key.getMasterKeyId(), key.getFingerprint());
+ } catch (PgpKeyNotFoundException e) {
+ Log.e(Constants.TAG, "Key that should be moved to YubiKey not found in database!");
+ return null;
+ }
+
+ Cursor cursor = getActivity().getContentResolver().query(
+ KeychainContract.Keys.buildKeysUri(mSaveKeyringParcel.mMasterKeyId),
+ new String[]{KeychainContract.Keys.KEY_ID,}, null, null, null
+ );
+ try {
+ while (cursor != null && cursor.moveToNext()) {
+ long subkeyId = cursor.getLong(0);
+ mSaveKeyringParcel.getOrCreateSubkeyChange(subkeyId).mMoveKeyToCard = true;
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ return mSaveKeyringParcel;
+ }
+
+ // currently only used for moveToCard
+ @Override
+ public void onCryptoOperationSuccess(OperationResult result) {
+ EditKeyResult editResult = (EditKeyResult) result;
+
+ if (editResult.mMasterKeyId != null && mUploadCheckbox.isChecked()) {
+ // result will be displayed after upload
+ uploadKey(editResult);
+ return;
+ }
+
+ Intent data = new Intent();
+ data.putExtra(OperationResult.EXTRA_RESULT, result);
+ getActivity().setResult(Activity.RESULT_OK, data);
+ getActivity().finish();
}
// TODO move into EditKeyOperation
private void uploadKey(final EditKeyResult saveKeyResult) {
-
// set data uri as path to keyring
final Uri blobUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(
saveKeyResult.mMasterKeyId);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyBlankFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyBlankFragment.java
new file mode 100644
index 000000000..6df340636
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyBlankFragment.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
+
+public class CreateKeyYubiKeyBlankFragment extends Fragment {
+
+ CreateKeyActivity mCreateKeyActivity;
+ View mBackButton;
+ View mNextButton;
+
+ /**
+ * Creates new instance of this fragment
+ */
+ public static CreateKeyYubiKeyBlankFragment newInstance() {
+ CreateKeyYubiKeyBlankFragment frag = new CreateKeyYubiKeyBlankFragment();
+
+ Bundle args = new Bundle();
+
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.create_yubi_key_blank_fragment, container, false);
+
+ mBackButton = view.findViewById(R.id.create_key_back_button);
+ mNextButton = view.findViewById(R.id.create_key_next_button);
+
+ mBackButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (getFragmentManager().getBackStackEntryCount() == 0) {
+ getActivity().setResult(Activity.RESULT_CANCELED);
+ getActivity().finish();
+ } else {
+ mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
+ }
+ }
+ });
+ mNextButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ nextClicked();
+ }
+ });
+
+ return view;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mCreateKeyActivity = (CreateKeyActivity) getActivity();
+ }
+
+ private void nextClicked() {
+ mCreateKeyActivity.mUseSmartCardSettings = true;
+
+ CreateKeyNameFragment frag = CreateKeyNameFragment.newInstance();
+ mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyImportFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyImportFragment.java
index 7997d8025..8de874ec5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyImportFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyImportFragment.java
@@ -66,7 +66,7 @@ public class CreateKeyYubiKeyImportFragment
private String mKeyserver;
private ArrayList<ParcelableKeyRing> mKeyList;
- public static Fragment createInstance(byte[] scannedFingerprints, byte[] nfcAid, String userId) {
+ public static Fragment newInstance(byte[] scannedFingerprints, byte[] nfcAid, String userId) {
CreateKeyYubiKeyImportFragment frag = new CreateKeyYubiKeyImportFragment();
@@ -97,7 +97,7 @@ public class CreateKeyYubiKeyImportFragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.create_yubikey_import_fragment, container, false);
+ View view = inflater.inflate(R.layout.create_yubi_key_import_fragment, container, false);
vSerNo = (TextView) view.findViewById(R.id.yubikey_serno);
vUserId = (TextView) view.findViewById(R.id.yubikey_userid);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyWaitFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyWaitFragment.java
index 0b8586c0a..0e2dd2531 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyWaitFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyWaitFragment.java
@@ -35,7 +35,7 @@ public class CreateKeyYubiKeyWaitFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.create_yubikey_wait_fragment, container, false);
+ View view = inflater.inflate(R.layout.create_yubi_key_wait_fragment, container, false);
mBackButton = view.findViewById(R.id.create_key_back_button);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
index 4375be740..04f54f151 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
@@ -120,7 +120,14 @@ public class DecryptActivity extends BaseActivity {
case ACTION_DECRYPT_FROM_CLIPBOARD: {
ClipboardManager clipMan = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
+ if (clipMan == null) {
+ break;
+ }
+
ClipData clip = clipMan.getPrimaryClip();
+ if (clip == null) {
+ break;
+ }
// check if data is available as uri
Uri uri = null;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java
index 590d02c6f..779b22535 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java
@@ -29,6 +29,7 @@ import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -37,6 +38,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker;
import org.sufficientlysecure.keychain.util.FileHelper;
@@ -92,15 +94,31 @@ public class EncryptDecryptOverviewFragment extends Fragment {
mDecryptFromClipboard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- Intent clipboardDecrypt = new Intent(getActivity(), DecryptActivity.class);
- clipboardDecrypt.setAction(DecryptActivity.ACTION_DECRYPT_FROM_CLIPBOARD);
- startActivityForResult(clipboardDecrypt, 0);
+ decryptFromClipboard();
}
});
return view;
}
+ private void decryptFromClipboard() {
+
+ Activity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+
+ final CharSequence clipboardText = ClipboardReflection.getClipboardText(activity);
+ if (clipboardText == null || TextUtils.isEmpty(clipboardText)) {
+ Notify.create(activity, R.string.error_clipboard_empty, Style.ERROR).show();
+ return;
+ }
+
+ Intent clipboardDecrypt = new Intent(getActivity(), DecryptActivity.class);
+ clipboardDecrypt.setAction(DecryptActivity.ACTION_DECRYPT_FROM_CLIPBOARD);
+ startActivityForResult(clipboardDecrypt, 0);
+ }
+
@Override
public void onResume() {
super.onResume();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java
index c5fc9abe0..addfb6a23 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java
@@ -63,7 +63,7 @@ public class NfcOperationActivity extends BaseNfcActivity {
mServiceIntent = data.getParcelable(EXTRA_SERVICE_INTENT);
// obtain passphrase for this subkey
- if (mRequiredInput.mType != RequiredInputParcel.RequiredInputType.NFC_KEYTOCARD) {
+ if (mRequiredInput.mType != RequiredInputParcel.RequiredInputType.NFC_MOVE_KEY_TO_CARD) {
obtainYubiKeyPin(mRequiredInput);
}
}
@@ -96,7 +96,7 @@ public class NfcOperationActivity extends BaseNfcActivity {
}
break;
}
- case NFC_KEYTOCARD: {
+ case NFC_MOVE_KEY_TO_CARD: {
ProviderHelper providerHelper = new ProviderHelper(this);
CanonicalizedSecretKeyRing secretKeyRing;
try {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
index 442bdf8f7..a552e1c55 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
*
* This program is free software: you can redistribute it and/or modify
@@ -17,14 +18,11 @@
package org.sufficientlysecure.keychain.ui;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
-import android.os.Build;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
-import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
import android.support.v7.widget.Toolbar;
@@ -32,15 +30,15 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
-import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.compatibility.AppCompatPreferenceActivity;
import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference;
import org.sufficientlysecure.keychain.util.Preferences;
import java.util.List;
-public class SettingsActivity extends PreferenceActivity {
+public class SettingsActivity extends AppCompatPreferenceActivity {
public static final String ACTION_PREFS_CLOUD = "org.sufficientlysecure.keychain.ui.PREFS_CLOUD";
public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV";
@@ -91,22 +89,6 @@ public class SettingsActivity extends PreferenceActivity {
initializePassphraseCacheTtl(
(IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL));
- int[] valueIds = new int[]{
- CompressionAlgorithmTags.UNCOMPRESSED,
- CompressionAlgorithmTags.ZIP,
- CompressionAlgorithmTags.ZLIB,
- CompressionAlgorithmTags.BZIP2,
- };
- String[] entries = new String[]{
- getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")",
- "ZIP (" + getString(R.string.compression_fast) + ")",
- "ZLIB (" + getString(R.string.compression_fast) + ")",
- "BZIP2 (" + getString(R.string.compression_very_slow) + ")",};
- String[] values = new String[valueIds.length];
- for (int i = 0; i < values.length; ++i) {
- values[i] = "" + valueIds[i];
- }
-
initializeUseDefaultYubiKeyPin(
(CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN));
@@ -122,13 +104,14 @@ public class SettingsActivity extends PreferenceActivity {
private void setupToolbar() {
ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
LinearLayout content = (LinearLayout) root.getChildAt(0);
- LinearLayout toolbarContainer = (LinearLayout) View.inflate(this, R.layout.preference_toolbar_activity, null);
+ LinearLayout toolbarContainer = (LinearLayout) View.inflate(this, R.layout.preference_toolbar, null);
root.removeAllViews();
toolbarContainer.addView(content);
root.addView(toolbarContainer);
Toolbar toolbar = (Toolbar) toolbarContainer.findViewById(R.id.toolbar);
+
toolbar.setTitle(R.string.title_preferences);
toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24dp));
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@@ -168,7 +151,7 @@ public class SettingsActivity extends PreferenceActivity {
}
/**
- * This fragment shows the Cloud Search preferences in android 3.0+
+ * This fragment shows the Cloud Search preferences
*/
public static class CloudSearchPrefsFragment extends PreferenceFragment {
@@ -226,7 +209,7 @@ public class SettingsActivity extends PreferenceActivity {
}
/**
- * This fragment shows the advanced preferences in android 3.0+
+ * This fragment shows the PIN/password preferences
*/
public static class AdvancedPrefsFragment extends PreferenceFragment {
@@ -243,25 +226,6 @@ public class SettingsActivity extends PreferenceActivity {
initializePassphraseCacheTtl(
(IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL));
- int[] valueIds = new int[]{
- CompressionAlgorithmTags.UNCOMPRESSED,
- CompressionAlgorithmTags.ZIP,
- CompressionAlgorithmTags.ZLIB,
- CompressionAlgorithmTags.BZIP2,
- };
-
- String[] entries = new String[]{
- getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")",
- "ZIP (" + getString(R.string.compression_fast) + ")",
- "ZLIB (" + getString(R.string.compression_fast) + ")",
- "BZIP2 (" + getString(R.string.compression_very_slow) + ")",
- };
-
- String[] values = new String[valueIds.length];
- for (int i = 0; i < values.length; ++i) {
- values[i] = "" + valueIds[i];
- }
-
initializeUseDefaultYubiKeyPin(
(CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN));
@@ -270,7 +234,6 @@ public class SettingsActivity extends PreferenceActivity {
}
}
- @TargetApi(Build.VERSION_CODES.KITKAT)
protected boolean isValidFragment(String fragmentName) {
return AdvancedPrefsFragment.class.getName().equals(fragmentName)
|| CloudSearchPrefsFragment.class.getName().equals(fragmentName)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java
index 9e8a12c8a..6669f2654 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java
@@ -53,13 +53,15 @@ public class ViewKeyAdvActivity extends BaseActivity implements
protected Uri mDataUri;
public static final String EXTRA_SELECTED_TAB = "selected_tab";
- public static final int TAB_MAIN = 0;
- public static final int TAB_SHARE = 1;
+ public static final int TAB_SHARE = 0;
+ public static final int TAB_IDENTITIES = 1;
+ public static final int TAB_SUBKEYS = 2;
+ public static final int TAB_CERTS = 3;
+ public static final int TAB_KEYBASE = 4;
// view
private ViewPager mViewPager;
private PagerSlidingTabStrip mSlidingTabLayout;
- private PagerTabStripAdapter mTabsAdapter;
private static final int LOADER_ID_UNIFIED = 0;
@@ -80,11 +82,8 @@ public class ViewKeyAdvActivity extends BaseActivity implements
mViewPager = (ViewPager) findViewById(R.id.pager);
mSlidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.sliding_tab_layout);
- int switchToTab = TAB_MAIN;
Intent intent = getIntent();
- if (intent.getExtras() != null && intent.getExtras().containsKey(EXTRA_SELECTED_TAB)) {
- switchToTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB);
- }
+ int switchToTab = intent.getIntExtra(EXTRA_SELECTED_TAB, TAB_SHARE);
mDataUri = getIntent().getData();
if (mDataUri == null) {
@@ -102,8 +101,6 @@ public class ViewKeyAdvActivity extends BaseActivity implements
}
}
- Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
-
// Prepare the loaders. Either re-connect with an existing ones,
// or start new ones.
getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
@@ -120,32 +117,32 @@ public class ViewKeyAdvActivity extends BaseActivity implements
}
private void initTabs(Uri dataUri) {
- mTabsAdapter = new PagerTabStripAdapter(this);
- mViewPager.setAdapter(mTabsAdapter);
+ PagerTabStripAdapter adapter = new PagerTabStripAdapter(this);
+ mViewPager.setAdapter(adapter);
Bundle shareBundle = new Bundle();
shareBundle.putParcelable(ViewKeyAdvUserIdsFragment.ARG_DATA_URI, dataUri);
- mTabsAdapter.addTab(ViewKeyAdvShareFragment.class,
+ adapter.addTab(ViewKeyAdvShareFragment.class,
shareBundle, getString(R.string.key_view_tab_share));
Bundle userIdsBundle = new Bundle();
userIdsBundle.putParcelable(ViewKeyAdvUserIdsFragment.ARG_DATA_URI, dataUri);
- mTabsAdapter.addTab(ViewKeyAdvUserIdsFragment.class,
+ adapter.addTab(ViewKeyAdvUserIdsFragment.class,
userIdsBundle, getString(R.string.section_user_ids));
Bundle keysBundle = new Bundle();
keysBundle.putParcelable(ViewKeyAdvSubkeysFragment.ARG_DATA_URI, dataUri);
- mTabsAdapter.addTab(ViewKeyAdvSubkeysFragment.class,
+ adapter.addTab(ViewKeyAdvSubkeysFragment.class,
keysBundle, getString(R.string.key_view_tab_keys));
Bundle certsBundle = new Bundle();
certsBundle.putParcelable(ViewKeyAdvCertsFragment.ARG_DATA_URI, dataUri);
- mTabsAdapter.addTab(ViewKeyAdvCertsFragment.class,
+ adapter.addTab(ViewKeyAdvCertsFragment.class,
certsBundle, getString(R.string.key_view_tab_certs));
Bundle trustBundle = new Bundle();
trustBundle.putParcelable(ViewKeyTrustFragment.ARG_DATA_URI, dataUri);
- mTabsAdapter.addTab(ViewKeyTrustFragment.class,
+ adapter.addTab(ViewKeyTrustFragment.class,
trustBundle, getString(R.string.key_view_tab_keybase));
// update layout after operations
@@ -185,11 +182,8 @@ public class ViewKeyAdvActivity extends BaseActivity implements
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- /* TODO better error handling? May cause problems when a key is deleted,
- * because the notification triggers faster than the activity closes.
- */
// Avoid NullPointerExceptions...
- if (data.getCount() == 0) {
+ if (data == null || data.getCount() == 0) {
return;
}
// Swap the new cursor in. (The framework will take care of closing the
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
index 42abf35eb..b44e6dc78 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
@@ -17,6 +17,13 @@
package org.sufficientlysecure.keychain.ui;
+
+import java.io.BufferedWriter;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
import android.database.Cursor;
@@ -43,12 +50,10 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
-import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@@ -57,57 +62,35 @@ import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.NfcHelper;
-import java.io.BufferedWriter;
-import java.io.OutputStreamWriter;
-import java.io.IOException;
-import java.io.FileNotFoundException;
-
public class ViewKeyAdvShareFragment extends LoaderFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "uri";
- private TextView mFingerprint;
private ImageView mQrCode;
private CardView mQrCodeLayout;
- private View mFingerprintShareButton;
- private View mFingerprintClipboardButton;
- private View mKeyShareButton;
- private View mKeyClipboardButton;
- private View mKeyNfcButton;
- private ImageButton mKeySafeSlingerButton;
- private View mKeyUploadButton;
-
- ProviderHelper mProviderHelper;
+ private TextView mFingerprintView;
+
NfcHelper mNfcHelper;
private static final int LOADER_ID_UNIFIED = 0;
private Uri mDataUri;
+ private byte[] mFingerprint;
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) {
View root = super.onCreateView(inflater, superContainer, savedInstanceState);
View view = inflater.inflate(R.layout.view_key_adv_share_fragment, getContainer());
- mProviderHelper = new ProviderHelper(ViewKeyAdvShareFragment.this.getActivity());
- mNfcHelper = new NfcHelper(getActivity(), mProviderHelper);
+ ProviderHelper providerHelper = new ProviderHelper(ViewKeyAdvShareFragment.this.getActivity());
+ mNfcHelper = new NfcHelper(getActivity(), providerHelper);
- mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint);
+ mFingerprintView = (TextView) view.findViewById(R.id.view_key_fingerprint);
mQrCode = (ImageView) view.findViewById(R.id.view_key_qr_code);
mQrCodeLayout = (CardView) view.findViewById(R.id.view_key_qr_code_layout);
- mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share);
- mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard);
- mKeyShareButton = view.findViewById(R.id.view_key_action_key_share);
- mKeyNfcButton = view.findViewById(R.id.view_key_action_key_nfc);
- mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard);
- mKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger);
- mKeyUploadButton = view.findViewById(R.id.view_key_action_upload);
-
- mKeySafeSlingerButton.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
- PorterDuff.Mode.SRC_IN);
-
mQrCodeLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -115,50 +98,60 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
}
});
- mFingerprintShareButton.setOnClickListener(new View.OnClickListener() {
+ View vFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share);
+ View vFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard);
+ View vKeyShareButton = view.findViewById(R.id.view_key_action_key_share);
+ View vKeyNfcButton = view.findViewById(R.id.view_key_action_key_nfc);
+ View vKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard);
+ ImageButton vKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger);
+ View vKeyUploadButton = view.findViewById(R.id.view_key_action_upload);
+ vKeySafeSlingerButton.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
+ PorterDuff.Mode.SRC_IN);
+
+ vFingerprintShareButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- share(mDataUri, mProviderHelper, true, false);
+ share(true, false);
}
});
- mFingerprintClipboardButton.setOnClickListener(new View.OnClickListener() {
+ vFingerprintClipboardButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- share(mDataUri, mProviderHelper, true, true);
+ share(true, true);
}
});
- mKeyShareButton.setOnClickListener(new View.OnClickListener() {
+ vKeyShareButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- share(mDataUri, mProviderHelper, false, false);
+ share(false, false);
}
});
- mKeyClipboardButton.setOnClickListener(new View.OnClickListener() {
+ vKeyClipboardButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- share(mDataUri, mProviderHelper, false, true);
+ share(false, true);
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- mKeyNfcButton.setVisibility(View.VISIBLE);
- mKeyNfcButton.setOnClickListener(new View.OnClickListener() {
+ vKeyNfcButton.setVisibility(View.VISIBLE);
+ vKeyNfcButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNfcHelper.invokeNfcBeam();
}
});
} else {
- mKeyNfcButton.setVisibility(View.GONE);
+ vKeyNfcButton.setVisibility(View.GONE);
}
- mKeySafeSlingerButton.setOnClickListener(new View.OnClickListener() {
+ vKeySafeSlingerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startSafeSlinger(mDataUri);
}
});
- mKeyUploadButton.setOnClickListener(new View.OnClickListener() {
+ vKeyUploadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
uploadToKeyserver();
@@ -182,97 +175,79 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
startActivityForResult(safeSlingerIntent, 0);
}
- private void share(Uri dataUri, ProviderHelper providerHelper, boolean fingerprintOnly,
- boolean toClipboard) {
+ private void share(boolean fingerprintOnly, boolean toClipboard) {
+ Activity activity = getActivity();
+ if (activity == null || mFingerprint == null) {
+ return;
+ }
+ ProviderHelper providerHelper = new ProviderHelper(activity);
+
try {
String content;
- byte[] fingerprintData = (byte[]) providerHelper.getGenericData(
- KeyRings.buildUnifiedKeyRingUri(dataUri),
- Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
if (fingerprintOnly) {
- String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintData);
+ String fingerprint = KeyFormattingUtils.convertFingerprintToHex(mFingerprint);
if (!toClipboard) {
content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
} else {
content = fingerprint;
}
} else {
- Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri);
- // get public keyring as ascii armored string
- content = providerHelper.getKeyRingAsArmoredString(uri);
+ content = providerHelper.getKeyRingAsArmoredString(
+ KeychainContract.KeyRingData.buildPublicKeyRingUri(mDataUri));
}
if (toClipboard) {
- ClipboardReflection.copyToClipboard(getActivity(), content);
- String message;
- if (fingerprintOnly) {
- message = getResources().getString(R.string.fingerprint_copied_to_clipboard);
- } else {
- message = getResources().getString(R.string.key_copied_to_clipboard);
- }
- Notify.create(getActivity(), message, Notify.Style.OK).show();
- } else {
- // Android will fail with android.os.TransactionTooLargeException if key is too big
- // see http://www.lonestarprod.com/?p=34
- if (content.length() >= 86389) {
- Notify.create(getActivity(), R.string.key_too_big_for_sharing,
- Notify.Style.ERROR).show();
- return;
- }
-
- // let user choose application
- Intent sendIntent = new Intent(Intent.ACTION_SEND);
- sendIntent.putExtra(Intent.EXTRA_TEXT, content);
- sendIntent.setType("text/plain");
+ ClipboardReflection.copyToClipboard(activity, content);
+ Notify.create(activity, fingerprintOnly ? R.string.fingerprint_copied_to_clipboard
+ : R.string.key_copied_to_clipboard, Notify.Style.OK).show();
+ return;
+ }
- String title;
- if (fingerprintOnly) {
- title = getResources().getString(R.string.title_share_fingerprint_with);
- } else {
- title = getResources().getString(R.string.title_share_key);
- }
- Intent shareChooser = Intent.createChooser(sendIntent, title);
-
- // Bluetooth Share will convert text/plain sent via EXTRA_TEXT to HTML
- // Add replacement extra to send a text/plain file instead.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- try {
- String primaryUserId = UncachedKeyRing.decodeFromData(content.getBytes()).
- getPublicKey().getPrimaryUserIdWithFallback();
-
- TemporaryStorageProvider shareFileProv = new TemporaryStorageProvider();
- Uri contentUri = TemporaryStorageProvider.createFile(getActivity(),
- primaryUserId + Constants.FILE_EXTENSION_ASC);
-
- BufferedWriter contentWriter = new BufferedWriter(new OutputStreamWriter(
- new ParcelFileDescriptor.AutoCloseOutputStream(
- shareFileProv.openFile(contentUri, "w"))));
- contentWriter.write(content);
- contentWriter.close();
-
- // create replacement extras inside try{}:
- // if file creation fails, just don't add the replacements
- Bundle replacements = new Bundle();
- shareChooser.putExtra(Intent.EXTRA_REPLACEMENT_EXTRAS, replacements);
-
- Bundle bluetoothExtra = new Bundle(sendIntent.getExtras());
- replacements.putBundle("com.android.bluetooth", bluetoothExtra);
-
- bluetoothExtra.putParcelable(Intent.EXTRA_STREAM, contentUri);
- } catch (FileNotFoundException e) {
- Log.e(Constants.TAG, "error creating temporary Bluetooth key share file!", e);
- Notify.create(getActivity(), R.string.error_bluetooth_file, Notify.Style.ERROR).show();
- }
- }
+ // Android will fail with android.os.TransactionTooLargeException if key is too big
+ // see http://www.lonestarprod.com/?p=34
+ if (content.length() >= 86389) {
+ Notify.create(activity, R.string.key_too_big_for_sharing, Notify.Style.ERROR).show();
+ return;
+ }
- startActivity(shareChooser);
+ // let user choose application
+ Intent sendIntent = new Intent(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_TEXT, content);
+ sendIntent.setType("text/plain");
+
+ // Bluetooth Share will convert text/plain sent via EXTRA_TEXT to HTML
+ // Add replacement extra to send a text/plain file instead.
+ try {
+ TemporaryStorageProvider shareFileProv = new TemporaryStorageProvider();
+ Uri contentUri = TemporaryStorageProvider.createFile(activity,
+ KeyFormattingUtils.convertFingerprintToHex(mFingerprint) + Constants.FILE_EXTENSION_ASC);
+
+ BufferedWriter contentWriter = new BufferedWriter(new OutputStreamWriter(
+ new ParcelFileDescriptor.AutoCloseOutputStream(
+ shareFileProv.openFile(contentUri, "w"))));
+ contentWriter.write(content);
+ contentWriter.close();
+
+ sendIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
+ } catch (FileNotFoundException e) {
+ Log.e(Constants.TAG, "error creating temporary Bluetooth key share file!", e);
+ // no need for a snackbar because one sharing option doesn't work
+ // Notify.create(getActivity(), R.string.error_temp_file, Notify.Style.ERROR).show();
}
+
+
+ String title = getString(fingerprintOnly
+ ? R.string.title_share_fingerprint_with : R.string.title_share_key);
+ Intent shareChooser = Intent.createChooser(sendIntent, title);
+
+ startActivity(shareChooser);
+
} catch (PgpGeneralException | IOException e) {
Log.e(Constants.TAG, "error processing key!", e);
- Notify.create(getActivity(), R.string.error_key_processing, Notify.Style.ERROR).show();
+ Notify.create(activity, R.string.error_key_processing, Notify.Style.ERROR).show();
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
- Notify.create(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR).show();
+ Notify.create(activity, R.string.error_key_not_found, Notify.Style.ERROR).show();
}
}
@@ -293,8 +268,8 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
}
@Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
Uri dataUri = getArguments().getParcelable(ARG_DATA_URI);
if (dataUri == null) {
@@ -309,8 +284,6 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
private void loadData(Uri dataUri) {
mDataUri = dataUri;
- Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
-
// Prepare the loaders. Either re-connect with an existing ones,
// or start new ones.
getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
@@ -320,19 +293,10 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
}
static final String[] UNIFIED_PROJECTION = new String[] {
- KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET,
- KeyRings.USER_ID, KeyRings.FINGERPRINT,
- KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.IS_EXPIRED,
-
+ KeyRings._ID, KeyRings.FINGERPRINT
};
- static final int INDEX_UNIFIED_MASTER_KEY_ID = 1;
- static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2;
- static final int INDEX_UNIFIED_USER_ID = 3;
- static final int INDEX_UNIFIED_FINGERPRINT = 4;
- static final int INDEX_UNIFIED_ALGORITHM = 5;
- static final int INDEX_UNIFIED_KEY_SIZE = 6;
- static final int INDEX_UNIFIED_CREATION = 7;
- static final int INDEX_UNIFIED_ID_EXPIRED = 8;
+
+ static final int INDEX_UNIFIED_FINGERPRINT = 1;
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
setContentShown(false);
@@ -348,11 +312,8 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- /* TODO better error handling? May cause problems when a key is deleted,
- * because the notification triggers faster than the activity closes.
- */
// Avoid NullPointerExceptions...
- if (data.getCount() == 0) {
+ if (data == null || data.getCount() == 0) {
return;
}
// Swap the new cursor in. (The framework will take care of closing the
@@ -362,10 +323,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
if (data.moveToFirst()) {
byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT);
- String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob);
- mFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint));
-
- loadQrCode(fingerprint);
+ setFingerprint(fingerprintBlob);
break;
}
@@ -380,14 +338,16 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
* We need to make sure we are no longer using it.
*/
public void onLoaderReset(Loader<Cursor> loader) {
+ mFingerprint = null;
}
- /**
- * Load QR Code asynchronously and with a fade in animation
- *
- * @param fingerprint
- */
- private void loadQrCode(final String fingerprint) {
+ /** Load QR Code asynchronously and with a fade in animation */
+ private void setFingerprint(byte[] fingerprintBlob) {
+ mFingerprint = fingerprintBlob;
+
+ final String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob);
+ mFingerprintView.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint));
+
AsyncTask<Void, Void, Bitmap> loadTask =
new AsyncTask<Void, Void, Bitmap>() {
protected Bitmap doInBackground(Void... unused) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java
index a28a5ea59..bede16b2a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java
@@ -94,7 +94,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
public void onNewIntent(Intent intent) {
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
try {
- handleNdefDiscoveredIntent(intent);
+ handleTagDiscoveredIntent(intent);
} catch (CardException e) {
handleNfcError(e);
} catch (IOException e) {
@@ -269,7 +269,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
* This method is called by onNewIntent above upon discovery of an NFC tag.
* It handles initialization and login to the application, subsequently
* calls either nfcCalculateSignature() or nfcDecryptSessionKey(), then
- * finishes the activity with an appropiate result.
+ * finishes the activity with an appropriate result.
*
* On general communication, see also
* http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_annex-a.aspx
@@ -278,7 +278,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
* on ISO SmartCard Systems specification.
*
*/
- protected void handleNdefDiscoveredIntent(Intent intent) throws IOException {
+ protected void handleTagDiscoveredIntent(Intent intent) throws IOException {
Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java
index acac84e88..240dd0972 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java
@@ -121,7 +121,7 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
Activity activity = mUseFragment ? mFragment.getActivity() : mActivity;
switch (requiredInput.mType) {
- case NFC_KEYTOCARD:
+ case NFC_MOVE_KEY_TO_CARD:
case NFC_DECRYPT:
case NFC_SIGN: {
Intent intent = new Intent(activity, NfcOperationActivity.class);