mirror of
https://github.com/moparisthebest/open-keychain
synced 2025-02-22 13:51:48 -05:00
Merge branch 'development' into linked-identities
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java
This commit is contained in:
commit
4afd6b881e
11
.gitmodules
vendored
11
.gitmodules
vendored
@ -1,29 +1,36 @@
|
||||
[submodule "extern/StickyListHeaders"]
|
||||
path = extern/StickyListHeaders
|
||||
url = https://github.com/open-keychain/StickyListHeaders.git
|
||||
ignore = dirty
|
||||
[submodule "extern/spongycastle"]
|
||||
path = extern/spongycastle
|
||||
url = https://github.com/open-keychain/spongycastle.git
|
||||
ignore = dirty
|
||||
[submodule "extern/html-textview"]
|
||||
path = extern/html-textview
|
||||
url = https://github.com/open-keychain/html-textview.git
|
||||
ignore = dirty
|
||||
[submodule "extern/openpgp-api-lib"]
|
||||
path = extern/openpgp-api-lib
|
||||
url = https://github.com/open-keychain/openpgp-api-lib.git
|
||||
ignore = dirty
|
||||
[submodule "extern/openkeychain-api-lib"]
|
||||
path = extern/openkeychain-api-lib
|
||||
url = https://github.com/open-keychain/openkeychain-api-lib.git
|
||||
ignore = dirty
|
||||
[submodule "extern/KeybaseLib"]
|
||||
path = extern/KeybaseLib
|
||||
url = https://github.com/open-keychain/KeybaseLib.git
|
||||
ignore = dirty
|
||||
[submodule "extern/minidns"]
|
||||
path = extern/minidns
|
||||
url = https://github.com/open-keychain/minidns.git
|
||||
ignore = dirty
|
||||
ignore = dirty
|
||||
[submodule "extern/TokenAutoComplete"]
|
||||
path = extern/TokenAutoComplete
|
||||
url = https://github.com/open-keychain/TokenAutoComplete
|
||||
ignore = dirty
|
||||
[submodule "extern/safeslinger-exchange"]
|
||||
path = extern/safeslinger-exchange
|
||||
url = https://github.com/open-keychain/exchange-android
|
||||
url = https://github.com/open-keychain/exchange-android
|
||||
ignore = dirty
|
||||
|
13
CHANGELOG
13
CHANGELOG
@ -1,3 +1,16 @@
|
||||
## 3.2beta2
|
||||
* Material design
|
||||
* Integration of QR Scanner (New permissions required)
|
||||
* Improved key creation wizard
|
||||
* Fix missing contacts after sync
|
||||
* Requires Android 4
|
||||
* Redesigned key screen
|
||||
* Simplify crypto preferences, better selection of secure ciphers
|
||||
* API: Detached signatures, free selection of signing key,...
|
||||
* Fix: Some valid keys were shown revoked or expired
|
||||
* Don't accept signatures by expired or revoked subkeys
|
||||
* Keybase.io support in advanced view
|
||||
|
||||
## 3.1.2
|
||||
* Fix key export to files (now for real)
|
||||
|
||||
|
@ -16,7 +16,7 @@ apply plugin: 'jacoco'
|
||||
dependencies {
|
||||
testCompile 'junit:junit:4.11'
|
||||
testCompile 'com.google.android:android:4.1.1.4'
|
||||
testCompile('com.squareup:fest-android:1.0.+') { exclude module: 'support-v4' }
|
||||
testCompile('com.squareup:fest-android:1.0.8') { exclude module: 'support-v4' }
|
||||
testCompile ('org.robolectric:robolectric:2.3') {
|
||||
exclude module: 'classworlds'
|
||||
exclude module: 'maven-artifact'
|
||||
|
@ -536,6 +536,12 @@ public class PgpKeyOperationTest {
|
||||
expiry, modified.getPublicKey(keyId).getUnsafeExpiryTimeForTesting().getTime() / 1000);
|
||||
Assert.assertEquals("modified key must have same flags as before",
|
||||
ring.getPublicKey(keyId).getKeyUsage(), modified.getPublicKey(keyId).getKeyUsage());
|
||||
|
||||
Date date = modified.canonicalize(new OperationLog(), 0).getPublicKey().getExpiryTime();
|
||||
Assert.assertNotNull("modified key must have an expiry date", date);
|
||||
Assert.assertEquals("modified key must have expected expiry date",
|
||||
expiry, date.getTime() / 1000);
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -3,8 +3,8 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="org.sufficientlysecure.keychain"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="31201"
|
||||
android:versionName="3.2beta1">
|
||||
android:versionCode="31202"
|
||||
android:versionName="3.2beta2">
|
||||
|
||||
<!--
|
||||
General remarks
|
||||
@ -65,6 +65,7 @@
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.READ_PROFILE" />
|
||||
<uses-permission android:name="android.permission.WRITE_PROFILE" />
|
||||
|
||||
<!-- android:allowBackup="false": Don't allow backup over adb backup or other apps! -->
|
||||
<application
|
||||
@ -715,6 +716,12 @@
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop"
|
||||
android:process=":remote_api" />
|
||||
<activity
|
||||
android:name=".remote.ui.SelectSignKeyIdActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop"
|
||||
android:process=":remote_api" />
|
||||
<activity
|
||||
android:name=".remote.ui.AppSettingsActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
|
@ -294,8 +294,9 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
||||
mKeyId = key.getKeyId();
|
||||
mKeyIdHex = KeyFormattingUtils.convertKeyIdToHex(mKeyId);
|
||||
|
||||
mRevoked = key.isMaybeRevoked();
|
||||
mExpired = key.isMaybeExpired();
|
||||
// NOTE: Dont use maybe methods for now, they can be wrong.
|
||||
mRevoked = false; //key.isMaybeRevoked();
|
||||
mExpired = false; //key.isMaybeExpired();
|
||||
mFingerprintHex = KeyFormattingUtils.convertFingerprintToHex(key.getFingerprint());
|
||||
mBitStrength = key.getBitStrength();
|
||||
mCurveOid = key.getCurveOid();
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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.operations;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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.operations;
|
||||
|
||||
import android.content.Context;
|
||||
@ -20,6 +37,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
|
||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
|
||||
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
@ -191,6 +209,9 @@ public class CertifyOperation extends BaseOperation {
|
||||
}
|
||||
|
||||
log.add(LogType.MSG_CRT_SUCCESS, 0);
|
||||
//since only verified keys are synced to contacts, we need to initiate a sync now
|
||||
ContactSyncAdapterService.requestSync();
|
||||
|
||||
return new CertifyResult(CertifyResult.RESULT_OK, log, certifyOk, certifyError, uploadOk, uploadError);
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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.operations;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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.operations;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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.operations;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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.operations;
|
||||
|
||||
import android.content.Context;
|
||||
@ -48,6 +65,7 @@ public class SignEncryptOperation extends BaseOperation {
|
||||
byte[] inputBytes = input.getBytes();
|
||||
byte[] outputBytes = null;
|
||||
|
||||
int total = inputBytes != null ? 1 : inputUris.size(), count = 0;
|
||||
ArrayList<PgpSignEncryptResult> results = new ArrayList<>();
|
||||
|
||||
do {
|
||||
@ -104,7 +122,7 @@ public class SignEncryptOperation extends BaseOperation {
|
||||
}
|
||||
|
||||
PgpSignEncryptOperation op = new PgpSignEncryptOperation(mContext, mProviderHelper,
|
||||
new ProgressScaler(), mCancelled);
|
||||
new ProgressScaler(mProgressable, 100 * count / total, 100 * ++count / total, 100), mCancelled);
|
||||
PgpSignEncryptResult result = op.execute(input, inputData, outStream);
|
||||
results.add(result);
|
||||
log.add(result, 2);
|
||||
|
@ -126,26 +126,27 @@ public class CanonicalizedPublicKey extends UncachedPublicKey {
|
||||
// the getValidSeconds method is unreliable for master keys. we need to iterate all
|
||||
// user ids, then use the most recent certification from a non-revoked user id
|
||||
if (isMasterKey()) {
|
||||
Date latestCreation = null;
|
||||
seconds = 0;
|
||||
|
||||
long masterKeyId = getKeyId();
|
||||
|
||||
Date latestCreation = null;
|
||||
for (byte[] rawUserId : getUnorderedRawUserIds()) {
|
||||
Iterator<WrappedSignature> sigs = getSignaturesForRawId(rawUserId);
|
||||
while (sigs.hasNext()) {
|
||||
WrappedSignature sig = sigs.next();
|
||||
if (sig.getKeyId() != masterKeyId) {
|
||||
continue;
|
||||
}
|
||||
if (sig.isRevocation()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// there is always a certification, so this call is safe
|
||||
WrappedSignature sig = sigs.next();
|
||||
if (latestCreation == null || latestCreation.before(sig.getCreationTime())) {
|
||||
latestCreation = sig.getCreationTime();
|
||||
seconds = sig.getKeyExpirySeconds();
|
||||
}
|
||||
|
||||
// we know a user id has at most two sigs: one certification, one revocation.
|
||||
// if the sig is a revocation, or there is another sig (which is a revocation),
|
||||
// the data in this uid is not relevant
|
||||
if (sig.isRevocation() || sigs.hasNext()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// this is our revocation, UNLESS there is a newer certificate!
|
||||
if (latestCreation == null || latestCreation.before(sig.getCreationTime())) {
|
||||
latestCreation = sig.getCreationTime();
|
||||
seconds = sig.getKeyExpirySeconds();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -18,9 +18,7 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.pgp;
|
||||
|
||||
import org.spongycastle.bcpg.HashAlgorithmTags;
|
||||
import org.spongycastle.bcpg.S2K;
|
||||
import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
|
||||
import org.spongycastle.openpgp.PGPException;
|
||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||
import org.spongycastle.openpgp.PGPPublicKey;
|
||||
@ -31,7 +29,6 @@ import org.spongycastle.openpgp.PGPSignatureGenerator;
|
||||
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
|
||||
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
||||
import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
|
||||
import org.spongycastle.openpgp.PGPUtil;
|
||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
|
||||
import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
|
||||
@ -43,13 +40,11 @@ import org.spongycastle.openpgp.operator.jcajce.NfcSyncPublicKeyDataDecryptorFac
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -287,9 +282,8 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
|
||||
// create a signatureGenerator from the supplied masterKeyId and passphrase
|
||||
PGPSignatureGenerator signatureGenerator;
|
||||
{
|
||||
// TODO: SHA256 fixed?
|
||||
PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(PGPUtil.SHA256,
|
||||
nfcSignedHash, nfcCreationTimestamp);
|
||||
PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(
|
||||
PgpConstants.CERTIFY_HASH_ALGO, nfcSignedHash, nfcCreationTimestamp);
|
||||
|
||||
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
|
||||
try {
|
||||
@ -351,9 +345,8 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
|
||||
// create a signatureGenerator from the supplied masterKeyId and passphrase
|
||||
PGPSignatureGenerator signatureGenerator;
|
||||
{
|
||||
// TODO: SHA256 fixed?
|
||||
PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(PGPUtil.SHA256,
|
||||
nfcSignedHash, nfcCreationTimestamp);
|
||||
PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(
|
||||
PgpConstants.CERTIFY_HASH_ALGO, nfcSignedHash, nfcCreationTimestamp);
|
||||
|
||||
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
|
||||
try {
|
||||
|
@ -104,8 +104,8 @@ public class OpenPgpSignatureResultBuilder {
|
||||
setUserIds(signingRing.getUnorderedUserIds());
|
||||
|
||||
// either master key is expired/revoked or this specific subkey is expired/revoked
|
||||
setKeyExpired(signingRing.isExpired() || signingKey.isMaybeExpired());
|
||||
setKeyRevoked(signingRing.isRevoked() || signingKey.isMaybeRevoked());
|
||||
setKeyExpired(signingRing.isExpired() || signingKey.isExpired());
|
||||
setKeyRevoked(signingRing.isRevoked() || signingKey.isRevoked());
|
||||
}
|
||||
|
||||
public OpenPgpSignatureResult build() {
|
||||
|
@ -53,11 +53,19 @@ public class PgpConstants {
|
||||
sPreferredHashAlgorithms.add(HashAlgorithmTags.SHA1);
|
||||
sPreferredHashAlgorithms.add(HashAlgorithmTags.RIPEMD160);
|
||||
|
||||
/*
|
||||
* Prefer ZIP
|
||||
* "ZLIB provides no benefit over ZIP and is more malleable"
|
||||
* - (OpenPGP WG mailinglist: "[openpgp] Intent to deprecate: Insecure primitives")
|
||||
* BZIP2: very slow
|
||||
*/
|
||||
sPreferredCompressionAlgorithms.add(CompressionAlgorithmTags.ZIP);
|
||||
sPreferredCompressionAlgorithms.add(CompressionAlgorithmTags.ZLIB);
|
||||
sPreferredCompressionAlgorithms.add(CompressionAlgorithmTags.BZIP2);
|
||||
sPreferredCompressionAlgorithms.add(CompressionAlgorithmTags.ZIP);
|
||||
}
|
||||
|
||||
public static final int CERTIFY_HASH_ALGO = HashAlgorithmTags.SHA256;
|
||||
|
||||
/*
|
||||
* Note: s2kcount is a number between 0 and 0xff that controls the
|
||||
* number of times to iterate the password hash before use. More
|
||||
|
@ -124,6 +124,7 @@ public class KeychainContract {
|
||||
public static final String HAS_SIGN = "has_sign";
|
||||
public static final String HAS_CERTIFY = "has_certify";
|
||||
public static final String HAS_AUTHENTICATE = "has_authenticate";
|
||||
public static final String HAS_DUPLICATE_USER_ID = "has_duplicate_user_id";
|
||||
public static final String PUBKEY_DATA = "pubkey_data";
|
||||
public static final String PRIVKEY_DATA = "privkey_data";
|
||||
|
||||
|
@ -286,7 +286,15 @@ public class KeychainProvider extends ContentProvider {
|
||||
projectionMap.put(KeyRings.EXPIRY, Tables.KEYS + "." + Keys.EXPIRY);
|
||||
projectionMap.put(KeyRings.ALGORITHM, Tables.KEYS + "." + Keys.ALGORITHM);
|
||||
projectionMap.put(KeyRings.FINGERPRINT, Tables.KEYS + "." + Keys.FINGERPRINT);
|
||||
projectionMap.put(KeyRings.USER_ID, UserPackets.USER_ID);
|
||||
projectionMap.put(KeyRings.USER_ID, Tables.USER_PACKETS + "." + UserPackets.USER_ID);
|
||||
projectionMap.put(KeyRings.HAS_DUPLICATE_USER_ID,
|
||||
"(SELECT COUNT (*) FROM " + Tables.USER_PACKETS + " AS dups"
|
||||
+ " WHERE dups." + UserPackets.MASTER_KEY_ID
|
||||
+ " != " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||
+ " AND dups." + UserPackets.RANK + " = 0"
|
||||
+ " AND dups." + UserPackets.USER_ID
|
||||
+ " = "+ Tables.USER_PACKETS + "." + UserPackets.USER_ID
|
||||
+ ") AS " + KeyRings.HAS_DUPLICATE_USER_ID);
|
||||
projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED);
|
||||
projectionMap.put(KeyRings.PUBKEY_DATA,
|
||||
Tables.KEY_RINGS_PUBLIC + "." + KeyRingData.KEY_RING_DATA
|
||||
|
@ -28,6 +28,7 @@ import android.net.Uri;
|
||||
import android.os.RemoteException;
|
||||
import android.support.v4.util.LongSparseArray;
|
||||
|
||||
import org.spongycastle.bcpg.CompressionAlgorithmTags;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||
@ -48,6 +49,7 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpConstants;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||
@ -81,15 +83,15 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/** This class contains high level methods for database access. Despite its
|
||||
/**
|
||||
* This class contains high level methods for database access. Despite its
|
||||
* name, it is not only a helper but actually the main interface for all
|
||||
* synchronous database operations.
|
||||
*
|
||||
* <p/>
|
||||
* Operations in this class write logs. These can be obtained from the
|
||||
* OperationResultParcel return values directly, but are also accumulated over
|
||||
* the lifetime of the executing ProviderHelper object unless the resetLog()
|
||||
* method is called to start a new one specifically.
|
||||
*
|
||||
*/
|
||||
public class ProviderHelper {
|
||||
private final Context mContext;
|
||||
@ -126,12 +128,13 @@ public class ProviderHelper {
|
||||
}
|
||||
|
||||
public void log(LogType type) {
|
||||
if(mLog != null) {
|
||||
if (mLog != null) {
|
||||
mLog.add(type, mIndent);
|
||||
}
|
||||
}
|
||||
|
||||
public void log(LogType type, Object... parameters) {
|
||||
if(mLog != null) {
|
||||
if (mLog != null) {
|
||||
mLog.add(type, mIndent, parameters);
|
||||
}
|
||||
}
|
||||
@ -213,7 +216,7 @@ public class ProviderHelper {
|
||||
}
|
||||
|
||||
private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() {
|
||||
Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[] {
|
||||
Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{
|
||||
KeyRings.MASTER_KEY_ID,
|
||||
// we pick from cache only information that is not easily available from keyrings
|
||||
KeyRings.HAS_ANY_SECRET, KeyRings.VERIFIED,
|
||||
@ -288,7 +291,7 @@ public class ProviderHelper {
|
||||
boolean hasAnySecret = cursor.getInt(0) > 0;
|
||||
int verified = cursor.getInt(1);
|
||||
byte[] blob = cursor.getBlob(2);
|
||||
if(secret &! hasAnySecret) {
|
||||
if (secret & !hasAnySecret) {
|
||||
throw new NotFoundException("Secret key not available!");
|
||||
}
|
||||
return secret
|
||||
@ -305,7 +308,7 @@ public class ProviderHelper {
|
||||
}
|
||||
|
||||
// bits, in order: CESA. make SURE these are correct, we will get bad log entries otherwise!!
|
||||
static final LogType LOG_TYPES_FLAG_MASTER[] = new LogType[] {
|
||||
static final LogType LOG_TYPES_FLAG_MASTER[] = new LogType[]{
|
||||
LogType.MSG_IP_MASTER_FLAGS_XXXX, LogType.MSG_IP_MASTER_FLAGS_CXXX,
|
||||
LogType.MSG_IP_MASTER_FLAGS_XEXX, LogType.MSG_IP_MASTER_FLAGS_CEXX,
|
||||
LogType.MSG_IP_MASTER_FLAGS_XXSX, LogType.MSG_IP_MASTER_FLAGS_CXSX,
|
||||
@ -317,7 +320,7 @@ public class ProviderHelper {
|
||||
};
|
||||
|
||||
// same as above, but for subkeys
|
||||
static final LogType LOG_TYPES_FLAG_SUBKEY[] = new LogType[] {
|
||||
static final LogType LOG_TYPES_FLAG_SUBKEY[] = new LogType[]{
|
||||
LogType.MSG_IP_SUBKEY_FLAGS_XXXX, LogType.MSG_IP_SUBKEY_FLAGS_CXXX,
|
||||
LogType.MSG_IP_SUBKEY_FLAGS_XEXX, LogType.MSG_IP_SUBKEY_FLAGS_CEXX,
|
||||
LogType.MSG_IP_SUBKEY_FLAGS_XXSX, LogType.MSG_IP_SUBKEY_FLAGS_CXSX,
|
||||
@ -328,8 +331,9 @@ public class ProviderHelper {
|
||||
LogType.MSG_IP_SUBKEY_FLAGS_XESA, LogType.MSG_IP_SUBKEY_FLAGS_CESA
|
||||
};
|
||||
|
||||
/** Saves an UncachedKeyRing of the public variant into the db.
|
||||
*
|
||||
/**
|
||||
* Saves an UncachedKeyRing of the public variant into the db.
|
||||
* <p/>
|
||||
* This method will not delete all previous data for this masterKeyId from the database prior
|
||||
* to inserting. All public data is effectively re-inserted, secret keyrings are left deleted
|
||||
* and need to be saved externally to be preserved past the operation.
|
||||
@ -403,7 +407,7 @@ public class ProviderHelper {
|
||||
if (key.getKeyUsage() == null) {
|
||||
log(LogType.MSG_IP_MASTER_FLAGS_UNSPECIFIED);
|
||||
} else {
|
||||
log(LOG_TYPES_FLAG_MASTER[(c?1:0) + (e?2:0) + (s?4:0) + (a?8:0)]);
|
||||
log(LOG_TYPES_FLAG_MASTER[(c ? 1 : 0) + (e ? 2 : 0) + (s ? 4 : 0) + (a ? 8 : 0)]);
|
||||
}
|
||||
} else {
|
||||
if (key.getKeyUsage() == null) {
|
||||
@ -492,7 +496,7 @@ public class ProviderHelper {
|
||||
try {
|
||||
cert.init(trustedKey);
|
||||
// if it doesn't certify, leave a note and skip
|
||||
if ( ! cert.verifySignature(masterKey, rawUserId)) {
|
||||
if (!cert.verifySignature(masterKey, rawUserId)) {
|
||||
log(LogType.MSG_IP_UID_CERT_BAD);
|
||||
continue;
|
||||
}
|
||||
@ -537,7 +541,7 @@ public class ProviderHelper {
|
||||
|
||||
ArrayList<WrappedUserAttribute> userAttributes = masterKey.getUnorderedUserAttributes();
|
||||
// Don't spam the log if there aren't even any attributes
|
||||
if ( ! userAttributes.isEmpty()) {
|
||||
if (!userAttributes.isEmpty()) {
|
||||
log(LogType.MSG_IP_UAT_CLASSIFYING);
|
||||
}
|
||||
|
||||
@ -592,7 +596,7 @@ public class ProviderHelper {
|
||||
try {
|
||||
cert.init(trustedKey);
|
||||
// if it doesn't certify, leave a note and skip
|
||||
if ( ! cert.verifySignature(masterKey, userAttribute)) {
|
||||
if (!cert.verifySignature(masterKey, userAttribute)) {
|
||||
log(LogType.MSG_IP_UAT_CERT_BAD);
|
||||
continue;
|
||||
}
|
||||
@ -660,7 +664,7 @@ public class ProviderHelper {
|
||||
selfCertsAreTrusted ? Certs.VERIFIED_SECRET : Certs.VERIFIED_SELF));
|
||||
|
||||
// iterate over signatures
|
||||
for (int i = 0; i < item.trustedCerts.size() ; i++) {
|
||||
for (int i = 0; i < item.trustedCerts.size(); i++) {
|
||||
WrappedSignature sig = item.trustedCerts.valueAt(i);
|
||||
// if it's a revocation
|
||||
if (sig.isRevocation()) {
|
||||
@ -725,7 +729,7 @@ public class ProviderHelper {
|
||||
public int compareTo(UserPacketItem o) {
|
||||
// revoked keys always come last!
|
||||
//noinspection DoubleNegation
|
||||
if ( (selfRevocation != null) != (o.selfRevocation != null)) {
|
||||
if ((selfRevocation != null) != (o.selfRevocation != null)) {
|
||||
return selfRevocation != null ? 1 : -1;
|
||||
}
|
||||
// if one is a user id, but the other isn't, the user id always comes first.
|
||||
@ -742,7 +746,8 @@ public class ProviderHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/** Saves an UncachedKeyRing of the secret variant into the db.
|
||||
/**
|
||||
* Saves an UncachedKeyRing of the secret variant into the db.
|
||||
* This method will fail if no corresponding public keyring is in the database!
|
||||
*/
|
||||
private int saveCanonicalizedSecretKeyRing(CanonicalizedSecretKeyRing keyRing) {
|
||||
@ -789,7 +794,7 @@ public class ProviderHelper {
|
||||
SecretKeyType mode = sub.getSecretKeyType();
|
||||
values.put(Keys.HAS_SECRET, mode.getNum());
|
||||
int upd = mContentResolver.update(uri, values, Keys.KEY_ID + " = ?",
|
||||
new String[]{ Long.toString(id) });
|
||||
new String[]{Long.toString(id)});
|
||||
if (upd == 1) {
|
||||
switch (mode) {
|
||||
case PASSPHRASE:
|
||||
@ -843,8 +848,9 @@ public class ProviderHelper {
|
||||
return savePublicKeyRing(keyRing, new ProgressScaler());
|
||||
}
|
||||
|
||||
/** Save a public keyring into the database.
|
||||
*
|
||||
/**
|
||||
* Save a public keyring into the database.
|
||||
* <p/>
|
||||
* This is a high level method, which takes care of merging all new information into the old and
|
||||
* keep public and secret keyrings in sync.
|
||||
*/
|
||||
@ -949,7 +955,7 @@ public class ProviderHelper {
|
||||
log(LogType.MSG_IS, KeyFormattingUtils.convertKeyIdToHex(masterKeyId));
|
||||
mIndent += 1;
|
||||
|
||||
if ( ! secretRing.isSecret()) {
|
||||
if (!secretRing.isSecret()) {
|
||||
log(LogType.MSG_IS_BAD_TYPE_PUBLIC);
|
||||
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
|
||||
}
|
||||
@ -1417,9 +1423,13 @@ public class ProviderHelper {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(KeychainContract.ApiAccounts.ACCOUNT_NAME, accSettings.getAccountName());
|
||||
values.put(KeychainContract.ApiAccounts.KEY_ID, accSettings.getKeyId());
|
||||
values.put(KeychainContract.ApiAccounts.COMPRESSION, accSettings.getCompression());
|
||||
values.put(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM, accSettings.getEncryptionAlgorithm());
|
||||
values.put(KeychainContract.ApiAccounts.HASH_ALORITHM, accSettings.getHashAlgorithm());
|
||||
|
||||
// DEPRECATED and thus hardcoded
|
||||
values.put(KeychainContract.ApiAccounts.COMPRESSION, CompressionAlgorithmTags.ZLIB);
|
||||
values.put(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM,
|
||||
PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
|
||||
values.put(KeychainContract.ApiAccounts.HASH_ALORITHM,
|
||||
PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED);
|
||||
return values;
|
||||
}
|
||||
|
||||
@ -1475,12 +1485,6 @@ public class ProviderHelper {
|
||||
cursor.getColumnIndex(KeychainContract.ApiAccounts.ACCOUNT_NAME)));
|
||||
settings.setKeyId(cursor.getLong(
|
||||
cursor.getColumnIndex(KeychainContract.ApiAccounts.KEY_ID)));
|
||||
settings.setCompression(cursor.getInt(
|
||||
cursor.getColumnIndexOrThrow(KeychainContract.ApiAccounts.COMPRESSION)));
|
||||
settings.setHashAlgorithm(cursor.getInt(
|
||||
cursor.getColumnIndexOrThrow(KeychainContract.ApiAccounts.HASH_ALORITHM)));
|
||||
settings.setEncryptionAlgorithm(cursor.getInt(
|
||||
cursor.getColumnIndexOrThrow(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM)));
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
@ -1544,26 +1548,32 @@ public class ProviderHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public void addAllowedKeyIdForApp(Uri uri, long allowedKeyId) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(ApiAllowedKeys.KEY_ID, allowedKeyId);
|
||||
mContentResolver.insert(uri, values);
|
||||
}
|
||||
|
||||
public Set<String> getAllFingerprints(Uri uri) {
|
||||
Set<String> fingerprints = new HashSet<>();
|
||||
String[] projection = new String[]{KeyRings.FINGERPRINT};
|
||||
Cursor cursor = mContentResolver.query(uri, projection, null, null, null);
|
||||
try {
|
||||
if(cursor != null) {
|
||||
int fingerprintColumn = cursor.getColumnIndex(KeyRings.FINGERPRINT);
|
||||
while(cursor.moveToNext()) {
|
||||
fingerprints.add(
|
||||
Set<String> fingerprints = new HashSet<>();
|
||||
String[] projection = new String[]{KeyRings.FINGERPRINT};
|
||||
Cursor cursor = mContentResolver.query(uri, projection, null, null, null);
|
||||
try {
|
||||
if (cursor != null) {
|
||||
int fingerprintColumn = cursor.getColumnIndex(KeyRings.FINGERPRINT);
|
||||
while (cursor.moveToNext()) {
|
||||
fingerprints.add(
|
||||
KeyFormattingUtils.convertFingerprintToHex(cursor.getBlob(fingerprintColumn))
|
||||
);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return fingerprints;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return fingerprints;
|
||||
}
|
||||
|
||||
public byte[] getApiAppSignature(String packageName) {
|
||||
Uri queryUri = ApiApps.buildByPackageNameUri(packageName);
|
||||
|
@ -17,17 +17,14 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.remote;
|
||||
|
||||
import org.spongycastle.bcpg.CompressionAlgorithmTags;
|
||||
import org.spongycastle.bcpg.HashAlgorithmTags;
|
||||
import org.spongycastle.openpgp.PGPEncryptedData;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
|
||||
/**
|
||||
* DEPRECATED API
|
||||
*/
|
||||
public class AccountSettings {
|
||||
private String mAccountName;
|
||||
private long mKeyId = Constants.key.none;
|
||||
private int mEncryptionAlgorithm;
|
||||
private int mHashAlgorithm;
|
||||
private int mCompression;
|
||||
|
||||
public AccountSettings() {
|
||||
|
||||
@ -36,11 +33,6 @@ public class AccountSettings {
|
||||
public AccountSettings(String accountName) {
|
||||
super();
|
||||
this.mAccountName = accountName;
|
||||
|
||||
// defaults:
|
||||
this.mEncryptionAlgorithm = PGPEncryptedData.AES_256;
|
||||
this.mHashAlgorithm = HashAlgorithmTags.SHA256;
|
||||
this.mCompression = CompressionAlgorithmTags.ZLIB;
|
||||
}
|
||||
|
||||
public String getAccountName() {
|
||||
@ -59,28 +51,4 @@ public class AccountSettings {
|
||||
this.mKeyId = scretKeyId;
|
||||
}
|
||||
|
||||
public int getEncryptionAlgorithm() {
|
||||
return mEncryptionAlgorithm;
|
||||
}
|
||||
|
||||
public void setEncryptionAlgorithm(int encryptionAlgorithm) {
|
||||
this.mEncryptionAlgorithm = encryptionAlgorithm;
|
||||
}
|
||||
|
||||
public int getHashAlgorithm() {
|
||||
return mHashAlgorithm;
|
||||
}
|
||||
|
||||
public void setHashAlgorithm(int hashAlgorithm) {
|
||||
this.mHashAlgorithm = hashAlgorithm;
|
||||
}
|
||||
|
||||
public int getCompression() {
|
||||
return mCompression;
|
||||
}
|
||||
|
||||
public void setCompression(int compression) {
|
||||
this.mCompression = compression;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity;
|
||||
import org.sufficientlysecure.keychain.remote.ui.SelectSignKeyIdActivity;
|
||||
import org.sufficientlysecure.keychain.ui.ImportKeysActivity;
|
||||
import org.sufficientlysecure.keychain.ui.NfcActivity;
|
||||
import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
|
||||
@ -232,8 +233,7 @@ public class OpenPgpService extends RemoteService {
|
||||
}
|
||||
|
||||
private Intent signImpl(Intent data, ParcelFileDescriptor input,
|
||||
ParcelFileDescriptor output, AccountSettings accSettings,
|
||||
boolean cleartextSign) {
|
||||
ParcelFileDescriptor output, boolean cleartextSign) {
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
try {
|
||||
@ -246,6 +246,17 @@ public class OpenPgpService extends RemoteService {
|
||||
Log.d(Constants.TAG, "nfcSignedHash: null");
|
||||
}
|
||||
|
||||
Intent signKeyIdIntent = getSignKeyMasterId(data);
|
||||
// NOTE: Fallback to return account settings (Old API)
|
||||
if (signKeyIdIntent.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)
|
||||
== OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED) {
|
||||
return signKeyIdIntent;
|
||||
}
|
||||
long signKeyId = signKeyIdIntent.getLongExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, Constants.key.none);
|
||||
if (signKeyId == Constants.key.none) {
|
||||
Log.e(Constants.TAG, "No signing key given!");
|
||||
}
|
||||
|
||||
// carefully: only set if timestamp exists
|
||||
Date nfcCreationDate = null;
|
||||
long nfcCreationTimestamp = data.getLongExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, -1);
|
||||
@ -271,7 +282,7 @@ public class OpenPgpService extends RemoteService {
|
||||
.setDetachedSignature(!cleartextSign)
|
||||
.setVersionHeader(null)
|
||||
.setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED)
|
||||
.setSignatureMasterKeyId(accSettings.getKeyId())
|
||||
.setSignatureMasterKeyId(signKeyId)
|
||||
.setNfcState(nfcSignedHash, nfcCreationDate);
|
||||
|
||||
// execute PGP operation!
|
||||
@ -336,8 +347,7 @@ public class OpenPgpService extends RemoteService {
|
||||
}
|
||||
|
||||
private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input,
|
||||
ParcelFileDescriptor output, AccountSettings accSettings,
|
||||
boolean sign) {
|
||||
ParcelFileDescriptor output, boolean sign) {
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
try {
|
||||
@ -347,6 +357,14 @@ public class OpenPgpService extends RemoteService {
|
||||
originalFilename = "";
|
||||
}
|
||||
|
||||
boolean enableCompression = data.getBooleanExtra(OpenPgpApi.EXTRA_ENABLE_COMPRESSION, true);
|
||||
int compressionId;
|
||||
if (enableCompression) {
|
||||
compressionId = CompressionAlgorithmTags.ZLIB;
|
||||
} else {
|
||||
compressionId = CompressionAlgorithmTags.UNCOMPRESSED;
|
||||
}
|
||||
|
||||
// first try to get key ids from non-ambiguous key id extra
|
||||
long[] keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);
|
||||
if (keyIds == null) {
|
||||
@ -374,14 +392,24 @@ public class OpenPgpService extends RemoteService {
|
||||
PgpSignEncryptInput pseInput = new PgpSignEncryptInput();
|
||||
pseInput.setEnableAsciiArmorOutput(asciiArmor)
|
||||
.setVersionHeader(null)
|
||||
.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED)
|
||||
.setCompressionId(compressionId)
|
||||
.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED)
|
||||
.setEncryptionMasterKeyIds(keyIds)
|
||||
.setFailOnMissingEncryptionKeyIds(true)
|
||||
.setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption
|
||||
.setFailOnMissingEncryptionKeyIds(true);
|
||||
|
||||
if (sign) {
|
||||
|
||||
Intent signKeyIdIntent = getSignKeyMasterId(data);
|
||||
// NOTE: Fallback to return account settings (Old API)
|
||||
if (signKeyIdIntent.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)
|
||||
== OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED) {
|
||||
return signKeyIdIntent;
|
||||
}
|
||||
long signKeyId = signKeyIdIntent.getLongExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, Constants.key.none);
|
||||
if (signKeyId == Constants.key.none) {
|
||||
Log.e(Constants.TAG, "No signing key given!");
|
||||
}
|
||||
|
||||
byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH);
|
||||
// carefully: only set if timestamp exists
|
||||
Date nfcCreationDate = null;
|
||||
@ -392,8 +420,9 @@ public class OpenPgpService extends RemoteService {
|
||||
|
||||
// sign and encrypt
|
||||
pseInput.setSignatureHashAlgorithm(PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED)
|
||||
.setSignatureMasterKeyId(accSettings.getKeyId())
|
||||
.setNfcState(nfcSignedHash, nfcCreationDate);
|
||||
.setSignatureMasterKeyId(signKeyId)
|
||||
.setNfcState(nfcSignedHash, nfcCreationDate)
|
||||
.setAdditionalEncryptId(signKeyId); // add sign key for encryption
|
||||
}
|
||||
|
||||
PgpSignEncryptOperation op = new PgpSignEncryptOperation(this, new ProviderHelper(getContext()), null);
|
||||
@ -455,8 +484,7 @@ public class OpenPgpService extends RemoteService {
|
||||
}
|
||||
|
||||
private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input,
|
||||
ParcelFileDescriptor output, Set<Long> allowedKeyIds,
|
||||
boolean decryptMetadataOnly) {
|
||||
ParcelFileDescriptor output, boolean decryptMetadataOnly) {
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
try {
|
||||
@ -470,6 +498,16 @@ public class OpenPgpService extends RemoteService {
|
||||
os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
|
||||
}
|
||||
|
||||
String currentPkg = getCurrentCallingPackage();
|
||||
Set<Long> allowedKeyIds;
|
||||
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 7) {
|
||||
allowedKeyIds = mProviderHelper.getAllKeyIdsForApp(
|
||||
ApiAccounts.buildBaseUri(currentPkg));
|
||||
} else {
|
||||
allowedKeyIds = mProviderHelper.getAllowedKeyIdsForApp(
|
||||
KeychainContract.ApiAllowedKeys.buildBaseUri(currentPkg));
|
||||
}
|
||||
|
||||
String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
||||
long inputLength = is.available();
|
||||
InputData inputData = new InputData(is, inputLength);
|
||||
@ -516,9 +554,16 @@ public class OpenPgpService extends RemoteService {
|
||||
}
|
||||
} else if (pgpResult.success()) {
|
||||
Intent result = new Intent();
|
||||
int resultType = OpenPgpApi.RESULT_TYPE_UNENCRYPTED_UNSIGNED;
|
||||
|
||||
OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult();
|
||||
if (signatureResult != null) {
|
||||
resultType |= OpenPgpApi.RESULT_TYPE_SIGNED;
|
||||
if (!signatureResult.isSignatureOnly()) {
|
||||
resultType |= OpenPgpApi.RESULT_TYPE_ENCRYPTED;
|
||||
}
|
||||
result.putExtra(OpenPgpApi.RESULT_TYPE, resultType);
|
||||
|
||||
result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult);
|
||||
|
||||
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 5) {
|
||||
@ -615,6 +660,27 @@ public class OpenPgpService extends RemoteService {
|
||||
}
|
||||
}
|
||||
|
||||
private Intent getSignKeyIdImpl(Intent data) {
|
||||
String preferredUserId = data.getStringExtra(OpenPgpApi.EXTRA_USER_ID);
|
||||
|
||||
Intent intent = new Intent(getBaseContext(), SelectSignKeyIdActivity.class);
|
||||
String currentPkg = getCurrentCallingPackage();
|
||||
intent.setData(KeychainContract.ApiApps.buildByPackageNameUri(currentPkg));
|
||||
intent.putExtra(SelectSignKeyIdActivity.EXTRA_USER_ID, preferredUserId);
|
||||
intent.putExtra(SelectSignKeyIdActivity.EXTRA_DATA, data);
|
||||
|
||||
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
|
||||
intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
||||
// return PendingIntent to be executed by client
|
||||
Intent result = new Intent();
|
||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
|
||||
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Intent getKeyIdsImpl(Intent data) {
|
||||
// if data already contains key ids extra GET_KEY_IDS has been executed again
|
||||
// after user interaction. Then, we just need to return the array again!
|
||||
@ -632,6 +698,35 @@ public class OpenPgpService extends RemoteService {
|
||||
}
|
||||
}
|
||||
|
||||
private Intent getSignKeyMasterId(Intent data) {
|
||||
// NOTE: Accounts are deprecated on API version >= 7
|
||||
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 7) {
|
||||
String accName = data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME);
|
||||
// if no account name is given use name "default"
|
||||
if (TextUtils.isEmpty(accName)) {
|
||||
accName = "default";
|
||||
}
|
||||
Log.d(Constants.TAG, "accName: " + accName);
|
||||
// fallback to old API
|
||||
final AccountSettings accSettings = getAccSettings(accName);
|
||||
if (accSettings == null || (accSettings.getKeyId() == Constants.key.none)) {
|
||||
return getCreateAccountIntent(data, accName);
|
||||
}
|
||||
|
||||
// NOTE: just wrapping the key id
|
||||
Intent result = new Intent();
|
||||
result.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, accSettings.getKeyId());
|
||||
return result;
|
||||
} else {
|
||||
long signKeyId = data.getLongExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, Constants.key.none);
|
||||
if (signKeyId == Constants.key.none) {
|
||||
return getSignKeyIdImpl(data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check requirements:
|
||||
* - params != null
|
||||
@ -657,12 +752,13 @@ public class OpenPgpService extends RemoteService {
|
||||
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 3
|
||||
&& data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 4
|
||||
&& data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 5
|
||||
&& data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 6) {
|
||||
&& data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 6
|
||||
&& data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 7) {
|
||||
Intent result = new Intent();
|
||||
OpenPgpError error = new OpenPgpError
|
||||
(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!\n"
|
||||
+ "used API version: " + data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) + "\n"
|
||||
+ "supported API versions: 3, 4, 5, 6");
|
||||
+ "supported API versions: 3-7");
|
||||
result.putExtra(OpenPgpApi.RESULT_ERROR, error);
|
||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||
return result;
|
||||
@ -677,16 +773,6 @@ public class OpenPgpService extends RemoteService {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getAccountName(Intent data) {
|
||||
String accName = data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME);
|
||||
// if no account name is given use name "default"
|
||||
if (TextUtils.isEmpty(accName)) {
|
||||
accName = "default";
|
||||
}
|
||||
Log.d(Constants.TAG, "accName: " + accName);
|
||||
return accName;
|
||||
}
|
||||
|
||||
// TODO: multi-threading
|
||||
private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() {
|
||||
|
||||
@ -698,41 +784,29 @@ public class OpenPgpService extends RemoteService {
|
||||
return errorResult;
|
||||
}
|
||||
|
||||
String accName = getAccountName(data);
|
||||
final AccountSettings accSettings = getAccSettings(accName);
|
||||
if (accSettings == null) {
|
||||
return getCreateAccountIntent(data, accName);
|
||||
}
|
||||
|
||||
String action = data.getAction();
|
||||
if (OpenPgpApi.ACTION_CLEARTEXT_SIGN.equals(action)) {
|
||||
return signImpl(data, input, output, accSettings, true);
|
||||
return signImpl(data, input, output, true);
|
||||
} else if (OpenPgpApi.ACTION_SIGN.equals(action)) {
|
||||
// DEPRECATED: same as ACTION_CLEARTEXT_SIGN
|
||||
Log.w(Constants.TAG, "You are using a deprecated API call, please use ACTION_CLEARTEXT_SIGN instead of ACTION_SIGN!");
|
||||
return signImpl(data, input, output, accSettings, true);
|
||||
return signImpl(data, input, output, true);
|
||||
} else if (OpenPgpApi.ACTION_DETACHED_SIGN.equals(action)) {
|
||||
return signImpl(data, input, output, accSettings, false);
|
||||
return signImpl(data, input, output, false);
|
||||
} else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) {
|
||||
return encryptAndSignImpl(data, input, output, accSettings, false);
|
||||
return encryptAndSignImpl(data, input, output, false);
|
||||
} else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) {
|
||||
return encryptAndSignImpl(data, input, output, accSettings, true);
|
||||
return encryptAndSignImpl(data, input, output, true);
|
||||
} else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) {
|
||||
String currentPkg = getCurrentCallingPackage();
|
||||
Set<Long> allowedKeyIds =
|
||||
mProviderHelper.getAllKeyIdsForApp(
|
||||
ApiAccounts.buildBaseUri(currentPkg));
|
||||
return decryptAndVerifyImpl(data, input, output, allowedKeyIds, false);
|
||||
return decryptAndVerifyImpl(data, input, output, false);
|
||||
} else if (OpenPgpApi.ACTION_DECRYPT_METADATA.equals(action)) {
|
||||
String currentPkg = getCurrentCallingPackage();
|
||||
Set<Long> allowedKeyIds =
|
||||
mProviderHelper.getAllKeyIdsForApp(
|
||||
ApiAccounts.buildBaseUri(currentPkg));
|
||||
return decryptAndVerifyImpl(data, input, output, allowedKeyIds, true);
|
||||
} else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) {
|
||||
return getKeyImpl(data);
|
||||
return decryptAndVerifyImpl(data, input, output, true);
|
||||
} else if (OpenPgpApi.ACTION_GET_SIGN_KEY_ID.equals(action)) {
|
||||
return getSignKeyIdImpl(data);
|
||||
} else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) {
|
||||
return getKeyIdsImpl(data);
|
||||
} else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) {
|
||||
return getKeyImpl(data);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2013-2015 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
|
||||
@ -154,9 +154,9 @@ public abstract class RemoteService extends Service {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves AccountSettings from database for the application calling this remote service
|
||||
* DEPRECATED API
|
||||
*
|
||||
* @return
|
||||
* Retrieves AccountSettings from database for the application calling this remote service
|
||||
*/
|
||||
protected AccountSettings getAccSettings(String accountName) {
|
||||
String currentPkg = getCurrentCallingPackage();
|
||||
@ -164,11 +164,12 @@ public abstract class RemoteService extends Service {
|
||||
|
||||
Uri uri = KeychainContract.ApiAccounts.buildByPackageAndAccountUri(currentPkg, accountName);
|
||||
|
||||
AccountSettings settings = mProviderHelper.getApiAccountSettings(uri);
|
||||
|
||||
return settings; // can be null!
|
||||
return mProviderHelper.getApiAccountSettings(uri); // can be null!
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated API
|
||||
*/
|
||||
protected Intent getCreateAccountIntent(Intent data, String accountName) {
|
||||
String packageName = getCurrentCallingPackage();
|
||||
Log.d(Constants.TAG, "getCreateAccountIntent accountName: " + accountName);
|
||||
|
@ -89,9 +89,10 @@ public class AccountSettingsActivity extends BaseActivity {
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_account_settings_delete:
|
||||
case R.id.menu_account_settings_delete: {
|
||||
deleteAccount();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
@ -24,22 +24,17 @@ import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.remote.AccountSettings;
|
||||
import org.sufficientlysecure.keychain.ui.CreateKeyActivity;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
|
||||
import org.sufficientlysecure.keychain.ui.widget.SignKeySpinner;
|
||||
import org.sufficientlysecure.keychain.util.AlgorithmNames;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
public class AccountSettingsFragment extends Fragment {
|
||||
@ -51,17 +46,10 @@ public class AccountSettingsFragment extends Fragment {
|
||||
|
||||
// view
|
||||
private TextView mAccNameView;
|
||||
private Spinner mEncryptionAlgorithm;
|
||||
private Spinner mHashAlgorithm;
|
||||
private Spinner mCompression;
|
||||
|
||||
private SignKeySpinner mSelectKeySpinner;
|
||||
private View mCreateKeyButton;
|
||||
|
||||
KeyValueSpinnerAdapter mEncryptionAdapter;
|
||||
KeyValueSpinnerAdapter mHashAdapter;
|
||||
KeyValueSpinnerAdapter mCompressionAdapter;
|
||||
|
||||
public AccountSettings getAccSettings() {
|
||||
return mAccSettings;
|
||||
}
|
||||
@ -71,10 +59,6 @@ public class AccountSettingsFragment extends Fragment {
|
||||
|
||||
mAccNameView.setText(accountSettings.getAccountName());
|
||||
mSelectKeySpinner.setSelectedKeyId(accountSettings.getKeyId());
|
||||
mEncryptionAlgorithm.setSelection(mEncryptionAdapter.getPosition(accountSettings
|
||||
.getEncryptionAlgorithm()));
|
||||
mHashAlgorithm.setSelection(mHashAdapter.getPosition(accountSettings.getHashAlgorithm()));
|
||||
mCompression.setSelection(mCompressionAdapter.getPosition(accountSettings.getCompression()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,10 +74,6 @@ public class AccountSettingsFragment extends Fragment {
|
||||
private void initView(View view) {
|
||||
mSelectKeySpinner = (SignKeySpinner) view.findViewById(R.id.api_account_settings_key_spinner);
|
||||
mAccNameView = (TextView) view.findViewById(R.id.api_account_settings_acc_name);
|
||||
mEncryptionAlgorithm = (Spinner) view
|
||||
.findViewById(R.id.api_account_settings_encryption_algorithm);
|
||||
mHashAlgorithm = (Spinner) view.findViewById(R.id.api_account_settings_hash_algorithm);
|
||||
mCompression = (Spinner) view.findViewById(R.id.api_account_settings_compression);
|
||||
mCreateKeyButton = view.findViewById(R.id.api_account_settings_create_key);
|
||||
|
||||
mSelectKeySpinner.setOnKeyChangedListener(new KeySpinner.OnKeyChangedListener() {
|
||||
@ -109,52 +89,6 @@ public class AccountSettingsFragment extends Fragment {
|
||||
createKey();
|
||||
}
|
||||
});
|
||||
|
||||
AlgorithmNames algorithmNames = new AlgorithmNames(getActivity());
|
||||
|
||||
mEncryptionAdapter = new KeyValueSpinnerAdapter(getActivity(),
|
||||
algorithmNames.getEncryptionNames());
|
||||
mEncryptionAlgorithm.setAdapter(mEncryptionAdapter);
|
||||
mEncryptionAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
mAccSettings.setEncryptionAlgorithm((int) id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
|
||||
mHashAdapter = new KeyValueSpinnerAdapter(getActivity(), algorithmNames.getHashNames());
|
||||
mHashAlgorithm.setAdapter(mHashAdapter);
|
||||
mHashAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
mAccSettings.setHashAlgorithm((int) id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
|
||||
mCompressionAdapter = new KeyValueSpinnerAdapter(getActivity(),
|
||||
algorithmNames.getCompressionNames());
|
||||
mCompression.setAdapter(mCompressionAdapter);
|
||||
mCompression.setOnItemSelectedListener(new OnItemSelectedListener() {
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
mAccSettings.setCompression((int) id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createKey() {
|
||||
@ -172,8 +106,8 @@ public class AccountSettingsFragment extends Fragment {
|
||||
case REQUEST_CODE_CREATE_KEY: {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
|
||||
SaveKeyringResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
|
||||
mSelectKeySpinner.setSelectedKeyId(result.mRingMasterKeyId);
|
||||
EditKeyResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
|
||||
mSelectKeySpinner.setSelectedKeyId(result.mMasterKeyId);
|
||||
} else {
|
||||
Log.e(Constants.TAG, "missing result!");
|
||||
}
|
||||
|
@ -205,6 +205,8 @@ public class AppSettingsAllowedKeysListFragment extends ListFragmentWorkaround i
|
||||
KeyRings.HAS_ENCRYPT,
|
||||
KeyRings.VERIFIED,
|
||||
KeyRings.HAS_ANY_SECRET,
|
||||
KeyRings.HAS_DUPLICATE_USER_ID,
|
||||
KeyRings.CREATION,
|
||||
};
|
||||
|
||||
String inMasterKeyList = null;
|
||||
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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.remote.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.openintents.openpgp.util.OpenPgpApi;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.ui.BaseActivity;
|
||||
import org.sufficientlysecure.keychain.ui.CreateKeyActivity;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
public class SelectSignKeyIdActivity extends BaseActivity {
|
||||
|
||||
public static final String EXTRA_USER_ID = OpenPgpApi.EXTRA_USER_ID;
|
||||
public static final String EXTRA_DATA = "data";
|
||||
|
||||
private static final int REQUEST_CODE_CREATE_KEY = 0x00008884;
|
||||
|
||||
private Uri mAppUri;
|
||||
private String mPreferredUserId;
|
||||
|
||||
private SelectSignKeyIdListFragment mListFragment;
|
||||
private TextView mActionCreateKey;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Inflate a "Done" custom action bar
|
||||
setFullScreenDialogClose(
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
mActionCreateKey = (TextView) findViewById(R.id.api_select_sign_key_create_key);
|
||||
mActionCreateKey.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
createKey(mPreferredUserId);
|
||||
}
|
||||
});
|
||||
|
||||
Intent intent = getIntent();
|
||||
mAppUri = intent.getData();
|
||||
mPreferredUserId = intent.getStringExtra(EXTRA_USER_ID);
|
||||
Intent data = intent.getParcelableExtra(EXTRA_DATA);
|
||||
if (mAppUri == null) {
|
||||
Log.e(Constants.TAG, "Intent data missing. Should be Uri of app!");
|
||||
finish();
|
||||
return;
|
||||
} else {
|
||||
Log.d(Constants.TAG, "uri: " + mAppUri);
|
||||
startListFragments(savedInstanceState, mAppUri, data);
|
||||
}
|
||||
}
|
||||
|
||||
private void createKey(String userId) {
|
||||
String[] userIdSplit = KeyRing.splitUserId(userId);
|
||||
|
||||
Intent intent = new Intent(this, CreateKeyActivity.class);
|
||||
intent.putExtra(CreateKeyActivity.EXTRA_NAME, userIdSplit[0]);
|
||||
intent.putExtra(CreateKeyActivity.EXTRA_EMAIL, userIdSplit[1]);
|
||||
startActivityForResult(intent, REQUEST_CODE_CREATE_KEY);
|
||||
}
|
||||
|
||||
private void startListFragments(Bundle savedInstanceState, Uri dataUri, Intent data) {
|
||||
// However, if we're being restored from a previous state,
|
||||
// then we don't need to do anything and should return or else
|
||||
// we could end up with overlapping fragments.
|
||||
if (savedInstanceState != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create an instance of the fragments
|
||||
mListFragment = SelectSignKeyIdListFragment.newInstance(dataUri, data);
|
||||
// Add the fragment to the 'fragment_container' FrameLayout
|
||||
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.api_select_sign_key_list_fragment, mListFragment)
|
||||
.commitAllowingStateLoss();
|
||||
// do it immediately!
|
||||
getSupportFragmentManager().executePendingTransactions();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.api_select_sign_key_activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
// if a result has been returned, display a notify
|
||||
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
|
||||
OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
|
||||
result.createNotify(this).show();
|
||||
}
|
||||
|
||||
switch (requestCode) {
|
||||
case REQUEST_CODE_CREATE_KEY: {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
|
||||
// TODO: select?
|
||||
// EditKeyResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
|
||||
// mSelectKeySpinner.setSelectedKeyId(result.mMasterKeyId);
|
||||
} else {
|
||||
Log.e(Constants.TAG, "missing result!");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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.remote.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
|
||||
import org.openintents.openpgp.util.OpenPgpApi;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.widget.FixedListView;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
public class SelectSignKeyIdListFragment extends ListFragmentWorkaround implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||
private static final String ARG_DATA_URI = "uri";
|
||||
public static final String ARG_DATA = "data";
|
||||
|
||||
private SelectKeyCursorAdapter mAdapter;
|
||||
private ProviderHelper mProviderHelper;
|
||||
|
||||
private Uri mDataUri;
|
||||
|
||||
/**
|
||||
* Creates new instance of this fragment
|
||||
*/
|
||||
public static SelectSignKeyIdListFragment newInstance(Uri dataUri, Intent data) {
|
||||
SelectSignKeyIdListFragment frag = new SelectSignKeyIdListFragment();
|
||||
Bundle args = new Bundle();
|
||||
|
||||
args.putParcelable(ARG_DATA_URI, dataUri);
|
||||
args.putParcelable(ARG_DATA, data);
|
||||
|
||||
frag.setArguments(args);
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mProviderHelper = new ProviderHelper(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View layout = super.onCreateView(inflater, container,
|
||||
savedInstanceState);
|
||||
ListView lv = (ListView) layout.findViewById(android.R.id.list);
|
||||
ViewGroup parent = (ViewGroup) lv.getParent();
|
||||
|
||||
/*
|
||||
* http://stackoverflow.com/a/15880684
|
||||
* Remove ListView and add FixedListView in its place.
|
||||
* This is done here programatically to be still able to use the progressBar of ListFragment.
|
||||
*
|
||||
* We want FixedListView to be able to put this ListFragment inside a ScrollView
|
||||
*/
|
||||
int lvIndex = parent.indexOfChild(lv);
|
||||
parent.removeViewAt(lvIndex);
|
||||
FixedListView newLv = new FixedListView(getActivity());
|
||||
newLv.setId(android.R.id.list);
|
||||
parent.addView(newLv, lvIndex, lv.getLayoutParams());
|
||||
return layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define Adapter and Loader on create of Activity
|
||||
*/
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
mDataUri = getArguments().getParcelable(ARG_DATA_URI);
|
||||
final Intent resultData = getArguments().getParcelable(ARG_DATA);
|
||||
|
||||
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
|
||||
getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
long masterKeyId = mAdapter.getMasterKeyId(position);
|
||||
|
||||
Uri allowedKeysUri = mDataUri.buildUpon().appendPath(KeychainContract.PATH_ALLOWED_KEYS).build();
|
||||
Log.d(Constants.TAG, "allowedKeysUri: " + allowedKeysUri);
|
||||
mProviderHelper.addAllowedKeyIdForApp(allowedKeysUri, masterKeyId);
|
||||
|
||||
resultData.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, masterKeyId);
|
||||
|
||||
getActivity().setResult(Activity.RESULT_OK, resultData);
|
||||
getActivity().finish();
|
||||
}
|
||||
});
|
||||
|
||||
// Give some text to display if there is no data. In a real
|
||||
// application this would come from a resource.
|
||||
setEmptyText(getString(R.string.list_empty));
|
||||
|
||||
mAdapter = new SecretKeyCursorAdapter(getActivity(), null, 0, getListView());
|
||||
|
||||
setListAdapter(mAdapter);
|
||||
|
||||
// Start out with a progress indicator.
|
||||
setListShown(false);
|
||||
|
||||
// Prepare the loader. Either re-connect with an existing one,
|
||||
// or start a new one.
|
||||
getLoaderManager().initLoader(0, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
|
||||
|
||||
// These are the rows that we will retrieve.
|
||||
String[] projection = new String[]{
|
||||
KeyRings._ID,
|
||||
KeyRings.MASTER_KEY_ID,
|
||||
KeyRings.USER_ID,
|
||||
KeyRings.IS_EXPIRED,
|
||||
KeyRings.IS_REVOKED,
|
||||
KeyRings.HAS_ENCRYPT,
|
||||
KeyRings.VERIFIED,
|
||||
KeyRings.HAS_ANY_SECRET,
|
||||
KeyRings.HAS_DUPLICATE_USER_ID,
|
||||
KeyRings.CREATION,
|
||||
};
|
||||
|
||||
String selection = KeyRings.HAS_ANY_SECRET + " != 0";
|
||||
|
||||
String orderBy = KeyRings.USER_ID + " ASC";
|
||||
// Now create and return a CursorLoader that will take care of
|
||||
// creating a Cursor for the data being displayed.
|
||||
return new CursorLoader(getActivity(), baseUri, projection, selection, null, orderBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||
// Swap the new cursor in. (The framework will take care of closing the
|
||||
// old cursor once we return.)
|
||||
mAdapter.swapCursor(data);
|
||||
|
||||
// The list should now be shown.
|
||||
if (isResumed()) {
|
||||
setListShown(true);
|
||||
} else {
|
||||
setListShownNoAnimation(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) {
|
||||
// This is called when the last Cursor provided to onLoadFinished()
|
||||
// above is about to be closed. We need to make sure we are no
|
||||
// longer using it.
|
||||
mAdapter.swapCursor(null);
|
||||
}
|
||||
|
||||
private class SecretKeyCursorAdapter extends SelectKeyCursorAdapter {
|
||||
|
||||
public SecretKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView) {
|
||||
super(context, c, flags, listView);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initIndex(Cursor cursor) {
|
||||
super.initIndex(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
super.bindView(view, context, cursor);
|
||||
ViewHolderItem h = (ViewHolderItem) view.getTag();
|
||||
|
||||
h.selected.setVisibility(View.GONE);
|
||||
|
||||
boolean enabled = false;
|
||||
if ((Boolean) h.statusIcon.getTag()) {
|
||||
h.statusIcon.setVisibility(View.GONE);
|
||||
enabled = true;
|
||||
}
|
||||
h.setEnabled(enabled);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -68,6 +68,7 @@ import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus;
|
||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||
import org.sufficientlysecure.keychain.util.InputData;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
@ -134,8 +135,21 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
public static final String SOURCE = "source";
|
||||
|
||||
// possible targets:
|
||||
public static final int IO_BYTES = 1;
|
||||
public static final int IO_URI = 2;
|
||||
public static enum IOType {
|
||||
UNKNOWN,
|
||||
BYTES,
|
||||
URI;
|
||||
|
||||
private static final IOType[] values = values();
|
||||
|
||||
public static IOType fromInt(int n) {
|
||||
if(n < 0 || n >= values.length) {
|
||||
return UNKNOWN;
|
||||
} else {
|
||||
return values[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// encrypt
|
||||
public static final String ENCRYPT_DECRYPT_INPUT_URI = "input_uri";
|
||||
@ -252,7 +266,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
CertifyResult result = op.certify(parcel, keyServerUri);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -267,7 +281,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
}
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -296,7 +310,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
|
||||
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, decryptVerifyResult);
|
||||
sendMessageToHandler(MessageStatus.OKAY, decryptVerifyResult);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
@ -357,7 +371,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
}
|
||||
|
||||
// kind of awkward, but this whole class wants to pull bytes out of “data”
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES);
|
||||
data.putInt(KeychainIntentService.TARGET, IOType.BYTES.ordinal());
|
||||
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, messageBytes);
|
||||
|
||||
InputData inputData = createDecryptInputData(data);
|
||||
@ -394,7 +408,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
resultData.putString(KeychainIntentServiceHandler.KEYBASE_PROOF_URL, prover.getProofUrl());
|
||||
resultData.putString(KeychainIntentServiceHandler.KEYBASE_PRESENCE_URL, prover.getPresenceUrl());
|
||||
resultData.putString(KeychainIntentServiceHandler.KEYBASE_PRESENCE_LABEL, prover.getPresenceLabel());
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
|
||||
sendMessageToHandler(MessageStatus.OKAY, resultData);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
@ -437,7 +451,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
|
||||
Log.logDebugBundle(resultData, "resultData");
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
|
||||
sendMessageToHandler(MessageStatus.OKAY, resultData);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
@ -455,7 +469,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
DeleteResult result = op.execute(masterKeyIds, isSecret);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -470,7 +484,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
EditKeyResult result = op.execute(saveParcel, passphrase);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -484,7 +498,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
PromoteKeyResult result = op.execute(keyRingId);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -508,7 +522,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
}
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -529,7 +543,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
: importExportOperation.importKeyRings(cache, keyServer);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
||||
|
||||
break;
|
||||
|
||||
@ -545,7 +559,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
SignEncryptResult result = op.execute(inputParcel);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -568,7 +582,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
throw new PgpGeneralException("Unable to export key to selected server");
|
||||
}
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY);
|
||||
sendMessageToHandler(MessageStatus.OKAY);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
@ -590,7 +604,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
private void sendProofError(String msg) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KeychainIntentServiceHandler.DATA_ERROR, msg);
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, bundle);
|
||||
sendMessageToHandler(MessageStatus.OKAY, bundle);
|
||||
}
|
||||
|
||||
private void sendErrorToHandler(Exception e) {
|
||||
@ -607,14 +621,14 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
|
||||
Bundle data = new Bundle();
|
||||
data.putString(KeychainIntentServiceHandler.DATA_ERROR, message);
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_EXCEPTION, null, data);
|
||||
sendMessageToHandler(MessageStatus.EXCEPTION, null, data);
|
||||
}
|
||||
|
||||
private void sendMessageToHandler(Integer arg1, Integer arg2, Bundle data) {
|
||||
private void sendMessageToHandler(MessageStatus status, Integer arg2, Bundle data) {
|
||||
|
||||
Message msg = Message.obtain();
|
||||
assert msg != null;
|
||||
msg.arg1 = arg1;
|
||||
msg.arg1 = status.ordinal();
|
||||
if (arg2 != null) {
|
||||
msg.arg2 = arg2;
|
||||
}
|
||||
@ -631,18 +645,18 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMessageToHandler(Integer arg1, OperationResult data) {
|
||||
private void sendMessageToHandler(MessageStatus status, OperationResult data) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(OperationResult.EXTRA_RESULT, data);
|
||||
sendMessageToHandler(arg1, null, bundle);
|
||||
sendMessageToHandler(status, null, bundle);
|
||||
}
|
||||
|
||||
private void sendMessageToHandler(Integer arg1, Bundle data) {
|
||||
sendMessageToHandler(arg1, null, data);
|
||||
private void sendMessageToHandler(MessageStatus status, Bundle data) {
|
||||
sendMessageToHandler(status, null, data);
|
||||
}
|
||||
|
||||
private void sendMessageToHandler(Integer arg1) {
|
||||
sendMessageToHandler(arg1, null, null);
|
||||
private void sendMessageToHandler(MessageStatus status) {
|
||||
sendMessageToHandler(status, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -659,7 +673,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
data.putInt(KeychainIntentServiceHandler.DATA_PROGRESS, progress);
|
||||
data.putInt(KeychainIntentServiceHandler.DATA_PROGRESS_MAX, max);
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_UPDATE_PROGRESS, null, data);
|
||||
sendMessageToHandler(MessageStatus.UPDATE_PROGRESS, null, data);
|
||||
}
|
||||
|
||||
public void setProgress(int resourceId, int progress, int max) {
|
||||
@ -672,7 +686,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
|
||||
@Override
|
||||
public void setPreventCancel() {
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_PREVENT_CANCEL);
|
||||
sendMessageToHandler(MessageStatus.PREVENT_CANCEL);
|
||||
}
|
||||
|
||||
private InputData createDecryptInputData(Bundle data) throws IOException, PgpGeneralException {
|
||||
@ -681,35 +695,37 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
|
||||
private InputData createCryptInputData(Bundle data, String bytesName) throws PgpGeneralException, IOException {
|
||||
int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET);
|
||||
switch (source) {
|
||||
case IO_BYTES: /* encrypting bytes directly */
|
||||
IOType type = IOType.fromInt(source);
|
||||
switch (type) {
|
||||
case BYTES: /* encrypting bytes directly */
|
||||
byte[] bytes = data.getByteArray(bytesName);
|
||||
return new InputData(new ByteArrayInputStream(bytes), bytes.length);
|
||||
|
||||
case IO_URI: /* encrypting content uri */
|
||||
case URI: /* encrypting content uri */
|
||||
Uri providerUri = data.getParcelable(ENCRYPT_DECRYPT_INPUT_URI);
|
||||
|
||||
// InputStream
|
||||
return new InputData(getContentResolver().openInputStream(providerUri), FileHelper.getFileSize(this, providerUri, 0));
|
||||
|
||||
default:
|
||||
throw new PgpGeneralException("No target choosen!");
|
||||
throw new PgpGeneralException("No target chosen!");
|
||||
}
|
||||
}
|
||||
|
||||
private OutputStream createCryptOutputStream(Bundle data) throws PgpGeneralException, FileNotFoundException {
|
||||
int target = data.getInt(TARGET);
|
||||
switch (target) {
|
||||
case IO_BYTES:
|
||||
IOType type = IOType.fromInt(target);
|
||||
switch (type) {
|
||||
case BYTES:
|
||||
return new ByteArrayOutputStream();
|
||||
|
||||
case IO_URI:
|
||||
case URI:
|
||||
Uri providerUri = data.getParcelable(ENCRYPT_DECRYPT_OUTPUT_URI);
|
||||
|
||||
return getContentResolver().openOutputStream(providerUri);
|
||||
|
||||
default:
|
||||
throw new PgpGeneralException("No target choosen!");
|
||||
throw new PgpGeneralException("No target chosen!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -719,12 +735,13 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
|
||||
private void finalizeCryptOutputStream(Bundle data, Bundle resultData, OutputStream outStream, String bytesName) {
|
||||
int target = data.getInt(TARGET);
|
||||
switch (target) {
|
||||
case IO_BYTES:
|
||||
IOType type = IOType.fromInt(target);
|
||||
switch (type) {
|
||||
case BYTES:
|
||||
byte output[] = ((ByteArrayOutputStream) outStream).toByteArray();
|
||||
resultData.putByteArray(bytesName, output);
|
||||
break;
|
||||
case IO_URI:
|
||||
case URI:
|
||||
// nothing, output was written, just send okay and verification bundle
|
||||
|
||||
break;
|
||||
|
@ -32,11 +32,25 @@ import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
public class KeychainIntentServiceHandler extends Handler {
|
||||
|
||||
// possible messages send from this service to handler on ui
|
||||
public static final int MESSAGE_OKAY = 1;
|
||||
public static final int MESSAGE_EXCEPTION = 2;
|
||||
public static final int MESSAGE_UPDATE_PROGRESS = 3;
|
||||
public static final int MESSAGE_PREVENT_CANCEL = 4;
|
||||
// possible messages sent from this service to handler on ui
|
||||
public static enum MessageStatus{
|
||||
UNKNOWN,
|
||||
OKAY,
|
||||
EXCEPTION,
|
||||
UPDATE_PROGRESS,
|
||||
PREVENT_CANCEL;
|
||||
|
||||
private static final MessageStatus[] values = values();
|
||||
|
||||
public static MessageStatus fromInt(int n)
|
||||
{
|
||||
if(n < 0 || n >= values.length) {
|
||||
return UNKNOWN;
|
||||
} else {
|
||||
return values[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// possible data keys for messages
|
||||
public static final String DATA_ERROR = "error";
|
||||
@ -103,13 +117,14 @@ public class KeychainIntentServiceHandler extends Handler {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message.arg1) {
|
||||
case MESSAGE_OKAY:
|
||||
MessageStatus status = MessageStatus.fromInt(message.arg1);
|
||||
switch (status) {
|
||||
case OKAY:
|
||||
mProgressDialogFragment.dismissAllowingStateLoss();
|
||||
|
||||
break;
|
||||
|
||||
case MESSAGE_EXCEPTION:
|
||||
case EXCEPTION:
|
||||
mProgressDialogFragment.dismissAllowingStateLoss();
|
||||
|
||||
// show error from service
|
||||
@ -121,7 +136,7 @@ public class KeychainIntentServiceHandler extends Handler {
|
||||
|
||||
break;
|
||||
|
||||
case MESSAGE_UPDATE_PROGRESS:
|
||||
case UPDATE_PROGRESS:
|
||||
if (data.containsKey(DATA_PROGRESS) && data.containsKey(DATA_PROGRESS_MAX)) {
|
||||
|
||||
// update progress from service
|
||||
@ -139,7 +154,7 @@ public class KeychainIntentServiceHandler extends Handler {
|
||||
|
||||
break;
|
||||
|
||||
case MESSAGE_PREVENT_CANCEL:
|
||||
case PREVENT_CANCEL:
|
||||
mProgressDialogFragment.setPreventCancel(true);
|
||||
break;
|
||||
|
||||
|
@ -394,7 +394,7 @@ public class CertifyKeyFragment extends LoaderFragment
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
Bundle data = message.getData();
|
||||
CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
|
||||
|
||||
|
@ -57,7 +57,7 @@ public class ConsolidateDialogActivity extends FragmentActivity {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
/* don't care about the results (for now?)
|
||||
|
||||
// get returned data bundle
|
||||
|
@ -214,7 +214,7 @@ public class CreateKeyFinalFragment extends Fragment {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
if (returnData == null) {
|
||||
@ -284,7 +284,7 @@ public class CreateKeyFinalFragment extends Fragment {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
// TODO: upload operation needs a result!
|
||||
// TODO: then combine these results
|
||||
//if (result.getResult() == OperationResultParcel.RESULT_OK) {
|
||||
|
@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentService.IOType;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
@ -182,10 +183,10 @@ public class DecryptFilesFragment extends DecryptFragment {
|
||||
// data
|
||||
Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri);
|
||||
|
||||
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URI);
|
||||
data.putInt(KeychainIntentService.SOURCE, IOType.URI.ordinal());
|
||||
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_INPUT_URI, mInputUri);
|
||||
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URI);
|
||||
data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal());
|
||||
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri);
|
||||
|
||||
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
|
||||
@ -200,7 +201,7 @@ public class DecryptFilesFragment extends DecryptFragment {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
|
||||
@ -256,10 +257,10 @@ public class DecryptFilesFragment extends DecryptFragment {
|
||||
// data
|
||||
Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri);
|
||||
|
||||
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URI);
|
||||
data.putInt(KeychainIntentService.SOURCE, IOType.URI.ordinal());
|
||||
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_INPUT_URI, mInputUri);
|
||||
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URI);
|
||||
data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal());
|
||||
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri);
|
||||
|
||||
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
|
||||
@ -274,7 +275,7 @@ public class DecryptFilesFragment extends DecryptFragment {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
|
||||
|
@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentService.IOType;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
@ -158,7 +159,7 @@ public class DecryptTextFragment extends DecryptFragment {
|
||||
intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY);
|
||||
|
||||
// data
|
||||
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES);
|
||||
data.putInt(KeychainIntentService.TARGET, IOType.BYTES.ordinal());
|
||||
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes());
|
||||
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
|
||||
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
|
||||
@ -172,7 +173,7 @@ public class DecryptTextFragment extends DecryptFragment {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
|
||||
|
@ -605,7 +605,7 @@ public class EditKeyFragment extends LoaderFragment implements
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
|
@ -128,7 +128,7 @@ public abstract class EncryptActivity extends BaseActivity {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
SignEncryptResult result =
|
||||
message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT);
|
||||
|
||||
|
@ -36,7 +36,6 @@ import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
import org.sufficientlysecure.keychain.util.ShareHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -177,22 +176,36 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEncryptSuccess(SignEncryptResult result) {
|
||||
public void onEncryptSuccess(final SignEncryptResult result) {
|
||||
if (mDeleteAfterEncrypt) {
|
||||
for (Uri inputUri : mInputUris) {
|
||||
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(inputUri);
|
||||
deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog");
|
||||
}
|
||||
final Uri[] inputUris = mInputUris.toArray(new Uri[mInputUris.size()]);
|
||||
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(inputUris);
|
||||
deleteFileDialog.setOnDeletedListener(new DeleteFileDialogFragment.OnDeletedListener() {
|
||||
|
||||
@Override
|
||||
public void onDeleted() {
|
||||
if (mShareAfterEncrypt) {
|
||||
// Share encrypted message/file
|
||||
startActivity(sendWithChooserExcludingEncrypt());
|
||||
} else {
|
||||
// Save encrypted file
|
||||
result.createNotify(EncryptFilesActivity.this).show();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog");
|
||||
|
||||
mInputUris.clear();
|
||||
notifyUpdate();
|
||||
}
|
||||
|
||||
if (mShareAfterEncrypt) {
|
||||
// Share encrypted message/file
|
||||
startActivity(sendWithChooserExcludingEncrypt());
|
||||
} else {
|
||||
// Save encrypted file
|
||||
result.createNotify(EncryptFilesActivity.this).show();
|
||||
if (mShareAfterEncrypt) {
|
||||
// Share encrypted message/file
|
||||
startActivity(sendWithChooserExcludingEncrypt());
|
||||
} else {
|
||||
// Save encrypted file
|
||||
result.createNotify(EncryptFilesActivity.this).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,6 +114,13 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEncryptInterface.getInputUris().contains(inputUri)) {
|
||||
Notify.showNotify(getActivity(),
|
||||
getActivity().getString(R.string.error_file_added_already, FileHelper.getFilename(getActivity(), inputUri)),
|
||||
Notify.Style.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
mEncryptInterface.getInputUris().add(inputUri);
|
||||
mEncryptInterface.notifyUpdate();
|
||||
mSelectedFiles.requestFocus();
|
||||
|
@ -302,7 +302,7 @@ public class ImportKeysActivity extends BaseActivity {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
if (returnData == null) {
|
||||
|
@ -222,7 +222,7 @@ public class ImportKeysProxyActivity extends FragmentActivity {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
if (returnData == null) {
|
||||
|
@ -270,7 +270,8 @@ public class KeyListFragment extends LoaderFragment
|
||||
KeyRings.IS_REVOKED,
|
||||
KeyRings.IS_EXPIRED,
|
||||
KeyRings.VERIFIED,
|
||||
KeyRings.HAS_ANY_SECRET
|
||||
KeyRings.HAS_ANY_SECRET,
|
||||
KeyRings.HAS_DUPLICATE_USER_ID,
|
||||
};
|
||||
|
||||
static final int INDEX_MASTER_KEY_ID = 1;
|
||||
@ -279,6 +280,7 @@ public class KeyListFragment extends LoaderFragment
|
||||
static final int INDEX_IS_EXPIRED = 4;
|
||||
static final int INDEX_VERIFIED = 5;
|
||||
static final int INDEX_HAS_ANY_SECRET = 6;
|
||||
static final int INDEX_HAS_DUPLICATE_USER_ID = 7;
|
||||
|
||||
static final String ORDER =
|
||||
KeyRings.HAS_ANY_SECRET + " DESC, UPPER(" + KeyRings.USER_ID + ") ASC";
|
||||
@ -552,7 +554,7 @@ public class KeyListFragment extends LoaderFragment
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
if (returnData == null) {
|
||||
@ -707,6 +709,7 @@ public class KeyListFragment extends LoaderFragment
|
||||
boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
|
||||
boolean isExpired = cursor.getInt(INDEX_IS_EXPIRED) != 0;
|
||||
boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0;
|
||||
boolean hasDuplicate = cursor.getInt(INDEX_HAS_DUPLICATE_USER_ID) == 1;
|
||||
|
||||
h.mMasterKeyId = masterKeyId;
|
||||
|
||||
|
@ -132,7 +132,7 @@ public class SafeSlingerActivity extends BaseActivity {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
if (returnData == null) {
|
||||
|
@ -263,6 +263,8 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
|
||||
KeyRings.IS_REVOKED,
|
||||
KeyRings.HAS_ENCRYPT,
|
||||
KeyRings.VERIFIED,
|
||||
KeyRings.HAS_DUPLICATE_USER_ID,
|
||||
KeyRings.CREATION,
|
||||
};
|
||||
|
||||
String inMasterKeyList = null;
|
||||
|
@ -113,7 +113,7 @@ public class UploadKeyActivity extends BaseActivity {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
|
||||
Toast.makeText(UploadKeyActivity.this, R.string.msg_crt_upload_success,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
|
@ -25,6 +25,7 @@ import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
@ -74,6 +75,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||
import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus;
|
||||
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
@ -364,6 +366,11 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private void invokeNfcBeam() {
|
||||
// Check if device supports NFC
|
||||
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
|
||||
Notify.createNotify(this, R.string.no_nfc_support, Notify.LENGTH_LONG, Notify.Style.ERROR).show();
|
||||
return;
|
||||
}
|
||||
// Check for available NFC Adapter
|
||||
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
|
||||
if (mNfcAdapter == null || !mNfcAdapter.isEnabled()) {
|
||||
@ -420,7 +427,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
Bundle data = message.getData();
|
||||
CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
|
||||
|
||||
@ -477,7 +484,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
Handler returnHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
@ -586,7 +593,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
|
||||
|
@ -56,6 +56,8 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.ContactHelper;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ViewKeyFragment extends LoaderFragment implements
|
||||
LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
@ -67,7 +69,7 @@ public class ViewKeyFragment extends LoaderFragment implements
|
||||
//private ListView mLinkedSystemContact;
|
||||
|
||||
boolean mIsSecret = false;
|
||||
private String mName;
|
||||
boolean mSystemContactLoaded = false;
|
||||
|
||||
LinearLayout mSystemContactLayout;
|
||||
ImageView mSystemContactPicture;
|
||||
@ -209,28 +211,48 @@ public class ViewKeyFragment extends LoaderFragment implements
|
||||
/**
|
||||
* Checks if a system contact exists for given masterKeyId, and if it does, sets name, picture
|
||||
* and onClickListener for the linked system contact's layout
|
||||
* In the case of a secret key, "me" contact details are loaded
|
||||
*
|
||||
* @param name
|
||||
* @param masterKeyId
|
||||
*/
|
||||
private void loadLinkedSystemContact(String name, final long masterKeyId) {
|
||||
private void loadLinkedSystemContact(final long masterKeyId) {
|
||||
final Context context = mSystemContactName.getContext();
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
|
||||
final long contactId = ContactHelper.findContactId(resolver, masterKeyId);
|
||||
long contactId;
|
||||
String contactName = null;
|
||||
|
||||
if (contactId != -1) {//contact exists for given master key
|
||||
mSystemContactName.setText(name);
|
||||
if (mIsSecret) {//all secret keys are linked to "me" profile in contacts
|
||||
contactId = ContactHelper.getMainProfileContactId(resolver);
|
||||
List<String> mainProfileNames = ContactHelper.getMainProfileContactName(context);
|
||||
if (mainProfileNames != null && mainProfileNames.size() > 0) {
|
||||
contactName = mainProfileNames.get(0);
|
||||
}
|
||||
|
||||
Bitmap picture = ContactHelper.loadPhotoByMasterKeyId(resolver, masterKeyId, true);
|
||||
} else {
|
||||
contactId = ContactHelper.findContactId(resolver, masterKeyId);
|
||||
contactName = ContactHelper.getContactName(resolver, contactId);
|
||||
}
|
||||
|
||||
if (contactName != null) {//contact name exists for given master key
|
||||
mSystemContactName.setText(contactName);
|
||||
|
||||
Bitmap picture;
|
||||
if (mIsSecret) {
|
||||
picture = ContactHelper.loadMainProfilePhoto(resolver, false);
|
||||
} else {
|
||||
picture = ContactHelper.loadPhotoByMasterKeyId(resolver, masterKeyId, false);
|
||||
}
|
||||
if (picture != null) mSystemContactPicture.setImageBitmap(picture);
|
||||
|
||||
final long finalContactId = contactId;
|
||||
mSystemContactLayout.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
launchContactActivity(contactId, context);
|
||||
launchContactActivity(finalContactId, context);
|
||||
}
|
||||
});
|
||||
mSystemContactLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,10 +313,7 @@ public class ViewKeyFragment extends LoaderFragment implements
|
||||
switch (loader.getId()) {
|
||||
case LOADER_ID_USER_IDS: {
|
||||
mUserIdsAdapter.swapCursor(cursor);
|
||||
|
||||
String guessedName = mUserIdsAdapter.getGuessedName();
|
||||
loadLinkedSystemContact(guessedName,
|
||||
KeyFormattingUtils.convertFingerprintToKeyId(mFingerprint));
|
||||
loadLinkedSystemContact(KeyFormattingUtils.convertFingerprintToKeyId(mFingerprint));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -368,7 +368,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
Bundle returnData = message.getData();
|
||||
String msg = returnData.getString(KeychainIntentServiceHandler.DATA_MESSAGE);
|
||||
SpannableStringBuilder ssb = new SpannableStringBuilder();
|
||||
|
@ -81,16 +81,6 @@ public class MultiUserIdsAdapter extends CursorAdapter {
|
||||
ArrayList<String> uids = p.createStringArrayList();
|
||||
p.recycle();
|
||||
|
||||
if (isHeader == 1) {
|
||||
long masterKeyId = cursor.getLong(0);
|
||||
vHeaderId.setVisibility(View.VISIBLE);
|
||||
String message = mContext.getString(R.string.section_uids_to_certify) +
|
||||
KeyFormattingUtils.beautifyKeyIdWithPrefix(mContext, masterKeyId);
|
||||
vHeaderId.setText(message);
|
||||
} else {
|
||||
vHeaderId.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
{ // first one
|
||||
String userId = uids.get(0);
|
||||
String[] splitUserId = KeyRing.splitUserId(userId);
|
||||
@ -99,6 +89,21 @@ public class MultiUserIdsAdapter extends CursorAdapter {
|
||||
} else {
|
||||
vName.setText(R.string.user_id_no_name);
|
||||
}
|
||||
|
||||
if (isHeader == 1) {
|
||||
vHeaderId.setVisibility(View.VISIBLE);
|
||||
String message;
|
||||
if (splitUserId[0] != null) {
|
||||
message = mContext.getString(R.string.section_uids_to_certify) +
|
||||
splitUserId[0];
|
||||
} else {
|
||||
message = mContext.getString(R.string.section_uids_to_certify) +
|
||||
context.getString(R.string.user_id_no_name);
|
||||
}
|
||||
vHeaderId.setText(message);
|
||||
} else {
|
||||
vHeaderId.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder lines = new StringBuilder();
|
||||
|
@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui.adapter;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -35,6 +36,10 @@ import org.sufficientlysecure.keychain.ui.util.Highlighter;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
|
||||
/**
|
||||
* Yes this class is abstract!
|
||||
@ -44,7 +49,8 @@ abstract public class SelectKeyCursorAdapter extends CursorAdapter {
|
||||
private String mQuery;
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
protected int mIndexUserId, mIndexMasterKeyId, mIndexIsExpiry, mIndexIsRevoked;
|
||||
protected int mIndexUserId, mIndexMasterKeyId, mIndexIsExpiry, mIndexIsRevoked,
|
||||
mIndexDuplicateUserId, mIndexCreation;
|
||||
|
||||
public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView) {
|
||||
super(context, c, flags);
|
||||
@ -75,6 +81,8 @@ abstract public class SelectKeyCursorAdapter extends CursorAdapter {
|
||||
mIndexMasterKeyId = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID);
|
||||
mIndexIsExpiry = cursor.getColumnIndexOrThrow(KeyRings.IS_EXPIRED);
|
||||
mIndexIsRevoked = cursor.getColumnIndexOrThrow(KeyRings.IS_REVOKED);
|
||||
mIndexDuplicateUserId = cursor.getColumnIndexOrThrow(KeyRings.HAS_DUPLICATE_USER_ID);
|
||||
mIndexCreation = cursor.getColumnIndexOrThrow(KeyRings.CREATION);
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +98,7 @@ abstract public class SelectKeyCursorAdapter extends CursorAdapter {
|
||||
|
||||
public static class ViewHolderItem {
|
||||
public View view;
|
||||
public TextView mainUserId, mainUserIdRest, keyId;
|
||||
public TextView mainUserId, mainUserIdRest, creation;
|
||||
public ImageView statusIcon;
|
||||
public CheckBox selected;
|
||||
|
||||
@ -99,7 +107,7 @@ abstract public class SelectKeyCursorAdapter extends CursorAdapter {
|
||||
selected.setEnabled(enabled);
|
||||
mainUserId.setEnabled(enabled);
|
||||
mainUserIdRest.setEnabled(enabled);
|
||||
keyId.setEnabled(enabled);
|
||||
creation.setEnabled(enabled);
|
||||
statusIcon.setEnabled(enabled);
|
||||
|
||||
// Sorta special: We set an item as clickable to disable it in the ListView. This works
|
||||
@ -128,8 +136,20 @@ abstract public class SelectKeyCursorAdapter extends CursorAdapter {
|
||||
h.mainUserIdRest.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
long masterKeyId = cursor.getLong(mIndexMasterKeyId);
|
||||
h.keyId.setText(KeyFormattingUtils.beautifyKeyIdWithPrefix(mContext, masterKeyId));
|
||||
boolean duplicate = cursor.getLong(mIndexDuplicateUserId) > 0;
|
||||
if (duplicate) {
|
||||
Date creationDate = new Date(cursor.getLong(mIndexCreation) * 1000);
|
||||
Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
creationCal.setTime(creationDate);
|
||||
// convert from UTC to time zone of device
|
||||
creationCal.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
h.creation.setText(context.getString(R.string.label_creation) + ": "
|
||||
+ DateFormat.getDateFormat(context).format(creationCal.getTime()));
|
||||
h.creation.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
h.creation.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
boolean enabled;
|
||||
if (cursor.getInt(mIndexIsRevoked) != 0) {
|
||||
@ -155,7 +175,7 @@ abstract public class SelectKeyCursorAdapter extends CursorAdapter {
|
||||
holder.view = view;
|
||||
holder.mainUserId = (TextView) view.findViewById(R.id.select_key_item_name);
|
||||
holder.mainUserIdRest = (TextView) view.findViewById(R.id.select_key_item_email);
|
||||
holder.keyId = (TextView) view.findViewById(R.id.select_key_item_key_id);
|
||||
holder.creation = (TextView) view.findViewById(R.id.select_key_item_creation);
|
||||
holder.statusIcon = (ImageView) view.findViewById(R.id.select_key_item_status_icon);
|
||||
holder.selected = (CheckBox) view.findViewById(R.id.selected);
|
||||
view.setTag(holder);
|
||||
|
@ -177,14 +177,6 @@ public class UserIdsAdapter extends UserAttributesAdapter {
|
||||
return isRevokedPending;
|
||||
}
|
||||
|
||||
public String getGuessedName() {
|
||||
Cursor cursor = getCursor();
|
||||
cursor.moveToFirst();
|
||||
String userId = cursor.getString(INDEX_USER_ID);
|
||||
String[] splitUserId = KeyRing.splitUserId(userId);
|
||||
return splitUserId[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
return mInflater.inflate(R.layout.view_key_adv_user_id_item, null);
|
||||
|
@ -18,7 +18,6 @@
|
||||
package org.sufficientlysecure.keychain.ui.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.DialogInterface;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
@ -34,18 +33,22 @@ import org.sufficientlysecure.keychain.util.FileHelper;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class DeleteFileDialogFragment extends DialogFragment {
|
||||
private static final String ARG_DELETE_URI = "delete_uri";
|
||||
private static final String ARG_DELETE_URIS = "delete_uris";
|
||||
|
||||
private OnDeletedListener onDeletedListener;
|
||||
|
||||
/**
|
||||
* Creates new instance of this delete file dialog fragment
|
||||
*/
|
||||
public static DeleteFileDialogFragment newInstance(Uri deleteUri) {
|
||||
public static DeleteFileDialogFragment newInstance(Uri... deleteUris) {
|
||||
DeleteFileDialogFragment frag = new DeleteFileDialogFragment();
|
||||
Bundle args = new Bundle();
|
||||
|
||||
args.putParcelable(ARG_DELETE_URI, deleteUri);
|
||||
args.putParcelableArray(ARG_DELETE_URIS, deleteUris);
|
||||
|
||||
frag.setArguments(args);
|
||||
|
||||
@ -59,12 +62,21 @@ public class DeleteFileDialogFragment extends DialogFragment {
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final FragmentActivity activity = getActivity();
|
||||
|
||||
final Uri deleteUri = getArguments().getParcelable(ARG_DELETE_URI);
|
||||
final String deleteFilename = FileHelper.getFilename(getActivity(), deleteUri);
|
||||
final Uri[] deleteUris = (Uri[]) getArguments().getParcelableArray(ARG_DELETE_URIS);
|
||||
|
||||
final StringBuilder deleteFileNames = new StringBuilder();
|
||||
//Retrieving file names after deletion gives unexpected results
|
||||
final HashMap<Uri, String> deleteFileNameMap = new HashMap<>();
|
||||
for (Uri deleteUri : deleteUris) {
|
||||
String deleteFileName = FileHelper.getFilename(getActivity(), deleteUri);
|
||||
deleteFileNames.append('\n').append(deleteFileName);
|
||||
deleteFileNameMap.put(deleteUri, deleteFileName);
|
||||
}
|
||||
|
||||
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
|
||||
|
||||
alert.setMessage(this.getString(R.string.file_delete_confirmation, deleteFilename));
|
||||
alert.setTitle(getString(R.string.file_delete_confirmation_title));
|
||||
alert.setMessage(getString(R.string.file_delete_confirmation, deleteFileNames.toString()));
|
||||
|
||||
alert.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() {
|
||||
|
||||
@ -72,43 +84,55 @@ public class DeleteFileDialogFragment extends DialogFragment {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dismiss();
|
||||
|
||||
ArrayList<String> failedFileNameList = new ArrayList<>();
|
||||
|
||||
for (Uri deleteUri : deleteUris) {
|
||||
// Use DocumentsContract on Android >= 4.4
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
try {
|
||||
if (DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri)) {
|
||||
continue;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(Constants.TAG, "Catched Exception, can happen when delete is not supported!", e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (getActivity().getContentResolver().delete(deleteUri, null, null) > 0) {
|
||||
continue;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(Constants.TAG, "Catched Exception, can happen when delete is not supported!", e);
|
||||
}
|
||||
|
||||
// some Uri's a ContentResolver fails to delete is handled by the java.io.File's delete
|
||||
// via the path of the Uri
|
||||
if (new File(deleteUri.getPath()).delete()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Note: We can't delete every file...
|
||||
failedFileNameList.add(deleteFileNameMap.get(deleteUri));
|
||||
}
|
||||
|
||||
StringBuilder failedFileNames = new StringBuilder();
|
||||
if (!failedFileNameList.isEmpty()) {
|
||||
for (String failedFileName : failedFileNameList) {
|
||||
failedFileNames.append('\n').append(failedFileName);
|
||||
}
|
||||
failedFileNames.append('\n').append(getActivity().getString(R.string.error_file_delete_failed));
|
||||
}
|
||||
|
||||
// NOTE: Use Toasts, not Snackbars. When sharing to another application snackbars
|
||||
// would not show up!
|
||||
Toast.makeText(getActivity(), getActivity().getString(R.string.file_delete_successful,
|
||||
deleteUris.length - failedFileNameList.size(), deleteUris.length, failedFileNames.toString()),
|
||||
Toast.LENGTH_LONG).show();
|
||||
|
||||
// Use DocumentsContract on Android >= 4.4
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
try {
|
||||
if (DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri)) {
|
||||
Toast.makeText(getActivity(), getActivity().getString(R.string.file_delete_successful,
|
||||
deleteFilename), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
} catch (UnsupportedOperationException e) {
|
||||
Log.d(Constants.TAG, "Catched UnsupportedOperationException, can happen when delete is not supported!", e);
|
||||
}
|
||||
if (onDeletedListener != null) {
|
||||
onDeletedListener.onDeleted();
|
||||
}
|
||||
|
||||
try {
|
||||
if (getActivity().getContentResolver().delete(deleteUri, null, null) > 0) {
|
||||
Toast.makeText(getActivity(), getActivity().getString(R.string.file_delete_successful,
|
||||
deleteFilename), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
} catch (UnsupportedOperationException e) {
|
||||
Log.d(Constants.TAG, "Catched UnsupportedOperationException, can happen when delete is not supported!", e);
|
||||
}
|
||||
|
||||
// some Uri's a ContentResolver fails to delete is handled by the java.io.File's delete
|
||||
// via the path of the Uri
|
||||
if (new File(deleteUri.getPath()).delete()) {
|
||||
Toast.makeText(getActivity(), getActivity().getString(R.string.file_delete_successful,
|
||||
deleteFilename), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: We can't delete every file...
|
||||
Toast.makeText(getActivity(), getActivity().getString(R.string.error_file_delete_failed,
|
||||
deleteFilename), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@ -120,4 +144,18 @@ public class DeleteFileDialogFragment extends DialogFragment {
|
||||
|
||||
return alert.show();
|
||||
}
|
||||
|
||||
public void setOnDeletedListener(OnDeletedListener onDeletedListener) {
|
||||
this.onDeletedListener = onDeletedListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for performing tasks after the deletion of files
|
||||
*/
|
||||
public interface OnDeletedListener {
|
||||
|
||||
public void onDeleted();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
||||
public void handleMessage(Message message) {
|
||||
super.handleMessage(message);
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
if (message.arg1 == MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
try {
|
||||
Message msg = Message.obtain();
|
||||
msg.copyFrom(message);
|
||||
|
@ -188,7 +188,7 @@ public abstract class LinkedIdCreateFinalFragment extends Fragment {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
|
@ -557,7 +557,7 @@ public class LinkedIdViewFragment extends Fragment implements
|
||||
|
||||
Bundle data = message.getData();
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_UPDATE_PROGRESS) {
|
||||
if (message.arg1 == MessageStatus.UPDATE_PROGRESS.ordinal()) {
|
||||
if (data.containsKey(DATA_MESSAGE)) {
|
||||
mViewHolder.vText.setText(data.getString(DATA_MESSAGE));
|
||||
} else if (data.containsKey(DATA_MESSAGE_ID)) {
|
||||
@ -566,7 +566,7 @@ public class LinkedIdViewFragment extends Fragment implements
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
|
||||
result.createNotify(getActivity()).show();
|
||||
}
|
||||
|
@ -68,7 +68,9 @@ public class CertifyKeySpinner extends KeySpinner {
|
||||
KeychainContract.KeyRings.IS_REVOKED,
|
||||
KeychainContract.KeyRings.IS_EXPIRED,
|
||||
KeychainContract.KeyRings.HAS_CERTIFY,
|
||||
KeychainContract.KeyRings.HAS_ANY_SECRET
|
||||
KeychainContract.KeyRings.HAS_ANY_SECRET,
|
||||
KeychainContract.KeyRings.HAS_DUPLICATE_USER_ID,
|
||||
KeychainContract.KeyRings.CREATION
|
||||
};
|
||||
|
||||
String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1 AND "
|
||||
@ -91,16 +93,31 @@ public class CertifyKeySpinner extends KeySpinner {
|
||||
mIndexIsRevoked = data.getColumnIndex(KeychainContract.KeyRings.IS_REVOKED);
|
||||
mIndexIsExpired = data.getColumnIndex(KeychainContract.KeyRings.IS_EXPIRED);
|
||||
|
||||
// If there is only one choice, pick it by default
|
||||
if (mAdapter.getCount() == 2) {
|
||||
// If:
|
||||
// - no key has been pre-selected (e.g. by SageSlinger)
|
||||
// - there are actually keys (not just "none" entry)
|
||||
// Then:
|
||||
// - select key that is capable of certifying, but only if there is only one key capable of it
|
||||
if (mSelectedKeyId == Constants.key.none && mAdapter.getCount() > 1) {
|
||||
// preselect if key can certify
|
||||
if (data.moveToPosition(0) && !data.isNull(mIndexHasCertify)) {
|
||||
setSelection(1);
|
||||
int selection = -1;
|
||||
while (data.moveToNext()) {
|
||||
if (!data.isNull(mIndexHasCertify)) {
|
||||
if (selection == -1) {
|
||||
selection = data.getPosition() + 1;
|
||||
} else {
|
||||
// if selection is already set, we have more than one certify key!
|
||||
// get back to "none"!
|
||||
selection = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
setSelection(selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
boolean setStatus(Context context, Cursor cursor, ImageView statusView) {
|
||||
if (cursor.getInt(mIndexIsRevoked) != 0) {
|
||||
|
@ -28,6 +28,7 @@ import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@ -51,9 +52,12 @@ import org.sufficientlysecure.keychain.util.ContactHelper;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class EncryptKeyCompletionView extends TokenCompleteTextView {
|
||||
public EncryptKeyCompletionView(Context context) {
|
||||
@ -125,7 +129,9 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
|
||||
KeyRings.USER_ID,
|
||||
KeyRings.FINGERPRINT,
|
||||
KeyRings.IS_EXPIRED,
|
||||
KeyRings.HAS_ENCRYPT
|
||||
KeyRings.HAS_ENCRYPT,
|
||||
KeyRings.HAS_DUPLICATE_USER_ID,
|
||||
KeyRings.CREATION
|
||||
};
|
||||
|
||||
String where = KeyRings.HAS_ENCRYPT + " NOT NULL AND " + KeyRings.IS_EXPIRED + " = 0 AND "
|
||||
@ -153,7 +159,7 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
|
||||
public void onFocusChanged(boolean hasFocus, int direction, Rect previous) {
|
||||
super.onFocusChanged(hasFocus, direction, previous);
|
||||
if (hasFocus) {
|
||||
((InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE))
|
||||
((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE))
|
||||
.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
}
|
||||
@ -180,25 +186,30 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
|
||||
private String mUserIdFull;
|
||||
private String[] mUserId;
|
||||
private long mKeyId;
|
||||
private boolean mHasDuplicate;
|
||||
private Date mCreation;
|
||||
private String mFingerprint;
|
||||
|
||||
public EncryptionKey(String userId, long keyId, String fingerprint) {
|
||||
this.mUserId = KeyRing.splitUserId(userId);
|
||||
this.mUserIdFull = userId;
|
||||
this.mKeyId = keyId;
|
||||
this.mFingerprint = fingerprint;
|
||||
public EncryptionKey(String userId, long keyId, boolean hasDuplicate, Date creation, String fingerprint) {
|
||||
mUserId = KeyRing.splitUserId(userId);
|
||||
mUserIdFull = userId;
|
||||
mKeyId = keyId;
|
||||
mHasDuplicate = hasDuplicate;
|
||||
mCreation = creation;
|
||||
mFingerprint = fingerprint;
|
||||
}
|
||||
|
||||
public EncryptionKey(Cursor cursor) {
|
||||
this(cursor.getString(cursor.getColumnIndexOrThrow(KeyRings.USER_ID)),
|
||||
cursor.getLong(cursor.getColumnIndexOrThrow(KeyRings.KEY_ID)),
|
||||
cursor.getLong(cursor.getColumnIndexOrThrow(KeyRings.HAS_DUPLICATE_USER_ID)) > 0,
|
||||
new Date(cursor.getLong(cursor.getColumnIndexOrThrow(KeyRings.CREATION)) * 1000),
|
||||
KeyFormattingUtils.convertFingerprintToHex(
|
||||
cursor.getBlob(cursor.getColumnIndexOrThrow(KeyRings.FINGERPRINT))));
|
||||
|
||||
}
|
||||
|
||||
public EncryptionKey(CachedPublicKeyRing ring) throws PgpKeyNotFoundException {
|
||||
this(ring.getPrimaryUserId(), ring.extractOrGetMasterKeyId(),
|
||||
this(ring.getPrimaryUserId(), ring.extractOrGetMasterKeyId(), false, null,
|
||||
KeyFormattingUtils.convertFingerprintToHex(ring.getFingerprint()));
|
||||
}
|
||||
|
||||
@ -222,13 +233,13 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
|
||||
if (mUserId[1] != null) {
|
||||
return mUserId[1];
|
||||
} else {
|
||||
return getKeyIdHex();
|
||||
return getCreationDate();
|
||||
}
|
||||
}
|
||||
|
||||
public String getTertiary() {
|
||||
if (mUserId[0] != null) {
|
||||
return getKeyIdHex();
|
||||
return getCreationDate();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -238,6 +249,20 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
|
||||
return mKeyId;
|
||||
}
|
||||
|
||||
public String getCreationDate() {
|
||||
if (mHasDuplicate) {
|
||||
Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
creationCal.setTime(mCreation);
|
||||
// convert from UTC to time zone of device
|
||||
creationCal.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
return getContext().getString(R.string.label_creation) + ": "
|
||||
+ DateFormat.getDateFormat(getContext()).format(creationCal.getTime());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getKeyIdHex() {
|
||||
return KeyFormattingUtils.beautifyKeyIdWithPrefix(getContext(), mKeyId);
|
||||
}
|
||||
@ -278,7 +303,7 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
|
||||
protected boolean keepObject(EncryptionKey obj, String mask) {
|
||||
String m = mask.toLowerCase(Locale.ENGLISH);
|
||||
return obj.getUserId().toLowerCase(Locale.ENGLISH).contains(m) ||
|
||||
obj.getKeyIdHex().toString().contains(m) ||
|
||||
obj.getKeyIdHex().contains(m) ||
|
||||
obj.getKeyIdHexShort().startsWith(m);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.support.v7.internal.widget.TintSpinner;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -41,6 +42,10 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Use TintSpinner from AppCompat lib instead of Spinner. Fixes white dropdown icon.
|
||||
* Related: http://stackoverflow.com/a/27713090
|
||||
@ -50,7 +55,7 @@ public abstract class KeySpinner extends TintSpinner implements LoaderManager.Lo
|
||||
public void onKeyChanged(long masterKeyId);
|
||||
}
|
||||
|
||||
protected long mSelectedKeyId;
|
||||
protected long mSelectedKeyId = Constants.key.none;
|
||||
protected SelectKeyAdapter mAdapter = new SelectKeyAdapter();
|
||||
protected OnKeyChangedListener mListener;
|
||||
|
||||
@ -135,11 +140,12 @@ public abstract class KeySpinner extends TintSpinner implements LoaderManager.Lo
|
||||
protected class SelectKeyAdapter extends BaseAdapter implements SpinnerAdapter {
|
||||
private CursorAdapter inner;
|
||||
private int mIndexUserId;
|
||||
private int mIndexKeyId;
|
||||
private int mIndexDuplicate;
|
||||
private int mIndexMasterKeyId;
|
||||
private int mIndexCreationDate;
|
||||
|
||||
public SelectKeyAdapter() {
|
||||
inner = new CursorAdapter(null, null, 0) {
|
||||
inner = new CursorAdapter(getContext(), null, 0) {
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
return View.inflate(getContext(), R.layout.keyspinner_item, null);
|
||||
@ -150,12 +156,26 @@ public abstract class KeySpinner extends TintSpinner implements LoaderManager.Lo
|
||||
TextView vKeyName = (TextView) view.findViewById(R.id.keyspinner_key_name);
|
||||
ImageView vKeyStatus = (ImageView) view.findViewById(R.id.keyspinner_key_status);
|
||||
TextView vKeyEmail = (TextView) view.findViewById(R.id.keyspinner_key_email);
|
||||
TextView vKeyId = (TextView) view.findViewById(R.id.keyspinner_key_id);
|
||||
TextView vDuplicate = (TextView) view.findViewById(R.id.keyspinner_duplicate);
|
||||
|
||||
String[] userId = KeyRing.splitUserId(cursor.getString(mIndexUserId));
|
||||
vKeyName.setText(userId[2] == null ? userId[0] : (userId[0] + " (" + userId[2] + ")"));
|
||||
vKeyEmail.setText(userId[1]);
|
||||
vKeyId.setText(KeyFormattingUtils.beautifyKeyIdWithPrefix(getContext(), cursor.getLong(mIndexKeyId)));
|
||||
|
||||
boolean duplicate = cursor.getLong(mIndexDuplicate) > 0;
|
||||
if (duplicate) {
|
||||
Date creationDate = new Date(cursor.getLong(mIndexCreationDate) * 1000);
|
||||
Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
creationCal.setTime(creationDate);
|
||||
// convert from UTC to time zone of device
|
||||
creationCal.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
vDuplicate.setText(context.getString(R.string.label_creation) + ": "
|
||||
+ DateFormat.getDateFormat(context).format(creationCal.getTime()));
|
||||
vDuplicate.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
vDuplicate.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
boolean valid = setStatus(getContext(), cursor, vKeyStatus);
|
||||
setItemEnabled(view, valid);
|
||||
@ -177,18 +197,18 @@ public abstract class KeySpinner extends TintSpinner implements LoaderManager.Lo
|
||||
TextView vKeyName = (TextView) view.findViewById(R.id.keyspinner_key_name);
|
||||
ImageView vKeyStatus = (ImageView) view.findViewById(R.id.keyspinner_key_status);
|
||||
TextView vKeyEmail = (TextView) view.findViewById(R.id.keyspinner_key_email);
|
||||
TextView vKeyId = (TextView) view.findViewById(R.id.keyspinner_key_id);
|
||||
TextView vKeyDuplicate = (TextView) view.findViewById(R.id.keyspinner_duplicate);
|
||||
|
||||
if (enabled) {
|
||||
vKeyName.setTextColor(Color.BLACK);
|
||||
vKeyEmail.setTextColor(Color.BLACK);
|
||||
vKeyId.setTextColor(Color.BLACK);
|
||||
vKeyDuplicate.setTextColor(Color.BLACK);
|
||||
vKeyStatus.setVisibility(View.GONE);
|
||||
view.setClickable(false);
|
||||
} else {
|
||||
vKeyName.setTextColor(Color.GRAY);
|
||||
vKeyEmail.setTextColor(Color.GRAY);
|
||||
vKeyId.setTextColor(Color.GRAY);
|
||||
vKeyDuplicate.setTextColor(Color.GRAY);
|
||||
vKeyStatus.setVisibility(View.VISIBLE);
|
||||
// this is a HACK. the trick is, if the element itself is clickable, the
|
||||
// click is not passed on to the view list
|
||||
@ -199,10 +219,13 @@ public abstract class KeySpinner extends TintSpinner implements LoaderManager.Lo
|
||||
public Cursor swapCursor(Cursor newCursor) {
|
||||
if (newCursor == null) return inner.swapCursor(null);
|
||||
|
||||
mIndexKeyId = newCursor.getColumnIndex(KeychainContract.KeyRings.KEY_ID);
|
||||
mIndexDuplicate = newCursor.getColumnIndex(KeychainContract.KeyRings.HAS_DUPLICATE_USER_ID);
|
||||
mIndexUserId = newCursor.getColumnIndex(KeychainContract.KeyRings.USER_ID);
|
||||
mIndexMasterKeyId = newCursor.getColumnIndex(KeychainContract.KeyRings.MASTER_KEY_ID);
|
||||
if (newCursor.moveToFirst()) {
|
||||
mIndexCreationDate = newCursor.getColumnIndex(KeychainContract.KeyRings.CREATION);
|
||||
|
||||
// pre-select key if mSelectedKeyId is given
|
||||
if (mSelectedKeyId != Constants.key.none && newCursor.moveToFirst()) {
|
||||
do {
|
||||
if (newCursor.getLong(mIndexMasterKeyId) == mSelectedKeyId) {
|
||||
setSelection(newCursor.getPosition() + 1);
|
||||
@ -253,19 +276,17 @@ public abstract class KeySpinner extends TintSpinner implements LoaderManager.Lo
|
||||
TextView vKeyName = (TextView) view.findViewById(R.id.keyspinner_key_name);
|
||||
ImageView vKeyStatus = (ImageView) view.findViewById(R.id.keyspinner_key_status);
|
||||
TextView vKeyEmail = (TextView) view.findViewById(R.id.keyspinner_key_email);
|
||||
TextView vKeyId = (TextView) view.findViewById(R.id.keyspinner_key_id);
|
||||
TextView vKeyDuplicate = (TextView) view.findViewById(R.id.keyspinner_duplicate);
|
||||
|
||||
vKeyName.setText(R.string.choice_none);
|
||||
vKeyEmail.setVisibility(View.GONE);
|
||||
vKeyId.setVisibility(View.GONE);
|
||||
vKeyDuplicate.setVisibility(View.GONE);
|
||||
vKeyStatus.setVisibility(View.GONE);
|
||||
setItemEnabled(view, true);
|
||||
} else {
|
||||
view = inner.getView(position - 1, convertView, parent);
|
||||
TextView vKeyEmail = (TextView) view.findViewById(R.id.keyspinner_key_email);
|
||||
TextView vKeyId = (TextView) view.findViewById(R.id.keyspinner_key_id);
|
||||
vKeyEmail.setVisibility(View.VISIBLE);
|
||||
vKeyId.setVisibility(View.VISIBLE);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
@ -59,7 +59,9 @@ public class SignKeySpinner extends KeySpinner {
|
||||
KeychainContract.KeyRings.IS_REVOKED,
|
||||
KeychainContract.KeyRings.IS_EXPIRED,
|
||||
KeychainContract.KeyRings.HAS_SIGN,
|
||||
KeychainContract.KeyRings.HAS_ANY_SECRET
|
||||
KeychainContract.KeyRings.HAS_ANY_SECRET,
|
||||
KeychainContract.KeyRings.HAS_DUPLICATE_USER_ID,
|
||||
KeychainContract.KeyRings.CREATION
|
||||
};
|
||||
|
||||
String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1";
|
||||
|
@ -190,7 +190,7 @@ public class ContactHelper {
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
private static List<String> getMainProfileContactName(Context context) {
|
||||
public static List<String> getMainProfileContactName(Context context) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Cursor profileCursor = resolver.query(
|
||||
ContactsContract.Profile.CONTENT_URI,
|
||||
@ -214,6 +214,55 @@ public class ContactHelper {
|
||||
return new ArrayList<>(names);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the CONTACT_ID of the main ("me") contact
|
||||
* http://developer.android.com/reference/android/provider/ContactsContract.Profile.html
|
||||
*
|
||||
* @param resolver
|
||||
* @return
|
||||
*/
|
||||
public static long getMainProfileContactId(ContentResolver resolver) {
|
||||
Cursor profileCursor = resolver.query(ContactsContract.Profile.CONTENT_URI,
|
||||
new String[]{ ContactsContract.Profile._ID}, null, null, null);
|
||||
|
||||
if(profileCursor != null && profileCursor.getCount() != 0 && profileCursor.moveToNext()) {
|
||||
long contactId = profileCursor.getLong(0);
|
||||
profileCursor.close();
|
||||
return contactId;
|
||||
}
|
||||
else {
|
||||
if(profileCursor != null) {
|
||||
profileCursor.close();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* loads the profile picture of the main ("me") contact
|
||||
* http://developer.android.com/reference/android/provider/ContactsContract.Profile.html
|
||||
*
|
||||
* @param contentResolver
|
||||
* @param highRes true for large image if present, false for thumbnail
|
||||
* @return bitmap of loaded photo
|
||||
*/
|
||||
public static Bitmap loadMainProfilePhoto(ContentResolver contentResolver, boolean highRes) {
|
||||
try {
|
||||
long mainProfileContactId = getMainProfileContactId(contentResolver);
|
||||
|
||||
Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI,
|
||||
Long.toString(mainProfileContactId));
|
||||
InputStream photoInputStream =
|
||||
ContactsContract.Contacts.openContactPhotoInputStream(contentResolver, contactUri, highRes);
|
||||
if (photoInputStream == null) {
|
||||
return null;
|
||||
}
|
||||
return BitmapFactory.decodeStream(photoInputStream);
|
||||
} catch (Throwable ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getContactMails(Context context) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Cursor mailCursor = resolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,
|
||||
@ -269,7 +318,7 @@ public class ContactHelper {
|
||||
|
||||
/**
|
||||
* returns the CONTACT_ID of the raw contact to which a masterKeyId is associated, if the
|
||||
* raw contact has not been marked for deletion
|
||||
* raw contact has not been marked for deletion.
|
||||
*
|
||||
* @param resolver
|
||||
* @param masterKeyId
|
||||
@ -296,6 +345,34 @@ public class ContactHelper {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display name of the system contact associated with contactId, null if the
|
||||
* contact does not exist
|
||||
*
|
||||
* @param resolver
|
||||
* @param contactId
|
||||
* @return primary display name of system contact associated with contactId, null if it does
|
||||
* not exist
|
||||
*/
|
||||
public static String getContactName(ContentResolver resolver, long contactId) {
|
||||
String contactName = null;
|
||||
Cursor raw = resolver.query(ContactsContract.Contacts.CONTENT_URI,
|
||||
new String[]{
|
||||
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
|
||||
},
|
||||
ContactsContract.Contacts._ID + "=?",
|
||||
new String[]{//"0" for "not deleted"
|
||||
Long.toString(contactId)
|
||||
}, null);
|
||||
if (raw != null) {
|
||||
if (raw.moveToNext()) {
|
||||
contactName = raw.getString(0);
|
||||
}
|
||||
raw.close();
|
||||
}
|
||||
return contactName;
|
||||
}
|
||||
|
||||
public static Bitmap getCachedPhotoByMasterKeyId(ContentResolver contentResolver, long masterKeyId) {
|
||||
if (masterKeyId == -1) {
|
||||
return null;
|
||||
@ -333,46 +410,47 @@ public class ContactHelper {
|
||||
KeychainContract.KeyRings.MASTER_KEY_ID,
|
||||
KeychainContract.KeyRings.USER_ID,
|
||||
KeychainContract.KeyRings.IS_EXPIRED,
|
||||
KeychainContract.KeyRings.IS_REVOKED};
|
||||
KeychainContract.KeyRings.IS_REVOKED,
|
||||
KeychainContract.KeyRings.VERIFIED,
|
||||
KeychainContract.KeyRings.HAS_SECRET,
|
||||
KeychainContract.KeyRings.HAS_ANY_SECRET};
|
||||
|
||||
public static final int INDEX_MASTER_KEY_ID = 0;
|
||||
public static final int INDEX_USER_ID = 1;
|
||||
public static final int INDEX_IS_EXPIRED = 2;
|
||||
public static final int INDEX_IS_REVOKED = 3;
|
||||
public static final int INDEX_VERIFIED = 4;
|
||||
public static final int INDEX_HAS_SECRET = 5;
|
||||
public static final int INDEX_HAS_ANY_SECRET = 6;
|
||||
|
||||
/**
|
||||
* Write/Update the current OpenKeychain keys to the contact db
|
||||
*/
|
||||
public static void writeKeysToContacts(Context context) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Set<Long> deletedKeys = getRawContactMasterKeyIds(resolver);
|
||||
|
||||
if (Constants.DEBUG_SYNC_REMOVE_CONTACTS) {
|
||||
debugDeleteRawContacts(resolver);
|
||||
}
|
||||
|
||||
// ContentProviderClient client = resolver.acquireContentProviderClient(ContactsContract.AUTHORITY_URI);
|
||||
// ContentValues values = new ContentValues();
|
||||
// Account account = new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE);
|
||||
// values.put(ContactsContract.Settings.ACCOUNT_NAME, account.name);
|
||||
// values.put(ContactsContract.Settings.ACCOUNT_TYPE, account.type);
|
||||
// values.put(ContactsContract.Settings.UNGROUPED_VISIBLE, true);
|
||||
// try {
|
||||
// client.insert(ContactsContract.Settings.CONTENT_URI.buildUpon().appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build(), values);
|
||||
// } catch (RemoteException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
writeKeysToMainProfileContact(context, resolver);
|
||||
|
||||
Set<Long> deletedKeys = getRawContactMasterKeyIds(resolver);
|
||||
|
||||
// Load all public Keys from OK
|
||||
// TODO: figure out why using selectionArgs does not work in this case
|
||||
Cursor cursor = resolver.query(KeychainContract.KeyRings.buildUnifiedKeyRingsUri(),
|
||||
KEYS_TO_CONTACT_PROJECTION,
|
||||
KeychainContract.KeyRings.HAS_ANY_SECRET + "=0",
|
||||
null, null);
|
||||
|
||||
// Load all Keys from OK
|
||||
Cursor cursor = resolver.query(KeychainContract.KeyRings.buildUnifiedKeyRingsUri(), KEYS_TO_CONTACT_PROJECTION,
|
||||
null, null, null);
|
||||
if (cursor != null) {
|
||||
while (cursor.moveToNext()) {
|
||||
long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
|
||||
String[] userIdSplit = KeyRing.splitUserId(cursor.getString(INDEX_USER_ID));
|
||||
String keyIdShort = KeyFormattingUtils.convertKeyIdToHexShort(cursor.getLong(INDEX_MASTER_KEY_ID));
|
||||
boolean isExpired = cursor.getInt(INDEX_IS_EXPIRED) != 0;
|
||||
boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
|
||||
boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0;
|
||||
|
||||
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
|
||||
|
||||
@ -384,9 +462,11 @@ public class ContactHelper {
|
||||
|
||||
ArrayList<ContentProviderOperation> ops = new ArrayList<>();
|
||||
|
||||
// Do not store expired or revoked keys in contact db - and remove them if they already exist
|
||||
if (isExpired || isRevoked) {
|
||||
Log.d(Constants.TAG, "Expired or revoked: Deleting rawContactId " + rawContactId);
|
||||
// Do not store expired or revoked or unverified keys in contact db - and
|
||||
// remove them if they already exist. Secret keys do not reach this point
|
||||
if (isExpired || isRevoked || !isVerified) {
|
||||
Log.d(Constants.TAG, "Expired or revoked or unverified: Deleting rawContactId "
|
||||
+ rawContactId);
|
||||
if (rawContactId != -1) {
|
||||
deleteRawContactById(resolver, rawContactId);
|
||||
}
|
||||
@ -397,7 +477,7 @@ public class ContactHelper {
|
||||
Log.d(Constants.TAG, "Insert new raw contact with masterKeyId " + masterKeyId);
|
||||
|
||||
insertContact(ops, context, masterKeyId);
|
||||
writeContactKey(ops, context, rawContactId, masterKeyId, keyIdShort);
|
||||
writeContactKey(ops, context, rawContactId, masterKeyId, userIdSplit[0]);
|
||||
}
|
||||
|
||||
// We always update the display name (which is derived from primary user id)
|
||||
@ -422,43 +502,165 @@ public class ContactHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all raw contacts associated to OpenKeychain.
|
||||
* Links all keys with secrets to the main ("me") contact
|
||||
* http://developer.android.com/reference/android/provider/ContactsContract.Profile.html
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public static void writeKeysToMainProfileContact(Context context, ContentResolver resolver) {
|
||||
Set<Long> keysToDelete = getMainProfileMasterKeyIds(resolver);
|
||||
|
||||
// get all keys which have associated secret keys
|
||||
// TODO: figure out why using selectionArgs does not work in this case
|
||||
Cursor cursor = resolver.query(KeychainContract.KeyRings.buildUnifiedKeyRingsUri(),
|
||||
KEYS_TO_CONTACT_PROJECTION,
|
||||
KeychainContract.KeyRings.HAS_ANY_SECRET + "!=0",
|
||||
null, null);
|
||||
if (cursor != null) {
|
||||
while (cursor.moveToNext()) {
|
||||
long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
|
||||
boolean isExpired = cursor.getInt(INDEX_IS_EXPIRED) != 0;
|
||||
boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
|
||||
String[] userIdSplit = KeyRing.splitUserId(cursor.getString(INDEX_USER_ID));
|
||||
|
||||
if (!isExpired && !isRevoked && userIdSplit[0] != null) {
|
||||
// if expired or revoked will not be removed from keysToDelete or inserted
|
||||
// into main profile ("me" contact)
|
||||
boolean existsInMainProfile = keysToDelete.remove(masterKeyId);
|
||||
if (!existsInMainProfile) {
|
||||
long rawContactId = -1;//new raw contact
|
||||
|
||||
Log.d(Constants.TAG, "masterKeyId with secret " + masterKeyId);
|
||||
|
||||
ArrayList<ContentProviderOperation> ops = new ArrayList<>();
|
||||
insertMainProfileRawContact(ops, masterKeyId);
|
||||
writeContactKey(ops, context, rawContactId, masterKeyId, userIdSplit[0]);
|
||||
|
||||
try {
|
||||
resolver.applyBatch(ContactsContract.AUTHORITY, ops);
|
||||
} catch (Exception e) {
|
||||
Log.w(Constants.TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (long masterKeyId : keysToDelete) {
|
||||
deleteMainProfileRawContactByMasterKeyId(resolver, masterKeyId);
|
||||
Log.d(Constants.TAG, "Delete main profile raw contact with masterKeyId " + masterKeyId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a raw contact into the table defined by ContactsContract.Profile
|
||||
* http://developer.android.com/reference/android/provider/ContactsContract.Profile.html
|
||||
*
|
||||
* @param ops
|
||||
* @param masterKeyId
|
||||
*/
|
||||
private static void insertMainProfileRawContact(ArrayList<ContentProviderOperation> ops,
|
||||
long masterKeyId) {
|
||||
ops.add(ContentProviderOperation.newInsert(ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI)
|
||||
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, Constants.ACCOUNT_NAME)
|
||||
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, Constants.ACCOUNT_TYPE)
|
||||
.withValue(ContactsContract.RawContacts.SOURCE_ID, Long.toString(masterKeyId))
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes a raw contact from the main profile table ("me" contact)
|
||||
* http://developer.android.com/reference/android/provider/ContactsContract.Profile.html
|
||||
*
|
||||
* @param resolver
|
||||
* @param masterKeyId
|
||||
* @return
|
||||
*/
|
||||
private static int deleteMainProfileRawContactByMasterKeyId(ContentResolver resolver,
|
||||
long masterKeyId) {
|
||||
// CALLER_IS_SYNCADAPTER allows us to actually wipe the RawContact from the device, otherwise
|
||||
// would be just flagged for deletion
|
||||
Uri deleteUri = ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI.buildUpon().
|
||||
appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build();
|
||||
|
||||
return resolver.delete(deleteUri,
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " +
|
||||
ContactsContract.RawContacts.SOURCE_ID + "=?",
|
||||
new String[]{
|
||||
Constants.ACCOUNT_TYPE, Long.toString(masterKeyId)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all raw contacts associated to OpenKeychain, including those from "me" contact
|
||||
* defined by ContactsContract.Profile
|
||||
*
|
||||
* @return number of rows deleted
|
||||
*/
|
||||
private static int debugDeleteRawContacts(ContentResolver resolver) {
|
||||
//allows us to actually wipe the RawContact from the device, otherwise would be just flagged
|
||||
//for deletion
|
||||
// CALLER_IS_SYNCADAPTER allows us to actually wipe the RawContact from the device, otherwise
|
||||
// would be just flagged for deletion
|
||||
Uri deleteUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon().
|
||||
appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build();
|
||||
|
||||
Log.d(Constants.TAG, "Deleting all raw contacts associated to OK...");
|
||||
return resolver.delete(deleteUri,
|
||||
int delete = resolver.delete(deleteUri,
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=?",
|
||||
new String[]{
|
||||
Constants.ACCOUNT_TYPE
|
||||
});
|
||||
|
||||
Uri mainProfileDeleteUri = ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI.buildUpon()
|
||||
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build();
|
||||
|
||||
delete += resolver.delete(mainProfileDeleteUri,
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=?",
|
||||
new String[]{
|
||||
Constants.ACCOUNT_TYPE
|
||||
});
|
||||
|
||||
return delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes raw contacts from ContactsContract.RawContacts based on rawContactId. Does not
|
||||
* delete contacts from the "me" contact defined in ContactsContract.Profile
|
||||
*
|
||||
* @param resolver
|
||||
* @param rawContactId
|
||||
* @return number of rows deleted
|
||||
*/
|
||||
private static int deleteRawContactById(ContentResolver resolver, long rawContactId) {
|
||||
//allows us to actually wipe the RawContact from the device, otherwise would be just flagged
|
||||
//for deletion
|
||||
// CALLER_IS_SYNCADAPTER allows us to actually wipe the RawContact from the device, otherwise
|
||||
// would be just flagged for deletion
|
||||
Uri deleteUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon().
|
||||
appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build();
|
||||
|
||||
return resolver.delete(deleteUri,
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + ContactsContract.RawContacts._ID + "=?",
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " +
|
||||
ContactsContract.RawContacts._ID + "=?",
|
||||
new String[]{
|
||||
Constants.ACCOUNT_TYPE, Long.toString(rawContactId)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes raw contacts from ContactsContract.RawContacts based on masterKeyId. Does not
|
||||
* delete contacts from the "me" contact defined in ContactsContract.Profile
|
||||
*
|
||||
* @param resolver
|
||||
* @param masterKeyId
|
||||
* @return number of rows deleted
|
||||
*/
|
||||
private static int deleteRawContactByMasterKeyId(ContentResolver resolver, long masterKeyId) {
|
||||
//allows us to actually wipe the RawContact from the device, otherwise would be just flagged
|
||||
//for deletion
|
||||
// CALLER_IS_SYNCADAPTER allows us to actually wipe the RawContact from the device, otherwise
|
||||
// would be just flagged for deletion
|
||||
Uri deleteUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon().
|
||||
appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build();
|
||||
|
||||
return resolver.delete(deleteUri,
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + ContactsContract.RawContacts.SOURCE_ID + "=?",
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " +
|
||||
ContactsContract.RawContacts.SOURCE_ID + "=?",
|
||||
new String[]{
|
||||
Constants.ACCOUNT_TYPE, Long.toString(masterKeyId)
|
||||
});
|
||||
@ -486,6 +688,28 @@ public class ContactHelper {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a set of all key master key ids currently present in the contact db
|
||||
*/
|
||||
private static Set<Long> getMainProfileMasterKeyIds(ContentResolver resolver) {
|
||||
HashSet<Long> result = new HashSet<>();
|
||||
Cursor masterKeyIds = resolver.query(ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI,
|
||||
new String[]{
|
||||
ContactsContract.RawContacts.SOURCE_ID
|
||||
},
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=?",
|
||||
new String[]{
|
||||
Constants.ACCOUNT_TYPE
|
||||
}, null);
|
||||
if (masterKeyIds != null) {
|
||||
while (masterKeyIds.moveToNext()) {
|
||||
result.add(masterKeyIds.getLong(0));
|
||||
}
|
||||
masterKeyIds.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will search the contact db for a raw contact with a given master key id
|
||||
*
|
||||
@ -528,10 +752,10 @@ public class ContactHelper {
|
||||
* This creates the link to OK in contact details
|
||||
*/
|
||||
private static void writeContactKey(ArrayList<ContentProviderOperation> ops, Context context, long rawContactId,
|
||||
long masterKeyId, String keyIdShort) {
|
||||
long masterKeyId, String keyName) {
|
||||
ops.add(referenceRawContact(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI), rawContactId)
|
||||
.withValue(ContactsContract.Data.MIMETYPE, Constants.CUSTOM_CONTACT_DATA_MIME_TYPE)
|
||||
.withValue(ContactsContract.Data.DATA1, context.getString(R.string.contact_show_key, keyIdShort))
|
||||
.withValue(ContactsContract.Data.DATA1, context.getString(R.string.contact_show_key, keyName))
|
||||
.withValue(ContactsContract.Data.DATA2, masterKeyId)
|
||||
.build());
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ public class ExportHelper {
|
||||
// handle messages by standard KeychainIntentServiceHandler first
|
||||
super.handleMessage(message);
|
||||
|
||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||
// get returned data bundle
|
||||
Bundle data = message.getData();
|
||||
|
||||
|
@ -89,79 +89,4 @@
|
||||
android:layout_height="1dip"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
||||
<org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="16dp"
|
||||
custom:foldedLabel="@string/api_settings_show_advanced"
|
||||
custom:unFoldedLabel="@string/api_settings_hide_advanced">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="0dp"
|
||||
android:layout_margin="0dp">
|
||||
|
||||
<TextView
|
||||
android:paddingLeft="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="@string/label_encryption_algorithm"
|
||||
android:paddingRight="8dp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/api_account_settings_encryption_algorithm"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="0dp"
|
||||
android:layout_margin="0dp">
|
||||
|
||||
<TextView
|
||||
android:paddingLeft="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="@string/label_hash_algorithm"
|
||||
android:paddingRight="8dp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/api_account_settings_hash_algorithm"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="0dp"
|
||||
android:layout_margin="0dp">
|
||||
|
||||
<TextView
|
||||
android:paddingLeft="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="@string/label_message_compression"
|
||||
android:paddingRight="8dp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/api_account_settings_compression"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_include"
|
||||
layout="@layout/toolbar_standalone" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_below="@id/toolbar_include"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- focusable and related properties to workaround http://stackoverflow.com/q/16182331-->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:descendantFocusability="beforeDescendants"
|
||||
android:padding="16dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/api_select_sign_key_list_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="3dip"
|
||||
android:text="@string/api_select_sign_key_text"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/api_select_sign_key_list_fragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dip"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/api_select_sign_key_create_key"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:text="@string/api_settings_create_key"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||
android:drawableLeft="@drawable/ic_key_plus_grey600_24dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:clickable="true" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dip"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
@ -36,8 +36,8 @@
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/keyspinner_key_id"
|
||||
android:text="12345"
|
||||
android:id="@+id/keyspinner_duplicate"
|
||||
android:text="creation: bla"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
|
@ -38,7 +38,7 @@
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/select_key_item_key_id"
|
||||
android:id="@+id/select_key_item_creation"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="0xBBBBBBBBBBBBBBB"
|
||||
|
@ -31,27 +31,31 @@
|
||||
<h2>Libraries</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Libraries</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/zxing/zxing">ZXing</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<a href="https://github.com/journeyapps/zxing-android-embedded">ZXing Android Minimal</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/jpardogo/PagerSlidingTabStrip">PagerSlidingTabStrip (Material Design)</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<a href="https://github.com/neokree/MaterialNavigationDrawer">MaterialNavigationDrawer</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/nispok/snackbar">Snackbar</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="https://github.com/futuresimple/android-floating-action-button">FloatingActionButton</a> (Apache License v2)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +1,14 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h2>Getting started</h2>
|
||||
<p>First you need a personal key. Create one via the menu in "Keys" or import existing secret keys. Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
|
||||
|
||||
<p>On Android lower 4.4, it is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection.</p>
|
||||
|
||||
<h2>How do I activate OpenKeychain in K-9 Mail?</h2>
|
||||
<p>To use OpenKeychain with K-9 Mail, you want to follow these steps:</p>
|
||||
<ol>
|
||||
<li>Open K-9 Mail and long-tap on the account you want to use OpenKeychain with.</li>
|
||||
<li>Select "Account settings" and scroll to the very bottom and click "Cryptography".</li>
|
||||
<li>Click on "OpenPGP Provider" and select OpenKeychain from the list.</li>
|
||||
</ol>
|
||||
<h2>I found a bug in OpenKeychain!</h2>
|
||||
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<ol>
|
||||
<li>Make sure that NFC is turned on in Settings > More > NFC and make sure that Android Beam is also on in the same section.</li>
|
||||
<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
|
||||
<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
|
||||
<li>Tap the card and the content will then load on the other person’s device.</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -31,27 +31,31 @@
|
||||
<h2>Knihovny</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Libraries</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/zxing/zxing">ZXing</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<a href="https://github.com/journeyapps/zxing-android-embedded">ZXing Android Minimal</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/jpardogo/PagerSlidingTabStrip">PagerSlidingTabStrip (Material Design)</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<a href="https://github.com/neokree/MaterialNavigationDrawer">MaterialNavigationDrawer</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/nispok/snackbar">Snackbar</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="https://github.com/futuresimple/android-floating-action-button">FloatingActionButton</a> (Apache License v2)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +1,14 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h2>Začínáme</h2>
|
||||
<p>First you need a personal key. Create one via the menu in "Keys" or import existing secret keys. Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
|
||||
|
||||
<p>On Android lower 4.4, it is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection.</p>
|
||||
|
||||
<h2>How do I activate OpenKeychain in K-9 Mail?</h2>
|
||||
<p>To use OpenKeychain with K-9 Mail, you want to follow these steps:</p>
|
||||
<ol>
|
||||
<li>Open K-9 Mail and long-tap on the account you want to use OpenKeychain with.</li>
|
||||
<li>Select "Account settings" and scroll to the very bottom and click "Cryptography".</li>
|
||||
<li>Click on "OpenPGP Provider" and select OpenKeychain from the list.</li>
|
||||
</ol>
|
||||
<h2>Našel jsem chybu v OpenKeychain!</h2>
|
||||
<p>Nahlašte prosím chybu na <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">bug trackeru OpenKeychain</a>.</p>
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<ol>
|
||||
<li>Ujistěte se, že je NFC zapnuto v Nastavení > Další > NFC a ověřte, že Android Beam je ve stejné sekci také zapnutý.</li>
|
||||
<li>Podržte dvě zařízení zády k sobě (musí se téměř dotýkat) a ucítíte vibraci.</li>
|
||||
<li>Po tom co ucítíte vibraci, uvidíte že se obsah na displeji zařízení vašeho partnera změní na obrázek s animací připomínající rychlost warpu ze Star Treku.</li>
|
||||
<li>Tapněte na kartu a obsah se nahraje do zařízení.</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -31,27 +31,31 @@
|
||||
<h2>Bibliotheken</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Bibliothek v4</a> (Apache Lizenz v2)</li>
|
||||
<a href="https://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11-Lizenz)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Bibliothek v7 'appcompat'</a> (Apache Lizenz v2)</li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT-Lizenz)</li>
|
||||
<li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Apache License v2)</li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support-Bibliotheken</a> (Apache-Lizenz v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Apache-Lizenz v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache-Lizenz v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache-Lizenz v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache Lizenz v2)</li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache-Lizenz v2)</li>
|
||||
<li>
|
||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache Lizenz v2)</li>
|
||||
<a href="https://github.com/zxing/zxing">ZXing</a> (Apache-Lizenz v2)</li>
|
||||
<li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 Lizenz)</li>
|
||||
<a href="https://github.com/journeyapps/zxing-android-embedded">ZXing Android Minimal</a> (Apache-Lizenz v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache Lizenz v2)</li>
|
||||
<a href="https://github.com/jpardogo/PagerSlidingTabStrip">PagerSlidingTabStrip (Material-Design)</a> (Apache-Lizenz v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<a href="https://github.com/neokree/MaterialNavigationDrawer">MaterialNavigationDrawer</a> (Apache-Lizenz v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/nispok/snackbar">Snackbar</a> (MIT-Lizenz)</li>
|
||||
<li>
|
||||
<a href="https://github.com/futuresimple/android-floating-action-button">FloatingActionButton</a> (Apache-Lizenz v2)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -4,23 +4,23 @@
|
||||
|
||||
<h2>3.1.2</h2>
|
||||
<ul>
|
||||
<li>Behoben: Schlüsselexport in Datei (Jetzt wirklich)</li>
|
||||
<li>Behoben: Schlüsselexport in Datei (jetzt wirklich)</li>
|
||||
</ul>
|
||||
<h2>3.1.1</h2>
|
||||
<ul>
|
||||
<li>Behoben: Schlüsselexport in Datei (wurde nur teilweise geschrieben)</li>
|
||||
<li>Absturz auf Android 2.3 behoben</li>
|
||||
<li>Behoben: Absturz auf Android 2.3</li>
|
||||
</ul>
|
||||
<h2>3.1</h2>
|
||||
<ul>
|
||||
<li>Absturz auf Android 5 behoben</li>
|
||||
<li>New certify screen</li>
|
||||
<li>Secure Exchange directly from key list (SafeSlinger library)</li>
|
||||
<li>New QR Code program flow</li>
|
||||
<li>Redesigned decrypt screen</li>
|
||||
<li>New icon usage and colors</li>
|
||||
<li>Fix import of secret keys from Symantec Encryption Desktop</li>
|
||||
<li>Subkey IDs on Yubikeys are now checked correctly</li>
|
||||
<li>Behoben: Absturz auf Android 5</li>
|
||||
<li>Neuer Beglaubigungsbildschirm</li>
|
||||
<li>Sicherer Austausch direkt aus der Schlüsselliste (SafeSlinger-Bibliothek)</li>
|
||||
<li>Neuer Programmablauf für QR-Codes</li>
|
||||
<li>Neugestaltung des Entschlüsselungsbildschirms</li>
|
||||
<li>Verwendung neuer Icons und neuer Farben</li>
|
||||
<li>Behoben: Import geheimer Schlüssel von Symantec Encryption Desktop</li>
|
||||
<li>Unterschlüssel-IDs auf Yubikeys werden nun richtig geprüft</li>
|
||||
</ul>
|
||||
<h2>3.0.1</h2>
|
||||
<ul>
|
||||
@ -30,49 +30,49 @@
|
||||
<h2>3.0</h2>
|
||||
<ul>
|
||||
<li>Volle Unterstützung für Yubikey-Signaturerzeugung und Entschlüsselung!</li>
|
||||
<li>Kompatible, installierbare Apps in der Apps Liste anzeigen.</li>
|
||||
<li>Neues Design der Entschlüsselungsseite</li>
|
||||
<li>Many fixes for key import, also fixes stripped keys</li>
|
||||
<li>Honor and display key authenticate flags</li>
|
||||
<li>Kompatible, installierbare Apps in der App-Liste anzeigen</li>
|
||||
<li>Neues Design für den Entschlüsselungsbildschirm</li>
|
||||
<li>Viele Fehlerbehebungen für den Schlüsselimport, auch bei gekürzten Schlüsseln</li>
|
||||
<li>Schlüsselauthentifizierungs-Flags berücksichtigen und anzeigen</li>
|
||||
<li>Benutzeroberfläche zum Erzeugen benutzerdefinierter Schlüssel</li>
|
||||
<li>Fixing user id revocation certificates</li>
|
||||
<li>Neue Suche in der Cloud (sucht über traditionelle Schlüsselserver und über keybase.io)</li>
|
||||
<li>Support for stripping keys inside OpenKeychain</li>
|
||||
<li>Behoben: Benutzer-ID-Widerrufszertifikate</li>
|
||||
<li>Neue Cloudsuche (sucht über traditionelle Schlüsselserver und über keybase.io)</li>
|
||||
<li>Unterstützung für das Kürzen von Schlüsseln innerhalb von OpenKeychain</li>
|
||||
</ul>
|
||||
<h2>2.9.2</h2>
|
||||
<ul>
|
||||
<li>Defekte Schlüssel aus 2.9.1 behoben</li>
|
||||
<li>Behoben: Beschädigung von Schlüsseln in 2.9.1</li>
|
||||
<li>Yubikey-Entschlüsselung funktioniert nun über die API</li>
|
||||
</ul>
|
||||
<h2>2.9.1</h2>
|
||||
<ul>
|
||||
<li>Verschlüsselungsbildschirm auf zwei aufgeteilt</li>
|
||||
<li>Handhabung von Schlüsselflags ausgebessert (Unterstützt nun Mailvelope 0.7 Schlüssel)</li>
|
||||
<li>Handhabung von Passphrasen verbessert</li>
|
||||
<li>Behoben: Handhabung von Schlüsselflags (Unterstützt nun Mailvelope 0.7 Schlüssel)</li>
|
||||
<li>Handhabung von Passwörtern verbessert</li>
|
||||
<li>Schlüsselaustausch mit SafeSlinger</li>
|
||||
<li>Yubikey: Einstellung für andere PINs, zur Zeit funktioniert das Signieren nur mit der OpenPGP API, nicht innerhalb von OpenKeychain</li>
|
||||
<li>Verwendung von gekürzten Schlüsseln behoben</li>
|
||||
<li>Standardmäßig SHA256 aufgrund von Kompatibilität</li>
|
||||
<li>Änderungen an der Intent API, siehe https://github.com/open-keychain/open-keychain/wiki/Intent-API</li>
|
||||
<li>Das OpenPGP-API kann nun mit widerrufenen/abgelaufenen Schlüsseln umgehen und liefert alle Benutzerkennungen zurück</li>
|
||||
<li>Yubikey: neue Einstellung zur PIN-Änderung, zur Zeit funktioniert das Signieren nur mit der OpenPGP-API, nicht innerhalb von OpenKeychain</li>
|
||||
<li>Behoben: Verwendung von gekürzten Schlüsseln</li>
|
||||
<li>Standardmäßige Nutzung von SHA256 aus Kompatibilitätsgründen</li>
|
||||
<li>Änderungen an der Intent-API, siehe https://github.com/open-keychain/open-keychain/wiki/Intent-API</li>
|
||||
<li>OpenPGP-API kann nun mit widerrufenen/abgelaufenen Schlüsseln umgehen und liefert alle Benutzer-IDs zurück</li>
|
||||
</ul>
|
||||
<h2>2.9</h2>
|
||||
<ul>
|
||||
<li>Mit v2.8 eingeführte Abstürze behoben</li>
|
||||
<li>Behoben: Mit v2.8 eingeführte Abstürze</li>
|
||||
<li>Experimentelle ECC-Unterstützung</li>
|
||||
<li>Experimentelle Yubikey Unterstützung (Nur Signieren mit importierten Schlüsseln)</li>
|
||||
<li>Experimentelle Yubikey-Unterstützung (nur Signieren mit importierten Schlüsseln)</li>
|
||||
</ul>
|
||||
<h2>2.8</h2>
|
||||
<ul>
|
||||
<li>Es wurden in dieser Version so viele Fehler behoben, dass wir uns besser auf die neuen Funktionen konzentrieren</li>
|
||||
<li>Schlüsselbearbeitung: tolles neues Design und Schlüsselrückruf</li>
|
||||
<li>Schlüsselimport: tolles neues Design, gesicherte Verbindungen zum Schlüsselserver über HKPS, Schlüsselserver [?] über DNS SRV Einträge</li>
|
||||
<li>Neuer Bildschirm bei der ersten Öffnung</li>
|
||||
<li>Neuer Schlüsselerzeugungsbildschirm: Automatische Vorschläge für Name und E-Mail basierend auf Ihren persönlichen Android-Konten</li>
|
||||
<li>Dateiverschlüsselung: tolles neues Design, Unterstützung für mehrere Dateien</li>
|
||||
<li>Neue Symbole zum Anzeigen des Schlüsselstatus' (von Brennan Novak)</li>
|
||||
<li>Schlüsselimport: tolles neues Design, gesicherte Verbindungen zum Schlüsselserver über HKPS, Namensauflösung der Schlüsselserver über DNS SRV-Einträge</li>
|
||||
<li>Neuer Bildschirm für ersten Start der App</li>
|
||||
<li>Neuer Schlüsselerzeugungsbildschirm: Automatische Vorschläge für Name und E-Mail basierend auf deinen persönlichen Android-Konten</li>
|
||||
<li>Dateiverschlüsselung: tolles neues Design, Unterstützung für Verschlüsselung mehrerer Dateien</li>
|
||||
<li>Neue Symbole zum Anzeigen des Schlüsselstatus (von Brennan Novak)</li>
|
||||
<li>Wichtige Fehlerbehebung: Importieren größerer Schlüsselsammlungen aus einer Datei ist nun möglich</li>
|
||||
<li>Benachrichtigung, die die Passphrasen im Cache anzeigt</li>
|
||||
<li>Benachrichtigung, die zwischengespeicherte Passwörter anzeigt</li>
|
||||
<li>Schlüssel sind mit den Android-Kontakten verbunden</li>
|
||||
</ul>
|
||||
<p>Diese Version wäre ohne die Arbeit von Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray und Thialfihar nicht möglich</p>
|
||||
@ -82,109 +82,109 @@
|
||||
<li>Lila! (Dominik, Vincent)</li>
|
||||
<li>Neues Schlüsselansicht-Design (Dominik, Vincent)</li>
|
||||
<li>Neue flache Android-Schaltflächen (Dominik, Vincent)</li>
|
||||
<li>API-Fehler behoben (Dominik)</li>
|
||||
<li>API-Fehlerbehebungen (Dominik)</li>
|
||||
<li>Import aus keybase.io (Tim Bray)</li>
|
||||
</ul>
|
||||
<h2>2.6.1</h2>
|
||||
<ul>
|
||||
<li>Einige Behebungen für Regressionsfehler</li>
|
||||
<li>Einige Korrekturen für Regressionsfehler</li>
|
||||
</ul>
|
||||
<h2>2.6</h2>
|
||||
<ul>
|
||||
<li>Schlüsselzertifizierungen (danke an Vincent Breitmoser)</li>
|
||||
<li>Schlüsselbeglaubigungen (danke an Vincent Breitmoser)</li>
|
||||
<li>Unterstützung für GnuPG-Teilschlüssel (Dank an Vincent Breitmoser)</li>
|
||||
<li>Neues Design für Signaturverifikation</li>
|
||||
<li>Neues Design für Signaturprüfung</li>
|
||||
<li>Benutzerdefinierte Schlüssellänge (Dank an Greg Witczak)</li>
|
||||
<li>Fehler bei der Teilen-Funktion von anderen Apps behoben</li>
|
||||
</ul>
|
||||
<h2>2.5</h2>
|
||||
<ul>
|
||||
<li>Fix decryption of symmetric OpenPGP messages/files</li>
|
||||
<li>Refaktorisierter Schlüsselbearbeitungsbildschirm (Dank an Ash Hughes)</li>
|
||||
<li>Neues modernes Design für Verschlüsselungs-/Entschlüsselungs-Bildschirme</li>
|
||||
<li>OpenPGP API Version 3 (mehrfache API-Konten, interne Fehlerbehebungen, Schlüsselsuche)</li>
|
||||
<li>Behoben: Entschlüsselung von symmetrischen OpenPGP-Nachrichten/-Dateien</li>
|
||||
<li>Umgestaltung des Schlüsselbearbeitungsbildschirms (Dank an Ash Hughes)</li>
|
||||
<li>Neues modernes Design für Verschlüsselungs-/Entschlüsselungsbildschirme</li>
|
||||
<li>OpenPGP-API Version 3 (mehrerer API-Konten, interne Fehlerbehebungen, Schlüsselsuche)</li>
|
||||
</ul>
|
||||
<h2>2.4</h2>
|
||||
<p>Danke an alle Bewerber beim Google Summer of Code 2014, die diese Version funktionsreich und fehlerfrei gemacht haben.
|
||||
<p>Danke an alle Bewerber des Google Summer of Code 2014, die diese Version funktionsreich und fehlerfrei gemacht haben.
|
||||
Neben mehreren kleinen Updates sind eine beachtliche Anzahl von Updates von den folgenden Personen gemacht worden (in alphabetischer Reihenfolge):
|
||||
Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
|
||||
<ul>
|
||||
<li>Neue einheitliche Schlüsselliste</li>
|
||||
<li>Eingefärbter Schlüsselfingerabdruck</li>
|
||||
<li>Unterstützung für Schlüsselserverports</li>
|
||||
<li>Möglichkeit zum Erzeugen von schwachen Schlüssels deaktiviert</li>
|
||||
<li>Möglichkeit zum Erzeugen von schwachen Schlüsseln deaktiviert</li>
|
||||
<li>Viel mehr interne Arbeit an der API</li>
|
||||
<li>Benutzerkennungen zertifizieren</li>
|
||||
<li>Benutzerkennungen beglaubigen</li>
|
||||
<li>Schlüsselserver-Suchanfrage basierend auf maschinenlesbarer Ausgabe</li>
|
||||
<li>Lock navigation drawer on tablets</li>
|
||||
<li>Suggestions for emails on creation of keys</li>
|
||||
<li>"Navigation Drawer" auf Tablets sperren</li>
|
||||
<li>Vorschläge für E-Mails bei Schlüsselerzeugung</li>
|
||||
<li>Suche in öffentlichen Schlüssellisten</li>
|
||||
<li>Und viele weitere Verbesserungen und Fehlerbehebungen...</li>
|
||||
</ul>
|
||||
<h2>2.3.1</h2>
|
||||
<ul>
|
||||
<li>Hotfix for crash when upgrading from old versions</li>
|
||||
<li>Hotfix für Absturz beim Aktualisieren von alten Versionen</li>
|
||||
</ul>
|
||||
<h2>2.3</h2>
|
||||
<ul>
|
||||
<li>Remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
|
||||
<li>Fix setting expiry dates on keys (thanks to Ash Hughes)</li>
|
||||
<li>More internal fixes when editing keys (thanks to Ash Hughes)</li>
|
||||
<li>Querying keyservers directly from the import screen</li>
|
||||
<li>Anordnung und Dialogstil auf Android 2.2-3.0 behoben</li>
|
||||
<li>Absturz bei leeren Benutzerkennungen behoben</li>
|
||||
<li>Fix crash and empty lists when coming back from signing screen</li>
|
||||
<li>Bouncy Castle (Kryptographie Bibliothek) upgedatet von 1.47 auf 1.50 und vom Quellcode kompiliert.</li>
|
||||
<li>Fix upload of key from signing screen</li>
|
||||
<li>Kein unnötiger Export öffentlicher Schlüssel beim Export der geheimen Schlüssel (Dank an Ash Hughes)</li>
|
||||
<li>Behoben: Setzen des Schlüsselablaufdatums (Dank an Ash Hughes)</li>
|
||||
<li>Weitere interne Fehlerbehebungen für das Editieren von Schlüsseln (Dank an Ash Hughes)</li>
|
||||
<li>Schlüsselserverabfrage direkt aus dem Importbildschirm</li>
|
||||
<li>Behoben: Layout und Dialogstil auf Android 2.2-3.0</li>
|
||||
<li>Behoben: Absturz bei leeren Benutzer-IDs</li>
|
||||
<li>Behoben: Absturz nach Rückkehr vom Signierenbildschirm, außerdem wurden die Listen nicht geleert</li>
|
||||
<li>Bouncy Castle (Kryptographie-Bibliothek) von 1.47 auf 1.50 aktualisiert und aus Quellcode kompiliert.</li>
|
||||
<li>Behoben: Hochladen des Schlüssels aus dem Signierenbildschirm</li>
|
||||
</ul>
|
||||
<h2>2.2</h2>
|
||||
<ul>
|
||||
<li>New design with navigation drawer</li>
|
||||
<li>New public key list design</li>
|
||||
<li>Neues Design mit "Navigation Drawer"</li>
|
||||
<li>Neues Design der Liste öffentlicher Schlüssel</li>
|
||||
<li>Neue Ansicht für öffentliche Schlüssel</li>
|
||||
<li>Fehler beim Schlüsselimport behoben</li>
|
||||
<li>Key cross-certification (thanks to Ash Hughes)</li>
|
||||
<li>Handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
|
||||
<li>First version with new languages (thanks to the contributors on Transifex)</li>
|
||||
<li>Sharing of keys via QR Codes fixed and improved</li>
|
||||
<li>Package signature verification for API</li>
|
||||
<li>Behoben: Fehler beim Schlüsselimport</li>
|
||||
<li>Schlüsselbeglaubigungen über Kreuz, "Key cross-certification" (Dank an Ash Hughes)</li>
|
||||
<li>Korrekte Verarbeitung von UTF-8-Passwörtern (Dank an Ash Hughes)</li>
|
||||
<li>Erste Version mit neuen Sprachen (Dank an die Unterstützer auf Transifex)</li>
|
||||
<li>Behoben und verbessert: Teilen von Schlüsseln über QR-Codes</li>
|
||||
<li>Paket-Signaturprüfung für API</li>
|
||||
</ul>
|
||||
<h2>2.1.1</h2>
|
||||
<ul>
|
||||
<li>API-Aktualisierungen, Vorbereitung für die K-9 Mail-Integration</li>
|
||||
<li>API-Aktualisierungen, Vorbereitung für die "K-9 Mail"-Integration</li>
|
||||
</ul>
|
||||
<h2>2.1</h2>
|
||||
<ul>
|
||||
<li>Viele Fehlerbehebungen</li>
|
||||
<li>Neue API für Entwickler</li>
|
||||
<li>PRNG-Fehlerbehebungen von Google</li>
|
||||
<li>PRNG-Fehlerbehebung von Google</li>
|
||||
</ul>
|
||||
<h2>2.0</h2>
|
||||
<ul>
|
||||
<li>Complete redesign</li>
|
||||
<li>Öffentliche Schlüssel mit QR Codes oder NFC Beam teilen</li>
|
||||
<li>Komplette Neugestaltung</li>
|
||||
<li>Öffentliche Schlüssel über QR-Codes oder NFC-Beam teilen</li>
|
||||
<li>Schlüssel signieren</li>
|
||||
<li>Schlüssel auf den Server hochladen</li>
|
||||
<li>Importprobleme behoben</li>
|
||||
<li>Schlüssel auf Server hochladen</li>
|
||||
<li>Behoben: Importprobleme</li>
|
||||
<li>Neue AIDL-API</li>
|
||||
</ul>
|
||||
<h2>1.0.8</h2>
|
||||
<ul>
|
||||
<li>Grundlegende Schlüsselserverunterstützung</li>
|
||||
<li>App2sd</li>
|
||||
<li>Mehr Auswahlmöglichkeiten für den Passphrasencache: 1, 2, 4, 8, Stunden</li>
|
||||
<li>Translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
|
||||
<li>Mehr Auswahlmöglichkeiten für den Passwortzwischenspeicher: 1, 2, 4, 8, Stunden</li>
|
||||
<li>Übersetzungen: Norwegisch (Dank an Sander Danielsen), Chinesisch (Dank an Zhang Fredrick)</li>
|
||||
<li>Fehlerbehebungen</li>
|
||||
<li>Optimierungen</li>
|
||||
</ul>
|
||||
<h2>1.0.7</h2>
|
||||
<ul>
|
||||
<li>Fixed problem with signature verification of texts with trailing newline</li>
|
||||
<li>More options for passphrase cache time to live (20, 40, 60 mins)</li>
|
||||
<li>Behoben: Problem mit Signaturprüfung von Texten mit angehängtem Zeilenvorschub</li>
|
||||
<li>Mehr Optionen für die Länge der Passwortzwischenspeicherung (20, 40, 60 Minuten)</li>
|
||||
</ul>
|
||||
<h2>1.0.6</h2>
|
||||
<ul>
|
||||
<li>Account adding crash on Froyo fixed</li>
|
||||
<li>Behoben: Absturz bei Kontenerstellung unter Froyo</li>
|
||||
<li>Sichere Dateilöschung</li>
|
||||
<li>Option zum Löschen der Schlüsseldatei nach dem Import</li>
|
||||
<li>Streamverschlüsselung/-entschlüsselung (Galerie, usw.)</li>
|
||||
@ -195,37 +195,37 @@ Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Pa
|
||||
<h2>1.0.5</h2>
|
||||
<ul>
|
||||
<li>Deutsche und Italienische Übersetzung</li>
|
||||
<li>Much smaller package, due to reduced BC sources</li>
|
||||
<li>New preferences GUI</li>
|
||||
<li>Layout adjustment for localization</li>
|
||||
<li>Fehler bei Signatur behoben</li>
|
||||
<li>Viel kleineres Paket durch reduzierte BC-Quellen</li>
|
||||
<li>Neue Einstellungsoberfläche</li>
|
||||
<li>Layoutanpassungen für Übersetzungen</li>
|
||||
<li>Behoben: Signaturfehler</li>
|
||||
</ul>
|
||||
<h2>1.0.4</h2>
|
||||
<ul>
|
||||
<li>Fixed another crash caused by some SDK bug with query builder</li>
|
||||
<li>Behoben: Absturz durch einen SDK-Fehler mit "query builder"</li>
|
||||
</ul>
|
||||
<h2>1.0.3</h2>
|
||||
<ul>
|
||||
<li>Fixed crashes during encryption/signing and possibly key export</li>
|
||||
<li>Behoben: Abstürze während Verschlüsselung/Beglaubigung und möglicherweise Schlüsselexport</li>
|
||||
</ul>
|
||||
<h2>1.0.2</h2>
|
||||
<ul>
|
||||
<li>Filterable key lists</li>
|
||||
<li>Smarter pre-selection of encryption keys</li>
|
||||
<li>Filterbare Schlüsselliste</li>
|
||||
<li>Intelligentere Vorauswahl von Verschlüsselungsschlüsseln</li>
|
||||
<li>New Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
|
||||
<li>Fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
|
||||
<li>Fehlerbehebungen und zusätzliche Funktionen für K-9-Mail (Schlüsselvorauswahl), neuer Beta-Build verfügbar</li>
|
||||
</ul>
|
||||
<h2>1.0.1</h2>
|
||||
<ul>
|
||||
<li>GMail Account auflistung war nicht in Ordnung in 1.0.0, wieder behoben.</li>
|
||||
<li>Behoben: GMail-Konto-Auflistung in 1.0.0 fehlerhaft</li>
|
||||
</ul>
|
||||
<h2>1.0.0</h2>
|
||||
<ul>
|
||||
<li>K-9 Mail integration, APG unterstützt beta build von K-9 Mail</li>
|
||||
<li>Support of more file managers (including ASTRO)</li>
|
||||
<li>"K-9 Mail"-Integration, APG-unterstützendes Beta-Build von K-9 Mail</li>
|
||||
<li>Unterstützung weiterer Dateimanager (inklusive ASTRO)</li>
|
||||
<li>Slowenische Übersetzung</li>
|
||||
<li>New database, much faster, less memory usage</li>
|
||||
<li>Defined Intents and content provider for other apps</li>
|
||||
<li>Neue Datenbank, viel schneller, geringere Speichernutzung</li>
|
||||
<li>"Intents" und Inhaltsprovider für andere Apps definiert</li>
|
||||
<li>Fehlerbehebungen</li>
|
||||
</ul>
|
||||
</body>
|
||||
|
@ -1,19 +1,22 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h2>Los geht's</h2>
|
||||
<p>Zuerst wird ein geheimer Schlüssel benötigt. Erstelle einen über das Menü "Keys" oder importiere einen bereits existierenden geheimen Schlüssel. Anschließend kannst du die Schlüssel deiner Freunde herunterladen oder über QR-Codes oder NFC austauschen.</p>
|
||||
|
||||
<p>Auf Android-Geräte mit einer kleineren Versionsnummer als 4.4 wird empfohlen den Datei-Browser <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> zu installieren.</p>
|
||||
|
||||
<h2>Wie kann ich OpenKeychain in K-9 Mail nutzen?</h2>
|
||||
<p>Um OpenKeychain in K-9 Mail nutzen zu können, sind folgende Schritte nötig:</p>
|
||||
<ol>
|
||||
<li>Öffne K-9 Mail und drücke lange auf den Account, mit dem du OpenKeychain nutzen willst.</li>
|
||||
<li>Wähle "Kontoeinstellungen", blättere ganz nach unten und klicke auf "Kryptographie".</li>
|
||||
<li>Klicke auf "OpenPGP-Provider" und wähle OpenKeychain aus der Liste.</li>
|
||||
</ol>
|
||||
<h2>Ich habe einen Fehler in OpenKeychain gefunden!</h2>
|
||||
<p>Bitte berichten Sie Bugs mithilfe des <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">Issue Trackers der OpenKeychain</a>.</p>
|
||||
<p>Bitte sende uns einen Fehlerbericht mithilfe des <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">Problem-Trackers von OpenKeychain</a>.</p>
|
||||
|
||||
<h2>Unterstützen</h2>
|
||||
<p>Wenn Sie uns bei der Entwickelung von OpenKeychain durch das Beisteuern von Code helfen wollen, <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">schauen Sie unsere kurze Anleitung auf Github an</a>.</p>
|
||||
<p>Wenn du uns bei der Entwicklung von OpenKeychain, z.B. durch das Beisteuern von Code, helfen willst, <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">schau dir unsere kurze Anleitung auf GitHub an</a>.</p>
|
||||
|
||||
<h2>Übersetzungen</h2>
|
||||
<p>Hilf mit, OpenKeychain zu übersetzten! Jeder kann auf <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain auf Transifex</a> mitmachen.</p>
|
||||
<p>Hilf mit OpenKeychain zu übersetzten! Jeder kann mitmachen, besuche<a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain auf Transifex</a>.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<ol>
|
||||
<li>Stellen Sie sicher, dass NFC und Android Beam in den Einstellungen unter > Mehr > NFC eingeschaltet sind</li>
|
||||
<li>Halten sie die zwei Geräte rückseitig aneinander (sodass sie sich fast berühren) und es wird vibrieren</li>
|
||||
<li>Nachdem es vibriert sehen sie wie der Inhalt ihres Gerätes von einer Warp-Geschwindigkeit Animation umgeben wird</li>
|
||||
<li>Drücken Sie auf die Karte und der Inhalt wird auf das Gerät des Anderen geladen.</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -31,27 +31,31 @@
|
||||
<h2>Librerías</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Licencia Apache v2)</li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licencia MIT X11)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Licencia Apache v2)</li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">Librería SafeSlinger Exchange</a> (Licencia MIT)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Suppor Libraries</a> (Licencia Apache v2) [librerías de soporte de Android]</li>
|
||||
<li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Licencia Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Licencia Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Licencia Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Licencia Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Licencia Apache v2)</li>
|
||||
<li>
|
||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Licencia Apache v2)</li>
|
||||
<a href="https://github.com/zxing/zxing">ZXing</a> (Licencia Apache v2)</li>
|
||||
<li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licencia MIT X11)</li>
|
||||
<a href="https://github.com/journeyapps/zxing-android-embedded">ZXing Android Minimal</a> (Licencia Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licencia Apache v2)</li>
|
||||
<a href="https://github.com/jpardogo/PagerSlidingTabStrip">PagerSlidingTabStrip</a> (Licencia Apache v2) [indicador deslizante para paso de página estilo Material]</li>
|
||||
<li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">Librería SafeSlinger Exchange</a> (Licencia MIT)</li>
|
||||
<a href="https://github.com/neokree/MaterialNavigationDrawer">MaterialNavigationDrawer</a> (Licencia Apache v2) [panel de navegación estilo Material]</li>
|
||||
<li>
|
||||
<a href="https://github.com/nispok/snackbar">Snackbar</a> (Licencia MIT)</li>
|
||||
<li>
|
||||
<a href="https://github.com/futuresimple/android-floating-action-button">FloatingActionButton</a> (Licencia Apache v2) [botón de acción flotante]</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +1,14 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h2>Primeros pasos</h2>
|
||||
<p>Primero, necesita una clave personal. Cree una a través del menú en "Claves" o importe claves secretas (privadas) existentes. Después, puede descargar las claves de sus amigos o intercambiarlas mediante códigos QR o transmisión NFC.</p>
|
||||
|
||||
<p>En Android inferior a 4.4, se recomienda que instale <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> para una selección de ficheros mejorada.</p>
|
||||
|
||||
<h2>¿Cómo activo OpenKeychain in K-9 Mail?</h2>
|
||||
<p>Para utilizar OpenKeychain con K-9 Mail, querrá seguir estos pasos:</p>
|
||||
<ol>
|
||||
<li>Abra K-9 Mail y realice una pulsación larga en la cuenta con la que quiera utilizar OpenKeychain.</li>
|
||||
<li>Seleccione "Configuración de cuenta", deplácese al fondo del todo y haga clic en "Criptografía".</li>
|
||||
<li>Haga clic en "Proveedor OpenPGP" y de la lista seleccione OpenKeychain.</li>
|
||||
</ol>
|
||||
<h2>¡He encontrado un bug en OpenKeychain!</h2>
|
||||
<p>Por favor, informa de errores usando el <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">seguimiento de incidencias de OpenKeychain</a>.</p>
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<ol>
|
||||
<li>Asegúrate de que NFC está encendido en Ajustes > Más > NFC, y asegúrate de que Android Beam está también activado en ese mismo apartado.</li>
|
||||
<li>Mantén los dos dispositivos con ambos reversos juntos (deben estar casi en contacto) y notarás una vibración.</li>
|
||||
<li>Después de la vibración verás el contenido de tu dispositivo convertirse en una especie de ficha con una animación de Star Trek de fondo.</li>
|
||||
<li>Pulsa la ficha y el contenido será cargado en el dispositivo de la otra persona.</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -31,27 +31,31 @@
|
||||
<h2>Libraries</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Libraries</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/zxing/zxing">ZXing</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<a href="https://github.com/journeyapps/zxing-android-embedded">ZXing Android Minimal</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/jpardogo/PagerSlidingTabStrip">PagerSlidingTabStrip (Material Design)</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<a href="https://github.com/neokree/MaterialNavigationDrawer">MaterialNavigationDrawer</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/nispok/snackbar">Snackbar</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="https://github.com/futuresimple/android-floating-action-button">FloatingActionButton</a> (Apache License v2)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +1,14 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h2>Getting started</h2>
|
||||
<p>First you need a personal key. Create one via the menu in "Keys" or import existing secret keys. Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
|
||||
|
||||
<p>On Android lower 4.4, it is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection.</p>
|
||||
|
||||
<h2>How do I activate OpenKeychain in K-9 Mail?</h2>
|
||||
<p>To use OpenKeychain with K-9 Mail, you want to follow these steps:</p>
|
||||
<ol>
|
||||
<li>Open K-9 Mail and long-tap on the account you want to use OpenKeychain with.</li>
|
||||
<li>Select "Account settings" and scroll to the very bottom and click "Cryptography".</li>
|
||||
<li>Click on "OpenPGP Provider" and select OpenKeychain from the list.</li>
|
||||
</ol>
|
||||
<h2>I found a bug in OpenKeychain!</h2>
|
||||
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<ol>
|
||||
<li>Make sure that NFC is turned on in Settings > More > NFC and make sure that Android Beam is also on in the same section.</li>
|
||||
<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
|
||||
<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
|
||||
<li>Tap the card and the content will then load on the other person’s device.</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -2,12 +2,12 @@
|
||||
<head></head>
|
||||
<body>
|
||||
<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
|
||||
<p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
|
||||
<p>License: GPLv3+</p>
|
||||
<p><a href="http://www.openkeychain.org">OpenKeychain</a> Android-rako OpenPGP inplemetazio bat da.</p>
|
||||
<p>Baimena: GPLv3+</p>
|
||||
|
||||
<h2>Developers</h2>
|
||||
<h2>Garatzaileak</h2>
|
||||
<ul>
|
||||
<li>Dominik Schürmann (Maintainer)</li>
|
||||
<li>Dominik Schürmann (Mantentzailea)</li>
|
||||
<li>Art O Cathain</li>
|
||||
<li>Ash Hughes</li>
|
||||
<li>Brian C. Barnes</li>
|
||||
@ -28,30 +28,34 @@
|
||||
<li>Tim Bray</li>
|
||||
<li>Vincent Breitmoser</li>
|
||||
</ul>
|
||||
<h2>Libraries</h2>
|
||||
<h2>Liburutegiak</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 Baimena)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT Baimena)</li>
|
||||
<li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Apache License v2)</li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Libraries</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Apache Baimena v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache Baimena v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache Baimena v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache Baimena v2)</li>
|
||||
<li>
|
||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/zxing/zxing">ZXing</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<a href="https://github.com/journeyapps/zxing-android-embedded">ZXing Android Minimal</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/jpardogo/PagerSlidingTabStrip">PagerSlidingTabStrip (Material Design)</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<a href="https://github.com/neokree/MaterialNavigationDrawer">MaterialNavigationDrawer</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/nispok/snackbar">Snackbar</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="https://github.com/futuresimple/android-floating-action-button">FloatingActionButton</a> (Apache License v2)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,19 +1,22 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h2>Getting started</h2>
|
||||
<p>First you need a personal key. Create one via the menu in "Keys" or import existing secret keys. Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
|
||||
|
||||
<p>On Android lower 4.4, it is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection.</p>
|
||||
|
||||
<h2>I found a bug in OpenKeychain!</h2>
|
||||
<h2>How do I activate OpenKeychain in K-9 Mail?</h2>
|
||||
<p>To use OpenKeychain with K-9 Mail, you want to follow these steps:</p>
|
||||
<ol>
|
||||
<li>Open K-9 Mail and long-tap on the account you want to use OpenKeychain with.</li>
|
||||
<li>Select "Account settings" and scroll to the very bottom and click "Cryptography".</li>
|
||||
<li>Click on "OpenPGP Provider" and select OpenKeychain from the list.</li>
|
||||
</ol>
|
||||
<h2>Akats bat aurkitu dut OpenKeychain-en!</h2>
|
||||
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
|
||||
|
||||
<h2>Contribute</h2>
|
||||
<h2>Lagundu</h2>
|
||||
<p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
|
||||
|
||||
<h2>Translations</h2>
|
||||
<p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
|
||||
<h2>Itzulpenak</h2>
|
||||
<p>Lagundu OpenKeychain itzultzen! Edonork eskuhartu dezake hemen <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychainTransifex-en</a>.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<ol>
|
||||
<li>Make sure that NFC is turned on in Settings > More > NFC and make sure that Android Beam is also on in the same section.</li>
|
||||
<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
|
||||
<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
|
||||
<li>Tap the card and the content will then load on the other person’s device.</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -31,27 +31,31 @@
|
||||
<h2>Libraries</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Libraries</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/zxing/zxing">ZXing</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<a href="https://github.com/journeyapps/zxing-android-embedded">ZXing Android Minimal</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/jpardogo/PagerSlidingTabStrip">PagerSlidingTabStrip (Material Design)</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<a href="https://github.com/neokree/MaterialNavigationDrawer">MaterialNavigationDrawer</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/nispok/snackbar">Snackbar</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="https://github.com/futuresimple/android-floating-action-button">FloatingActionButton</a> (Apache License v2)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +1,14 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h2>Getting started</h2>
|
||||
<p>First you need a personal key. Create one via the menu in "Keys" or import existing secret keys. Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
|
||||
|
||||
<p>On Android lower 4.4, it is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection.</p>
|
||||
|
||||
<h2>How do I activate OpenKeychain in K-9 Mail?</h2>
|
||||
<p>To use OpenKeychain with K-9 Mail, you want to follow these steps:</p>
|
||||
<ol>
|
||||
<li>Open K-9 Mail and long-tap on the account you want to use OpenKeychain with.</li>
|
||||
<li>Select "Account settings" and scroll to the very bottom and click "Cryptography".</li>
|
||||
<li>Click on "OpenPGP Provider" and select OpenKeychain from the list.</li>
|
||||
</ol>
|
||||
<h2>I found a bug in OpenKeychain!</h2>
|
||||
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<ol>
|
||||
<li>Make sure that NFC is turned on in Settings > More > NFC and make sure that Android Beam is also on in the same section.</li>
|
||||
<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
|
||||
<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
|
||||
<li>Tap the card and the content will then load on the other person’s device.</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -31,27 +31,31 @@
|
||||
<h2>Bibliothèques</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Bibliothèque de soutien Android v4</a> (Licence Apache v2)</li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licence MIT X11)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Bibliothèque de soutien Android v7 « appcompat »</a> (Licence Apache v2)</li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">Bibliothèque d'échange SafeSlinger</a> (Licence MIT)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Bibliothèques de soutien Android</a> (Licence Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Licence Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (License Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (License Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (License Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Licence Apache v2)</li>
|
||||
<li>
|
||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Licence Apache v2)</li>
|
||||
<a href="https://github.com/zxing/zxing">ZXing</a> (Licence Apache v2)</li>
|
||||
<li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licence MIT X11)</li>
|
||||
<a href="https://github.com/journeyapps/zxing-android-embedded">ZXing Android Minimal</a> (Licence Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licence Apache v2)</li>
|
||||
<a href="https://github.com/jpardogo/PagerSlidingTabStrip">PagerSlidingTabStrip (conception matérielle )</a> (Licence Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">Bibliothèque d'échange SafeSlinger</a> (Licence MIT)</li>
|
||||
<a href="https://github.com/neokree/MaterialNavigationDrawer">MaterialNavigationDrawer</a> (Licence Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/nispok/snackbar">Snackbar</a> (Licence MIT)</li>
|
||||
<li>
|
||||
<a href="https://github.com/futuresimple/android-floating-action-button">FloatingActionButton</a> (Licence Apache v2)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +1,14 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h2>Commencer</h2>
|
||||
<p>Vous avez d'abord besoin d'une clef personnelle. Créez-en une avec l'option du menu « Clefs » ou importez des clefs secrètes existantes. Ensuite vous pourrez télécharger les clefs de vos amis, ou les échanger par codes QR ou NFC.</p>
|
||||
|
||||
<p>Sur les versions d'Android antérieures à 4.4, il vous est recommandé d'installer le<a href="market://details?id=org.openintents.filemanager">gestionnaire de fichiers OI</a> pour une sélection améliorée des fichiers.</p>
|
||||
|
||||
<h2>Comment puis-je activer OpenKeychain dans K-9 Mail ?</h2>
|
||||
<p>Pour utiliser OpenKeychain avec K-9 Mail, vous devez suivre ces étapes :</p>
|
||||
<ol>
|
||||
<li>Ouvrez K-9 Mail et toquez longuement sur le compte avec lequel vous voulez utiliser OpenKeychain. </li>
|
||||
<li>Sélectionnez « Paramètres du compte », faite défiler vers le bas et cliquez sur « Cryptographie».</li>
|
||||
<li>Cliquez sur « Fournisseur OpenPGP » et sélectionnez OpenKeychain dans la liste.</li>
|
||||
</ol>
|
||||
<h2>J'ai trouvé un bogue dans OpenKeychain !</h2>
|
||||
<p>Veuillez rapporter le bogue en utilisant le <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">gestionnaire de bogue d'OpenKeychain</a>.</p>
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<ol>
|
||||
<li>Assurez-vous que la NFC est activée dans Paramètres > Paramètres supplémentaires > NFC, ainsi que Android Beam. </li>
|
||||
<li>Tenir les deux appareils dos à dos (se touchant presque) et une vibration sera ressentie.</li>
|
||||
<li>Après la vibration, le contenu de votre appareil deviendra un objet en forme de carte avec une animation à la Star Trek en arrière-plan.</li>
|
||||
<li>Toquer la carte et le contenu se chargera alors sur votre appareil.</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -31,27 +31,31 @@
|
||||
<h2>Libraries</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Libraries</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/zxing/zxing">ZXing</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<a href="https://github.com/journeyapps/zxing-android-embedded">ZXing Android Minimal</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/jpardogo/PagerSlidingTabStrip">PagerSlidingTabStrip (Material Design)</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<a href="https://github.com/neokree/MaterialNavigationDrawer">MaterialNavigationDrawer</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/nispok/snackbar">Snackbar</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="https://github.com/futuresimple/android-floating-action-button">FloatingActionButton</a> (Apache License v2)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +1,14 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h2>Getting started</h2>
|
||||
<p>First you need a personal key. Create one via the menu in "Keys" or import existing secret keys. Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
|
||||
|
||||
<p>On Android lower 4.4, it is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection.</p>
|
||||
|
||||
<h2>How do I activate OpenKeychain in K-9 Mail?</h2>
|
||||
<p>To use OpenKeychain with K-9 Mail, you want to follow these steps:</p>
|
||||
<ol>
|
||||
<li>Open K-9 Mail and long-tap on the account you want to use OpenKeychain with.</li>
|
||||
<li>Select "Account settings" and scroll to the very bottom and click "Cryptography".</li>
|
||||
<li>Click on "OpenPGP Provider" and select OpenKeychain from the list.</li>
|
||||
</ol>
|
||||
<h2>I found a bug in OpenKeychain!</h2>
|
||||
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<ol>
|
||||
<li>Make sure that NFC is turned on in Settings > More > NFC and make sure that Android Beam is also on in the same section.</li>
|
||||
<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
|
||||
<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
|
||||
<li>Tap the card and the content will then load on the other person’s device.</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -31,27 +31,31 @@
|
||||
<h2>Librerie</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Licenza Apache v2)</li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licenza MIT X11)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Licenza Apache v2)</li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">Libreria SafeSlinger Exchange</a> (Licenza MIT)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Libraries</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Licenza Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Licenza Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Licenza Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Licenza Apache v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Licenza Apache v2)</li>
|
||||
<li>
|
||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Licenza Apache v2)</li>
|
||||
<a href="https://github.com/zxing/zxing">ZXing</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licenza MIT X11)</li>
|
||||
<a href="https://github.com/journeyapps/zxing-android-embedded">ZXing Android Minimal</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licenza Apache v2)</li>
|
||||
<a href="https://github.com/jpardogo/PagerSlidingTabStrip">PagerSlidingTabStrip (Material Design)</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">Libreria SafeSlinger Exchange</a> (Licenza MIT)</li>
|
||||
<a href="https://github.com/neokree/MaterialNavigationDrawer">MaterialNavigationDrawer</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/nispok/snackbar">Snackbar</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="https://github.com/futuresimple/android-floating-action-button">FloatingActionButton</a> (Apache License v2)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +1,14 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h2>Per iniziare</h2>
|
||||
<p>In primo luogo è necessaria una chiave segreta personale. Creane una tramite il menu opzioni sotto la voce "Chiavi" o importa chiavi segrete già esistenti. Successivamente, è possibile scaricare le chiavi dei vostri amici o scambiarle con i codici QR o NFC.</p>
|
||||
|
||||
<p>On Android lower 4.4, it is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection.</p>
|
||||
|
||||
<h2>How do I activate OpenKeychain in K-9 Mail?</h2>
|
||||
<p>To use OpenKeychain with K-9 Mail, you want to follow these steps:</p>
|
||||
<ol>
|
||||
<li>Open K-9 Mail and long-tap on the account you want to use OpenKeychain with.</li>
|
||||
<li>Select "Account settings" and scroll to the very bottom and click "Cryptography".</li>
|
||||
<li>Click on "OpenPGP Provider" and select OpenKeychain from the list.</li>
|
||||
</ol>
|
||||
<h2>Ho trovato un bug in OpenKeychain!</h2>
|
||||
<p>Per favore riporta i bug usando il <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker di OpenKeychain</a>.</p>
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<ol>
|
||||
<li>Assicurati che NFC sia acceso in Impostazioni > Altro > NFC a assicurati che Android Beam sia pure su On nella stessa sezione.</li>
|
||||
<li>Mantieni i due dispositivi vicini (devono quasi toccarsi) e sentirai una vibrazione.</li>
|
||||
<li>Dopo che ha vibrato, vedrai il contenuto del tuo dispositivo diventare come una scheda e nello sfondo apparirà una animazione come la propulsione a curvatura di Star Trek.</li>
|
||||
<li>Tocca la scheda e il contenuto dopo si trasferira' nel dispositivo dell'altra persona.</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -31,27 +31,31 @@
|
||||
<h2>ライブラリ</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Libraries</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/zxing/zxing">ZXing</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||
<a href="https://github.com/journeyapps/zxing-android-embedded">ZXing Android Minimal</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
|
||||
<a href="https://github.com/jpardogo/PagerSlidingTabStrip">PagerSlidingTabStrip (Material Design)</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT License)</li>
|
||||
<a href="https://github.com/neokree/MaterialNavigationDrawer">MaterialNavigationDrawer</a> (Apache License v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/nispok/snackbar">Snackbar</a> (MIT License)</li>
|
||||
<li>
|
||||
<a href="https://github.com/futuresimple/android-floating-action-button">FloatingActionButton</a> (Apache License v2)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +1,14 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h2>入門</h2>
|
||||
<p>最初にあなたの個人用鍵ペアが必要になります。メニューの"鍵"で生成するか、既存の鍵ペアをインポートします。その後、あなたの友人の鍵をダウンロード、もしくはQRコードやNFCで交換します。</p>
|
||||
|
||||
<p>Android 4.4 未満の場合、拡張したファイルの選択のためには<a href="market://details?id=org.openintents.filemanager">OI File Manager</a>のインストールを推奨します。</p>
|
||||
|
||||
<h2>How do I activate OpenKeychain in K-9 Mail?</h2>
|
||||
<p>To use OpenKeychain with K-9 Mail, you want to follow these steps:</p>
|
||||
<ol>
|
||||
<li>Open K-9 Mail and long-tap on the account you want to use OpenKeychain with.</li>
|
||||
<li>Select "Account settings" and scroll to the very bottom and click "Cryptography".</li>
|
||||
<li>Click on "OpenPGP Provider" and select OpenKeychain from the list.</li>
|
||||
</ol>
|
||||
<h2>OpenKeychainでバグを見付けた!</h2>
|
||||
<p><a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">OpenKeychainのIssueトラッカー</a>を使ってバグレポートを送ってください。</p>
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<ol>
|
||||
<li>設定 > その他 > NFC からNFCを有効にしてください、そしてAndroid Beamもまた選択してください。</li>
|
||||
<li>2つのデバイスを背中合せ(ほとんどすべてのタッチ方法)にしてバイブを感じるまで保持しておいてください。</li>
|
||||
<li>バイブの後、相手のデバイスでスタートレック風のバックグラウンドアニメーションしているカード風のコンテンツを見ると思います。</li>
|
||||
<li>カードをタップしコンテンツを他のデバイスに読み込ませてください。</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -31,27 +31,31 @@
|
||||
<h2>Bibliotheken</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Biblitheek v4</a> (Apache Licentie v2)</li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 Licentie)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Bibliotheek v7 'appcompat'</a> (Apache Licentie v2)</li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT-licentie)</li>
|
||||
<li>
|
||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Libraries</a> (Apache Licentie v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/timbray/KeybaseLib">KeybaseLib</a> (Apache-licentie v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/JohnPersano/SuperToasts">SuperToasts</a> (Apache-licentie v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/splitwise/TokenAutoComplete">TokenAutoComplete</a> (Apache-licentie v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/rtreffer/minidns">MiniDNS</a> (Apache-licentie v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache Licentie v2)</li>
|
||||
<li>
|
||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache Licentie v2)</li>
|
||||
<a href="https://github.com/zxing/zxing">ZXing</a> (Apache Licentie v2)</li>
|
||||
<li>
|
||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 Licentie)</li>
|
||||
<a href="https://github.com/journeyapps/zxing-android-embedded">ZXing Android Minimal</a> (Apache Licentie v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache Licentie v2)</li>
|
||||
<a href="https://github.com/jpardogo/PagerSlidingTabStrip">PagerSlidingTabStrip (Material Design)</a> (Apache Licentie v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/SafeSlingerProject/exchange-android">SafeSlinger Exchange library</a> (MIT-licentie)</li>
|
||||
<a href="https://github.com/neokree/MaterialNavigationDrawer">MaterialNavigationDrawer</a> (Apache Licentie v2)</li>
|
||||
<li>
|
||||
<a href="https://github.com/nispok/snackbar">Snackbar</a> (MIT Licentie)</li>
|
||||
<li>
|
||||
<a href="https://github.com/futuresimple/android-floating-action-button">FloatingActionButton</a> (Apache Licentie v2)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +1,14 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h2>Aan de slag</h2>
|
||||
<p>Eerst heb je een persoonlijke sleutel nodig. Maak er een aan via het menu in 'Sleutels' of importeer bestaande geheime sleutels. Nadien kan je de sleutels van je vrienden downloaden of ze uitwisselen via QR codes of NFC.</p>
|
||||
|
||||
<p>Op Android-versies lager dan 4.4 raden we aan dat je <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> installeert voor een verbeterde bestandsselectie.</p>
|
||||
|
||||
<h2>Hoe activeer ik OpenKeychain in K-9 Mail?</h2>
|
||||
<p>Volg deze stappen om OpenKeychain te gebruiken met K-9 Mail:</p>
|
||||
<ol>
|
||||
<li>Open K-9 Mail en druk lang op de account waarmee je OpenKeychain wil gebruiken.</li>
|
||||
<li>Selecteer "Accountinstellingen", scroll helemaal naar beneden en klik op "Cryptografie".</li>
|
||||
<li>Klik op "OpenPGP-provider" en selecteer OpenKeychain in de lijst.</li>
|
||||
</ol>
|
||||
<h2>Ik heb een bug in OpenKeychain gevonden!</h2>
|
||||
<p>Rapporteer de bug met de <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">problemen tracker van OpenKeychain</a>.</p>
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user