aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
diff options
context:
space:
mode:
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java779
1 files changed, 403 insertions, 376 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index 7ae4f1be3..fd50ed5ef 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -31,9 +31,10 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
import android.provider.ContactsContract;
+import android.support.design.widget.AppBarLayout;
+import android.support.design.widget.CollapsingToolbarLayout;
+import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.LoaderManager;
@@ -47,16 +48,17 @@ import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
+import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
-import com.getbase.floatingactionbutton.FloatingActionButton;
+
+
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
-import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.KeyRing;
@@ -65,13 +67,10 @@ import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard;
-import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
-import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
-import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
-import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
+import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
@@ -85,37 +84,45 @@ import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.NfcHelper;
import org.sufficientlysecure.keychain.util.Preferences;
+import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.HashMap;
public class ViewKeyActivity extends BaseNfcActivity implements
- LoaderManager.LoaderCallbacks<Cursor> {
+ LoaderManager.LoaderCallbacks<Cursor>,
+ CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> {
public static final String EXTRA_NFC_USER_ID = "nfc_user_id";
public static final String EXTRA_NFC_AID = "nfc_aid";
public static final String EXTRA_NFC_FINGERPRINTS = "nfc_fingerprints";
static final int REQUEST_QR_FINGERPRINT = 1;
- static final int REQUEST_DELETE = 2;
- static final int REQUEST_EXPORT = 3;
+ static final int REQUEST_BACKUP = 2;
+ static final int REQUEST_CERTIFY = 3;
+ static final int REQUEST_DELETE = 4;
+
public static final String EXTRA_DISPLAY_RESULT = "display_result";
- ExportHelper mExportHelper;
ProviderHelper mProviderHelper;
protected Uri mDataUri;
- private TextView mName;
+ // For CryptoOperationHelper.Callback
+ private String mKeyserver;
+ private ArrayList<ParcelableKeyRing> mKeyList;
+ private CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult> mOperationHelper;
+
private TextView mStatusText;
private ImageView mStatusImage;
- private RelativeLayout mBigToolbar;
+ private AppBarLayout mAppBarLayout;
+ private CollapsingToolbarLayout mCollapsingToolbarLayout;
private ImageButton mActionEncryptFile;
private ImageButton mActionEncryptText;
private ImageButton mActionNfc;
private FloatingActionButton mFab;
private ImageView mPhoto;
+ private FrameLayout mPhotoLayout;
private ImageView mQrCode;
private CardView mQrCodeLayout;
@@ -132,6 +139,8 @@ public class ViewKeyActivity extends BaseNfcActivity implements
private boolean mIsRevoked = false;
private boolean mIsExpired = false;
+ private boolean mShowYubikeyAfterCreation = false;
+
private MenuItem mRefreshItem;
private boolean mIsRefreshing;
private Animation mRotate, mRotateSpin;
@@ -139,26 +148,31 @@ public class ViewKeyActivity extends BaseNfcActivity implements
private String mFingerprint;
private long mMasterKeyId;
+ private byte[] mNfcFingerprints;
+ private String mNfcUserId;
+ private byte[] mNfcAid;
+
@SuppressLint("InflateParams")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mExportHelper = new ExportHelper(this);
mProviderHelper = new ProviderHelper(this);
+ mOperationHelper = new CryptoOperationHelper<>(1, this, this, null);
setTitle(null);
- mName = (TextView) findViewById(R.id.view_key_name);
mStatusText = (TextView) findViewById(R.id.view_key_status);
mStatusImage = (ImageView) findViewById(R.id.view_key_status_image);
- mBigToolbar = (RelativeLayout) findViewById(R.id.toolbar_big);
+ mAppBarLayout = (AppBarLayout) findViewById(R.id.app_bar_layout);
+ mCollapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
mActionEncryptFile = (ImageButton) findViewById(R.id.view_key_action_encrypt_files);
mActionEncryptText = (ImageButton) findViewById(R.id.view_key_action_encrypt_text);
mActionNfc = (ImageButton) findViewById(R.id.view_key_action_nfc);
mFab = (FloatingActionButton) findViewById(R.id.fab);
mPhoto = (ImageView) findViewById(R.id.view_key_photo);
+ mPhotoLayout = (FrameLayout) findViewById(R.id.view_key_photo_layout);
mQrCode = (ImageView) findViewById(R.id.view_key_qr_code);
mQrCodeLayout = (CardView) findViewById(R.id.view_key_qr_code_layout);
@@ -287,14 +301,17 @@ public class ViewKeyActivity extends BaseNfcActivity implements
.replace(R.id.view_key_fragment, frag)
.commit();
- if (getIntent().hasExtra(EXTRA_NFC_AID)) {
- Intent intent = getIntent();
- byte[] nfcFingerprints = intent.getByteArrayExtra(EXTRA_NFC_FINGERPRINTS);
- String nfcUserId = intent.getStringExtra(EXTRA_NFC_USER_ID);
- byte[] nfcAid = intent.getByteArrayExtra(EXTRA_NFC_AID);
- showYubiKeyFragment(nfcFingerprints, nfcUserId, nfcAid);
+ if (Preferences.getPreferences(this).getExperimentalEnableKeybase()) {
+ final ViewKeyKeybaseFragment keybaseFrag = ViewKeyKeybaseFragment.newInstance(mDataUri);
+ manager.beginTransaction()
+ .replace(R.id.view_key_keybase_fragment, keybaseFrag)
+ .commit();
}
+ // need to postpone loading of the yubikey fragment until after mMasterKeyId
+ // is available, but we mark here that this should be done
+ mShowYubikeyAfterCreation = true;
+
}
@Override
@@ -320,31 +337,11 @@ public class ViewKeyActivity extends BaseNfcActivity implements
return true;
}
case R.id.menu_key_view_export_file: {
- try {
- if (PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId, mMasterKeyId) != null) {
- exportToFile(mDataUri, mExportHelper, mProviderHelper);
- return true;
- }
-
- startPassphraseActivity(REQUEST_EXPORT);
- } catch (PassphraseCacheService.KeyNotFoundException e) {
- // This happens when the master key is stripped
- exportToFile(mDataUri, mExportHelper, mProviderHelper);
- }
+ startPassphraseActivity(REQUEST_BACKUP);
return true;
}
case R.id.menu_key_view_delete: {
- try {
- if (PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId, mMasterKeyId) != null) {
- deleteKey();
- return true;
- }
-
- startPassphraseActivity(REQUEST_DELETE);
- } catch (PassphraseCacheService.KeyNotFoundException e) {
- // This happens when the master key is stripped
- deleteKey();
- }
+ deleteKey();
return true;
}
case R.id.menu_key_view_advanced: {
@@ -372,7 +369,11 @@ public class ViewKeyActivity extends BaseNfcActivity implements
return true;
}
case R.id.menu_key_view_certify_fingerprint: {
- certifyFingeprint(mDataUri);
+ certifyFingeprint(mDataUri, false);
+ return true;
+ }
+ case R.id.menu_key_view_certify_fingerprint_word: {
+ certifyFingeprint(mDataUri, true);
return true;
}
}
@@ -384,11 +385,17 @@ public class ViewKeyActivity extends BaseNfcActivity implements
MenuItem editKey = menu.findItem(R.id.menu_key_view_edit);
editKey.setVisible(mIsSecret);
+ MenuItem exportKey = menu.findItem(R.id.menu_key_view_export_file);
+ exportKey.setVisible(mIsSecret);
+
MenuItem addLinked = menu.findItem(R.id.menu_key_view_add_linked_identity);
addLinked.setVisible(mIsSecret);
MenuItem certifyFingerprint = menu.findItem(R.id.menu_key_view_certify_fingerprint);
certifyFingerprint.setVisible(!mIsSecret && !mIsVerified && !mIsExpired && !mIsRevoked);
+ MenuItem certifyFingerprintWord = menu.findItem(R.id.menu_key_view_certify_fingerprint_word);
+ certifyFingerprintWord.setVisible(!mIsSecret && !mIsVerified && !mIsExpired && !mIsRevoked
+ && Preferences.getPreferences(this).getExperimentalEnableWordConfirm());
return true;
}
@@ -400,40 +407,19 @@ public class ViewKeyActivity extends BaseNfcActivity implements
startActivityForResult(scanQrCode, REQUEST_QR_FINGERPRINT);
}
- private void certifyFingeprint(Uri dataUri) {
+ private void certifyFingeprint(Uri dataUri, boolean enableWordConfirm) {
Intent intent = new Intent(this, CertifyFingerprintActivity.class);
intent.setData(dataUri);
+ intent.putExtra(CertifyFingerprintActivity.EXTRA_ENABLE_WORD_CONFIRM, enableWordConfirm);
- startCertifyIntent(intent);
+ startActivityForResult(intent, REQUEST_CERTIFY);
}
private void certifyImmediate() {
Intent intent = new Intent(this, CertifyKeyActivity.class);
- intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[] {mMasterKeyId});
+ intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{mMasterKeyId});
- startCertifyIntent(intent);
- }
-
- private void startCertifyIntent(Intent intent) {
- // Message is received after signing is done in KeychainIntentService
- ServiceProgressHandler saveHandler = new ServiceProgressHandler(this) {
- public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentServiceHandler first
- super.handleMessage(message);
-
- if (message.arg1 == MessageStatus.OKAY.ordinal()) {
- Bundle data = message.getData();
- CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
-
- result.createNotify(ViewKeyActivity.this).show();
- }
- }
- };
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(saveHandler);
- intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
-
- startActivityForResult(intent, 0);
+ startActivityForResult(intent, REQUEST_CERTIFY);
}
private void showQrCodeDialog() {
@@ -458,95 +444,108 @@ public class ViewKeyActivity extends BaseNfcActivity implements
startActivityForResult(intent, requestCode);
}
- private void exportToFile(Uri dataUri, ExportHelper exportHelper, ProviderHelper providerHelper) {
- try {
- Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri);
-
- HashMap<String, Object> data = providerHelper.getGenericData(
- baseUri,
- new String[] {KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET},
- new int[] {ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER});
-
- exportHelper.showExportKeysDialog(
- new long[] {(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)},
- Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) != 0)
- );
- } catch (ProviderHelper.NotFoundException e) {
- Notify.create(this, R.string.error_key_not_found, Notify.Style.ERROR).show();
- Log.e(Constants.TAG, "Key not found", e);
- }
+ private void backupToFile() {
+ new ExportHelper(this).showExportKeysDialog(
+ mMasterKeyId, new File(Constants.Path.APP_DIR,
+ KeyFormattingUtils.convertKeyIdToHex(mMasterKeyId) + ".sec.asc"), true);
}
private void deleteKey() {
- // Message is received after key is deleted
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.arg1 == MessageStatus.OKAY.ordinal()) {
- setResult(RESULT_CANCELED);
- finish();
- }
- }
- };
+ Intent deleteIntent = new Intent(this, DeleteKeyDialogActivity.class);
+
+ deleteIntent.putExtra(DeleteKeyDialogActivity.EXTRA_DELETE_MASTER_KEY_IDS,
+ new long[]{mMasterKeyId});
+ deleteIntent.putExtra(DeleteKeyDialogActivity.EXTRA_HAS_SECRET, mIsSecret);
+ if (mIsSecret) {
+ // for upload in case key is secret
+ deleteIntent.putExtra(DeleteKeyDialogActivity.EXTRA_KEYSERVER,
+ Preferences.getPreferences(this).getPreferredKeyserver());
+ }
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(returnHandler);
- DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
- new long[] {mMasterKeyId});
- deleteKeyDialog.show(getSupportFragmentManager(), "deleteKeyDialog");
+ startActivityForResult(deleteIntent, REQUEST_DELETE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUEST_QR_FINGERPRINT && resultCode == Activity.RESULT_OK) {
+ if (mOperationHelper.handleActivityResult(requestCode, resultCode, data)) {
+ return;
+ }
- // If there is an EXTRA_RESULT, that's an error. Just show it.
- if (data.hasExtra(OperationResult.EXTRA_RESULT)) {
- OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
- result.createNotify(this).show();
+ switch (requestCode) {
+ case REQUEST_QR_FINGERPRINT: {
+
+ if (resultCode != Activity.RESULT_OK) {
+ return;
+ }
+
+ // If there is an EXTRA_RESULT, that's an error. Just show it.
+ if (data.hasExtra(OperationResult.EXTRA_RESULT)) {
+ OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
+ result.createNotify(this).show();
+ return;
+ }
+
+ String fp = data.getStringExtra(ImportKeysProxyActivity.EXTRA_FINGERPRINT);
+ if (fp == null) {
+ Notify.create(this, R.string.error_scan_fp, Notify.LENGTH_LONG, Style.ERROR).show();
+ return;
+ }
+ if (mFingerprint.equalsIgnoreCase(fp)) {
+ certifyImmediate();
+ } else {
+ Notify.create(this, R.string.error_scan_match, Notify.LENGTH_LONG, Style.ERROR).show();
+ }
return;
}
- String fp = data.getStringExtra(ImportKeysProxyActivity.EXTRA_FINGERPRINT);
- if (fp == null) {
- Notify.create(this, "Error scanning fingerprint!",
- Notify.LENGTH_LONG, Notify.Style.ERROR).show();
+ case REQUEST_BACKUP: {
+ if (resultCode != Activity.RESULT_OK) {
+ return;
+ }
+
+ backupToFile();
return;
}
- if (mFingerprint.equalsIgnoreCase(fp)) {
- certifyImmediate();
- } else {
- Notify.create(this, "Fingerprints did not match!",
- Notify.LENGTH_LONG, Notify.Style.ERROR).show();
+
+ case REQUEST_CERTIFY: {
+ if (resultCode != Activity.RESULT_OK) {
+ return;
+ }
+
+ if (data.hasExtra(OperationResult.EXTRA_RESULT)) {
+ OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
+ result.createNotify(this).show();
+ }
+ return;
}
- return;
- }
+ case REQUEST_DELETE: {
+ if (resultCode != Activity.RESULT_OK) {
+ return;
+ }
- if (requestCode == REQUEST_DELETE && resultCode == Activity.RESULT_OK) {
- deleteKey();
+ setResult(RESULT_OK, data);
+ finish();
+ return;
+ }
}
- if (requestCode == REQUEST_EXPORT && resultCode == Activity.RESULT_OK) {
- exportToFile(mDataUri, mExportHelper, mProviderHelper);
- }
+ super.onActivityResult(requestCode, resultCode, data);
- if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
- OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
- result.createNotify(this).show();
- } else {
- super.onActivityResult(requestCode, resultCode, data);
- }
}
@Override
- protected void onNfcPerform() throws IOException {
+ protected void doNfcInBackground() throws IOException {
- final byte[] nfcFingerprints = nfcGetFingerprints();
- final String nfcUserId = nfcGetUserId();
- final byte[] nfcAid = nfcGetAid();
+ mNfcFingerprints = nfcGetFingerprints();
+ mNfcUserId = nfcGetUserId();
+ mNfcAid = nfcGetAid();
+ }
+
+ @Override
+ protected void onNfcPostExecute() throws IOException {
- long yubiKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(nfcFingerprints);
+ long yubiKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints);
try {
@@ -557,7 +556,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
// if the master key of that key matches this one, just show the yubikey dialog
if (KeyFormattingUtils.convertFingerprintToHex(candidateFp).equals(mFingerprint)) {
- showYubiKeyFragment(nfcFingerprints, nfcUserId, nfcAid);
+ showYubiKeyFragment(mNfcFingerprints, mNfcUserId, mNfcAid);
return;
}
@@ -570,14 +569,13 @@ public class ViewKeyActivity extends BaseNfcActivity implements
Intent intent = new Intent(
ViewKeyActivity.this, ViewKeyActivity.class);
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId));
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, nfcUserId);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
startActivity(intent);
finish();
}
}, R.string.snack_yubikey_view).show();
-
// and if it's not found, offer import
} catch (PgpKeyNotFoundException e) {
Notify.create(this, R.string.snack_yubi_other, Notify.LENGTH_LONG,
@@ -586,28 +584,36 @@ public class ViewKeyActivity extends BaseNfcActivity implements
public void onAction() {
Intent intent = new Intent(
ViewKeyActivity.this, CreateKeyActivity.class);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, nfcUserId);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
startActivity(intent);
finish();
}
}, R.string.snack_yubikey_import).show();
}
-
}
- public void showYubiKeyFragment(byte[] nfcFingerprints, String nfcUserId, byte[] nfcAid) {
- ViewKeyYubiKeyFragment frag = ViewKeyYubiKeyFragment.newInstance(
- nfcFingerprints, nfcUserId, nfcAid);
+ public void showYubiKeyFragment(
+ final byte[] nfcFingerprints, final String nfcUserId, final byte[] nfcAid) {
- FragmentManager manager = getSupportFragmentManager();
+ new Handler().post(new Runnable() {
+ @Override
+ public void run() {
+ ViewKeyYubiKeyFragment frag = ViewKeyYubiKeyFragment.newInstance(
+ mMasterKeyId, nfcFingerprints, nfcUserId, nfcAid);
+
+ FragmentManager manager = getSupportFragmentManager();
+
+ manager.popBackStack("yubikey", FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ manager.beginTransaction()
+ .addToBackStack("yubikey")
+ .replace(R.id.view_key_fragment, frag)
+ // if this is called while the activity wasn't resumed, just forget it happened
+ .commitAllowingStateLoss();
+ }
+ });
- manager.popBackStack("yubikey", FragmentManager.POP_BACK_STACK_INCLUSIVE);
- manager.beginTransaction()
- .addToBackStack("yubikey")
- .replace(R.id.view_key_fragment, frag)
- .commit();
}
private void encrypt(Uri dataUri, boolean text) {
@@ -620,7 +626,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
long keyId = new ProviderHelper(this)
.getCachedPublicKeyRing(dataUri)
.extractOrGetMasterKeyId();
- long[] encryptionKeyIds = new long[] {keyId};
+ long[] encryptionKeyIds = new long[]{keyId};
Intent intent;
if (text) {
intent = new Intent(this, EncryptTextActivity.class);
@@ -638,76 +644,6 @@ public class ViewKeyActivity extends BaseNfcActivity implements
}
}
- private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper)
- throws ProviderHelper.NotFoundException {
-
- mIsRefreshing = true;
- mRefreshItem.setEnabled(false);
- mRefreshItem.setActionView(mRefresh);
- mRefresh.startAnimation(mRotate);
-
- byte[] blob = (byte[]) providerHelper.getGenericData(
- KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
- KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
- String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob);
-
- ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null);
- ArrayList<ParcelableKeyRing> entries = new ArrayList<>();
- entries.add(keyEntry);
-
- // Message is received after importing is done in KeychainIntentService
- ServiceProgressHandler serviceHandler = new ServiceProgressHandler(this) {
- public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentServiceHandler first
- super.handleMessage(message);
-
- if (message.arg1 == MessageStatus.OKAY.ordinal()) {
- // get returned data bundle
- Bundle returnData = message.getData();
-
- mIsRefreshing = false;
-
- if (returnData == null) {
- finish();
- return;
- }
- final ImportKeyResult result =
- returnData.getParcelable(OperationResult.EXTRA_RESULT);
- result.createNotify(ViewKeyActivity.this).show();
- }
- }
- };
-
- // fill values for this action
- Bundle data = new Bundle();
-
- // search config
- {
- Preferences prefs = Preferences.getPreferences(this);
- Preferences.CloudSearchPrefs cloudPrefs =
- new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
- data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver);
- }
-
- data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, entries);
-
- // Send all information needed to service to query keys in other thread
- Intent intent = new Intent(this, KeychainIntentService.class);
- intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING);
- intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(serviceHandler);
- intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
-
- // show progress dialog
- serviceHandler.showProgressDialog(this);
-
- // start service with intent
- startService(intent);
-
- }
-
private void editKey(Uri dataUri) {
Intent editIntent = new Intent(this, EditKeyActivity.class);
editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri));
@@ -735,9 +671,12 @@ public class ViewKeyActivity extends BaseNfcActivity implements
AsyncTask<Void, Void, Bitmap> loadTask =
new AsyncTask<Void, Void, Bitmap>() {
protected Bitmap doInBackground(Void... unused) {
- String qrCodeContent = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
+ Uri uri = new Uri.Builder()
+ .scheme(Constants.FINGERPRINT_SCHEME)
+ .opaquePart(fingerprint)
+ .build();
// render with minimal size
- return QrCodeUtils.getQRCodeBitmap(qrCodeContent, 0);
+ return QrCodeUtils.getQRCodeBitmap(uri, 0);
}
protected void onPostExecute(Bitmap qrCode) {
@@ -761,7 +700,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
// These are the rows that we will retrieve.
- static final String[] PROJECTION = new String[] {
+ static final String[] PROJECTION = new String[]{
KeychainContract.KeyRings._ID,
KeychainContract.KeyRings.MASTER_KEY_ID,
KeychainContract.KeyRings.USER_ID,
@@ -797,6 +736,25 @@ public class ViewKeyActivity extends BaseNfcActivity implements
int mPreviousColor = 0;
+ /**
+ * Calculate a reasonable color for the status bar based on the given toolbar color.
+ * Style guides want the toolbar color to be a "700" on the Android scale and the status
+ * bar should be the same color at "500", this is roughly 17 / 20th of the value in each
+ * channel.
+ * http://www.google.com/design/spec/style/color.html#color-color-palette
+ */
+ static public int getStatusBarBackgroundColor(int color) {
+ int r = (color >> 16) & 0xff;
+ int g = (color >> 8) & 0xff;
+ int b = color & 0xff;
+
+ r = r * 17 / 20;
+ g = g * 17 / 20;
+ b = b * 17 / 20;
+
+ return (0xff << 24) | (r << 16) | (g << 8) | b;
+ }
+
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
/* TODO better error handling? May cause problems when a key is deleted,
@@ -809,172 +767,181 @@ public class ViewKeyActivity extends BaseNfcActivity implements
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
switch (loader.getId()) {
-
case LOADER_ID_UNIFIED: {
- if (!data.moveToFirst()) {
- return;
- }
-
- // get name, email, and comment from USER_ID
- KeyRing.UserId mainUserId = KeyRing.splitUserId(data.getString(INDEX_USER_ID));
- if (mainUserId.name != null) {
- mName.setText(mainUserId.name);
- } else {
- mName.setText(R.string.user_id_no_name);
- }
-
- mMasterKeyId = data.getLong(INDEX_MASTER_KEY_ID);
- mFingerprint = KeyFormattingUtils.convertFingerprintToHex(
- data.getBlob(INDEX_FINGERPRINT));
-
- mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0;
- mHasEncrypt = data.getInt(INDEX_HAS_ENCRYPT) != 0;
- mIsRevoked = data.getInt(INDEX_IS_REVOKED) > 0;
- mIsExpired = data.getInt(INDEX_IS_EXPIRED) != 0;
- mIsVerified = data.getInt(INDEX_VERIFIED) > 0;
-
- // if the refresh animation isn't playing
- if (!mRotate.hasStarted() && !mRotateSpin.hasStarted()) {
- // re-create options menu based on mIsSecret, mIsVerified
- supportInvalidateOptionsMenu();
- // this is done at the end of the animation otherwise
- }
-
- AsyncTask<Long, Void, Bitmap> photoTask =
- new AsyncTask<Long, Void, Bitmap>() {
- protected Bitmap doInBackground(Long... mMasterKeyId) {
- return ContactHelper.loadPhotoByMasterKeyId(getContentResolver(), mMasterKeyId[0], true);
- }
-
- protected void onPostExecute(Bitmap photo) {
- mPhoto.setImageBitmap(photo);
- mPhoto.setVisibility(View.VISIBLE);
- }
- };
-
- // Note: order is important
- int color;
- if (mIsRevoked) {
- mStatusText.setText(R.string.view_key_revoked);
- mStatusImage.setVisibility(View.VISIBLE);
- KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
- State.REVOKED, R.color.icons, true);
- color = getResources().getColor(R.color.android_red_light);
-
- mActionEncryptFile.setVisibility(View.GONE);
- mActionEncryptText.setVisibility(View.GONE);
- mActionNfc.setVisibility(View.GONE);
- mFab.setVisibility(View.GONE);
- mQrCodeLayout.setVisibility(View.GONE);
- } else if (mIsExpired) {
- if (mIsSecret) {
- mStatusText.setText(R.string.view_key_expired_secret);
+ if (data.moveToFirst()) {
+ // get name, email, and comment from USER_ID
+ KeyRing.UserId mainUserId = KeyRing.splitUserId(data.getString(INDEX_USER_ID));
+ if (mainUserId.name != null) {
+ mCollapsingToolbarLayout.setTitle(mainUserId.name);
} else {
- mStatusText.setText(R.string.view_key_expired);
- }
- mStatusImage.setVisibility(View.VISIBLE);
- KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
- State.EXPIRED, R.color.icons, true);
- color = getResources().getColor(R.color.android_red_light);
-
- mActionEncryptFile.setVisibility(View.GONE);
- mActionEncryptText.setVisibility(View.GONE);
- mActionNfc.setVisibility(View.GONE);
- mFab.setVisibility(View.GONE);
- mQrCodeLayout.setVisibility(View.GONE);
- } else if (mIsSecret) {
- mStatusText.setText(R.string.view_key_my_key);
- mStatusImage.setVisibility(View.GONE);
- color = getResources().getColor(R.color.primary);
- // reload qr code only if the fingerprint changed
- if (!mFingerprint.equals(mQrCodeLoaded)) {
- loadQrCode(mFingerprint);
- }
- photoTask.execute(mMasterKeyId);
- mQrCodeLayout.setVisibility(View.VISIBLE);
-
- // and place leftOf qr code
- RelativeLayout.LayoutParams nameParams = (RelativeLayout.LayoutParams)
- mName.getLayoutParams();
- // remove right margin
- nameParams.setMargins(FormattingUtils.dpToPx(this, 48), 0, 0, 0);
- if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- nameParams.setMarginEnd(0);
+ mCollapsingToolbarLayout.setTitle(getString(R.string.user_id_no_name));
}
- nameParams.addRule(RelativeLayout.LEFT_OF, R.id.view_key_qr_code_layout);
- mName.setLayoutParams(nameParams);
-
- RelativeLayout.LayoutParams statusParams = (RelativeLayout.LayoutParams)
- mStatusText.getLayoutParams();
- statusParams.setMargins(FormattingUtils.dpToPx(this, 48), 0, 0, 0);
- if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- statusParams.setMarginEnd(0);
- }
- statusParams.addRule(RelativeLayout.LEFT_OF, R.id.view_key_qr_code_layout);
- mStatusText.setLayoutParams(statusParams);
- mActionEncryptFile.setVisibility(View.VISIBLE);
- mActionEncryptText.setVisibility(View.VISIBLE);
+ mMasterKeyId = data.getLong(INDEX_MASTER_KEY_ID);
+ mFingerprint = KeyFormattingUtils.convertFingerprintToHex(data.getBlob(INDEX_FINGERPRINT));
+
+ // if it wasn't shown yet, display yubikey fragment
+ if (mShowYubikeyAfterCreation && getIntent().hasExtra(EXTRA_NFC_AID)) {
+ mShowYubikeyAfterCreation = false;
+ Intent intent = getIntent();
+ byte[] nfcFingerprints = intent.getByteArrayExtra(EXTRA_NFC_FINGERPRINTS);
+ String nfcUserId = intent.getStringExtra(EXTRA_NFC_USER_ID);
+ byte[] nfcAid = intent.getByteArrayExtra(EXTRA_NFC_AID);
+ showYubiKeyFragment(nfcFingerprints, nfcUserId, nfcAid);
+ }
- // invokeBeam is available from API 21
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- mActionNfc.setVisibility(View.VISIBLE);
- } else {
- mActionNfc.setVisibility(View.GONE);
+ mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0;
+ mHasEncrypt = data.getInt(INDEX_HAS_ENCRYPT) != 0;
+ mIsRevoked = data.getInt(INDEX_IS_REVOKED) > 0;
+ mIsExpired = data.getInt(INDEX_IS_EXPIRED) != 0;
+ mIsVerified = data.getInt(INDEX_VERIFIED) > 0;
+
+ // if the refresh animation isn't playing
+ if (!mRotate.hasStarted() && !mRotateSpin.hasStarted()) {
+ // re-create options menu based on mIsSecret, mIsVerified
+ supportInvalidateOptionsMenu();
+ // this is done at the end of the animation otherwise
}
- mFab.setVisibility(View.VISIBLE);
- mFab.setIconDrawable(getResources().getDrawable(R.drawable.ic_repeat_white_24dp));
- } else {
- mActionEncryptFile.setVisibility(View.VISIBLE);
- mActionEncryptText.setVisibility(View.VISIBLE);
- mQrCodeLayout.setVisibility(View.GONE);
- mActionNfc.setVisibility(View.GONE);
- if (mIsVerified) {
- mStatusText.setText(R.string.view_key_verified);
+ AsyncTask<Long, Void, Bitmap> photoTask =
+ new AsyncTask<Long, Void, Bitmap>() {
+ protected Bitmap doInBackground(Long... mMasterKeyId) {
+ return ContactHelper.loadPhotoByMasterKeyId(getContentResolver(),
+ mMasterKeyId[0], true);
+ }
+
+ protected void onPostExecute(Bitmap photo) {
+ if (photo == null) {
+ return;
+ }
+
+ mPhoto.setImageBitmap(photo);
+ mPhotoLayout.setVisibility(View.VISIBLE);
+ }
+ };
+
+ // Note: order is important
+ int color;
+ if (mIsRevoked) {
+ mStatusText.setText(R.string.view_key_revoked);
mStatusImage.setVisibility(View.VISIBLE);
KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
- State.VERIFIED, R.color.icons, true);
- color = getResources().getColor(R.color.primary);
- photoTask.execute(mMasterKeyId);
+ State.REVOKED, R.color.icons, true);
+ color = getResources().getColor(R.color.key_flag_red);
+ mActionEncryptFile.setVisibility(View.INVISIBLE);
+ mActionEncryptText.setVisibility(View.INVISIBLE);
+ mActionNfc.setVisibility(View.INVISIBLE);
mFab.setVisibility(View.GONE);
- } else {
- mStatusText.setText(R.string.view_key_unverified);
+ mQrCodeLayout.setVisibility(View.GONE);
+ } else if (mIsExpired) {
+ if (mIsSecret) {
+ mStatusText.setText(R.string.view_key_expired_secret);
+ } else {
+ mStatusText.setText(R.string.view_key_expired);
+ }
mStatusImage.setVisibility(View.VISIBLE);
KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
- State.UNVERIFIED, R.color.icons, true);
- color = getResources().getColor(R.color.android_orange_light);
+ State.EXPIRED, R.color.icons, true);
+ color = getResources().getColor(R.color.key_flag_red);
+ mActionEncryptFile.setVisibility(View.INVISIBLE);
+ mActionEncryptText.setVisibility(View.INVISIBLE);
+ mActionNfc.setVisibility(View.INVISIBLE);
+ mFab.setVisibility(View.GONE);
+ mQrCodeLayout.setVisibility(View.GONE);
+ } else if (mIsSecret) {
+ mStatusText.setText(R.string.view_key_my_key);
+ mStatusImage.setVisibility(View.GONE);
+ color = getResources().getColor(R.color.key_flag_green);
+ // reload qr code only if the fingerprint changed
+ if (!mFingerprint.equals(mQrCodeLoaded)) {
+ loadQrCode(mFingerprint);
+ }
+ photoTask.execute(mMasterKeyId);
+ mQrCodeLayout.setVisibility(View.VISIBLE);
+
+ // and place leftOf qr code
+// RelativeLayout.LayoutParams nameParams = (RelativeLayout.LayoutParams)
+// mName.getLayoutParams();
+// // remove right margin
+// nameParams.setMargins(FormattingUtils.dpToPx(this, 48), 0, 0, 0);
+// if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+// nameParams.setMarginEnd(0);
+// }
+// nameParams.addRule(RelativeLayout.LEFT_OF, R.id.view_key_qr_code_layout);
+// mName.setLayoutParams(nameParams);
+
+ RelativeLayout.LayoutParams statusParams = (RelativeLayout.LayoutParams)
+ mStatusText.getLayoutParams();
+ statusParams.setMargins(FormattingUtils.dpToPx(this, 48), 0, 0, 0);
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ statusParams.setMarginEnd(0);
+ }
+ statusParams.addRule(RelativeLayout.LEFT_OF, R.id.view_key_qr_code_layout);
+ mStatusText.setLayoutParams(statusParams);
+
+ mActionEncryptFile.setVisibility(View.VISIBLE);
+ mActionEncryptText.setVisibility(View.VISIBLE);
+
+ // invokeBeam is available from API 21
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ mActionNfc.setVisibility(View.VISIBLE);
+ } else {
+ mActionNfc.setVisibility(View.GONE);
+ }
mFab.setVisibility(View.VISIBLE);
- }
- }
+ // noinspection deprecation (no getDrawable with theme at current minApi level 15!)
+ mFab.setImageDrawable(getResources().getDrawable(R.drawable.ic_repeat_white_24dp));
+ } else {
+ mActionEncryptFile.setVisibility(View.VISIBLE);
+ mActionEncryptText.setVisibility(View.VISIBLE);
+ mQrCodeLayout.setVisibility(View.GONE);
+ mActionNfc.setVisibility(View.GONE);
- if (mPreviousColor == 0 || mPreviousColor == color) {
- mStatusBar.setBackgroundColor(color);
- mBigToolbar.setBackgroundColor(color);
- mPreviousColor = color;
- } else {
- ObjectAnimator colorFade1 =
- ObjectAnimator.ofObject(mStatusBar, "backgroundColor",
- new ArgbEvaluator(), mPreviousColor, color);
- ObjectAnimator colorFade2 =
- ObjectAnimator.ofObject(mBigToolbar, "backgroundColor",
- new ArgbEvaluator(), mPreviousColor, color);
-
- colorFade1.setDuration(1200);
- colorFade2.setDuration(1200);
- colorFade1.start();
- colorFade2.start();
- mPreviousColor = color;
- }
+ if (mIsVerified) {
+ mStatusText.setText(R.string.view_key_verified);
+ mStatusImage.setVisibility(View.VISIBLE);
+ KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
+ State.VERIFIED, R.color.icons, true);
+ color = getResources().getColor(R.color.key_flag_green);
+ photoTask.execute(mMasterKeyId);
+
+ mFab.setVisibility(View.GONE);
+ } else {
+ mStatusText.setText(R.string.view_key_unverified);
+ mStatusImage.setVisibility(View.VISIBLE);
+ KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
+ State.UNVERIFIED, R.color.icons, true);
+ color = getResources().getColor(R.color.key_flag_orange);
+
+ mFab.setVisibility(View.VISIBLE);
+ }
+ }
- //noinspection deprecation
- mStatusImage.setAlpha(80);
+ if (mPreviousColor == 0 || mPreviousColor == color) {
+ mAppBarLayout.setBackgroundColor(color);
+ mCollapsingToolbarLayout.setContentScrimColor(color);
+ mCollapsingToolbarLayout.setStatusBarScrimColor(getStatusBarBackgroundColor(color));
+ mPreviousColor = color;
+ } else {
+ ObjectAnimator colorFade =
+ ObjectAnimator.ofObject(mAppBarLayout, "backgroundColor",
+ new ArgbEvaluator(), mPreviousColor, color);
+ mCollapsingToolbarLayout.setContentScrimColor(color);
+ mCollapsingToolbarLayout.setStatusBarScrimColor(getStatusBarBackgroundColor(color));
+
+ colorFade.setDuration(1200);
+ colorFade.start();
+ mPreviousColor = color;
+ }
- break;
+ //noinspection deprecation
+ mStatusImage.setAlpha(80);
+ break;
+ }
}
}
}
@@ -984,4 +951,64 @@ public class ViewKeyActivity extends BaseNfcActivity implements
}
+ // CryptoOperationHelper.Callback functions
+
+
+ private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper)
+ throws ProviderHelper.NotFoundException {
+
+ mIsRefreshing = true;
+ mRefreshItem.setEnabled(false);
+ mRefreshItem.setActionView(mRefresh);
+ mRefresh.startAnimation(mRotate);
+
+ byte[] blob = (byte[]) providerHelper.getGenericData(
+ KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
+ KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
+ String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob);
+
+ ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null);
+ ArrayList<ParcelableKeyRing> entries = new ArrayList<>();
+ entries.add(keyEntry);
+ mKeyList = entries;
+
+ // search config
+ {
+ Preferences prefs = Preferences.getPreferences(this);
+ Preferences.CloudSearchPrefs cloudPrefs =
+ new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
+ mKeyserver = cloudPrefs.keyserver;
+ }
+
+ mOperationHelper.cryptoOperation();
+ }
+
+ @Override
+ public ImportKeyringParcel createOperationInput() {
+ return new ImportKeyringParcel(mKeyList, mKeyserver);
+ }
+
+ @Override
+ public void onCryptoOperationSuccess(ImportKeyResult result) {
+ mIsRefreshing = false;
+ result.createNotify(this).show();
+ }
+
+ @Override
+ public void onCryptoOperationCancelled() {
+ mIsRefreshing = false;
+ }
+
+ @Override
+ public void onCryptoOperationError(ImportKeyResult result) {
+ mIsRefreshing = false;
+ result.createNotify(this).show();
+ }
+
+ @Override
+ public boolean onCryptoSetProgress(String msg, int progress, int max) {
+ return true;
+ }
+
}
+