diff options
121 files changed, 2186 insertions, 630 deletions
| diff --git a/.gitmodules b/.gitmodules index f18a8731b..b7b0e1173 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@  [submodule "extern/StickyListHeaders"]  	path = extern/StickyListHeaders  	url = https://github.com/open-keychain/StickyListHeaders.git -[submodule "extern/AndroidBootstrap"] -	path = extern/AndroidBootstrap -	url = https://github.com/open-keychain/Android-Bootstrap.git  [submodule "extern/zxing-android-integration"]  	path = extern/zxing-android-integration  	url = https://github.com/open-keychain/zxing-android-integration.git @@ -30,7 +27,10 @@  	url = https://github.com/open-keychain/SuperToasts.git  [submodule "extern/KeybaseLib"]  	path = extern/KeybaseLib -	url = https://github.com/timbray/KeybaseLib.git +	url = https://github.com/open-keychain/KeybaseLib.git  [submodule "extern/minidns"]  	path = extern/minidns  	url = https://github.com/open-keychain/minidns.git +[submodule "OpenKeychain/src/test/resources/extern/OpenPGP-Haskell"] +	path = OpenKeychain/src/test/resources/extern/OpenPGP-Haskell +	url = https://github.com/singpolyma/OpenPGP-Haskell.git diff --git a/.travis.yml b/.travis.yml index 36e8f8fcf..5da831e61 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,13 +4,14 @@ before_install:      # Install base Android SDK      - sudo apt-get update -qq      - if [ `uname -m` = x86_64 ]; then sudo apt-get install -qq --force-yes libgd2-xpm lib32z1 lib32stdc++6; fi -    - wget http://dl.google.com/android/android-sdk_r22.6.2-linux.tgz -    - tar xzf android-sdk_r22.6.2-linux.tgz +    - wget http://dl.google.com/android/android-sdk_r23-linux.tgz +    - tar xzf android-sdk_r23-linux.tgz      - export ANDROID_HOME=$PWD/android-sdk-linux      - export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools      # Install required Android components. -    - echo "y" | android update sdk -a --filter build-tools-19.1.0,android-19,platform-tools,extra-android-support,extra-android-m2repository --no-ui --force +    #- echo "y" | android update sdk -a --filter build-tools-19.1.0,android-19,platform-tools,extra-android-support,extra-android-m2repository --no-ui --force +    - ( sleep 5 && while [ 1 ]; do sleep 1; echo y; done ) | android update sdk --no-ui --all --force --filter build-tools-19.1.0,android-19,platform-tools,extra-android-support,extra-android-m2repository  install: echo "Installation done"  script: gradle assemble -S -q diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle index fd0c4c6ba..f419141b4 100644 --- a/OpenKeychain/build.gradle +++ b/OpenKeychain/build.gradle @@ -10,7 +10,6 @@ dependencies {      compile project(':extern:openkeychain-api-lib')      compile project(':extern:html-textview')      compile project(':extern:StickyListHeaders:library') -    compile project(':extern:AndroidBootstrap:AndroidBootstrap')      compile project(':extern:zxing-qr-code')      compile project(':extern:zxing-android-integration')      compile project(':extern:spongycastle:core') diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index c6e528f4d..3ce200008 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -59,6 +59,7 @@      <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>      <uses-permission android:name="android.permission.READ_CONTACTS" />      <uses-permission android:name="android.permission.WRITE_CONTACTS" /> +    <uses-permission android:name="android.permission.READ_PROFILE" />      <!-- android:allowBackup="false": Don't allow backup over adb backup or other apps! -->      <application @@ -80,6 +81,11 @@              </intent-filter>          </activity>          <activity +            android:name=".ui.WizardActivity" +            android:configChanges="orientation|screenSize|keyboardHidden|keyboard" +            android:label="@string/title_wizard" +            android:windowSoftInputMode="stateHidden" /> +        <activity              android:name=".ui.EditKeyActivity"              android:configChanges="orientation|screenSize|keyboardHidden|keyboard"              android:label="@string/title_edit_key" diff --git a/OpenKeychain/src/main/assets/fontawesome-webfont.ttf b/OpenKeychain/src/main/assets/fontawesome-webfont.ttfBinary files differ deleted file mode 100644 index 7ec2e1de8..000000000 --- a/OpenKeychain/src/main/assets/fontawesome-webfont.ttf +++ /dev/null diff --git a/OpenKeychain/src/main/assets/sks-keyservers.netCA.cer b/OpenKeychain/src/main/assets/sks-keyservers.netCA.cer new file mode 100644 index 000000000..24a2ad2e8 --- /dev/null +++ b/OpenKeychain/src/main/assets/sks-keyservers.netCA.cer @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFizCCA3OgAwIBAgIJAK9zyLTPn4CPMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNV +BAYTAk5PMQ0wCwYDVQQIDARPc2xvMR4wHAYDVQQKDBVza3Mta2V5c2VydmVycy5u +ZXQgQ0ExHjAcBgNVBAMMFXNrcy1rZXlzZXJ2ZXJzLm5ldCBDQTAeFw0xMjEwMDkw +MDMzMzdaFw0yMjEwMDcwMDMzMzdaMFwxCzAJBgNVBAYTAk5PMQ0wCwYDVQQIDARP +c2xvMR4wHAYDVQQKDBVza3Mta2V5c2VydmVycy5uZXQgQ0ExHjAcBgNVBAMMFXNr +cy1rZXlzZXJ2ZXJzLm5ldCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBANdsWy4PXWNUCkS3L//nrd0GqN3dVwoBGZ6w94Tw2jPDPifegwxQozFXkG6I +6A4TK1CJLXPvfz0UP0aBYyPmTNadDinaB9T4jIwd4rnxl+59GiEmqkN3IfPsv5Jj +MkKUmJnvOT0DEVlEaO1UZIwx5WpfprB3mR81/qm4XkAgmYrmgnLXd/pJDAMk7y1F +45b5zWofiD5l677lplcIPRbFhpJ6kDTODXh/XEdtF71EAeaOdEGOvyGDmCO0GWqS +FDkMMPTlieLA/0rgFTcz4xwUYj/cD5e0ZBuSkYsYFAU3hd1cGfBue0cPZaQH2HYx +Qk4zXD8S3F4690fRhr+tki5gyG6JDR67aKp3BIGLqm7f45WkX1hYp+YXywmEziM4 +aSbGYhx8hoFGfq9UcfPEvp2aoc8u5sdqjDslhyUzM1v3m3ZGbhwEOnVjljY6JJLx +MxagxnZZSAY424ZZ3t71E/Mn27dm2w+xFRuoy8JEjv1d+BT3eChM5KaNwrj0IO/y +u8kFIgWYA1vZ/15qMT+tyJTfyrNVV/7Df7TNeWyNqjJ5rBmt0M6NpHG7CrUSkBy9 +p8JhimgjP5r0FlEkgg+lyD+V79H98gQfVgP3pbJICz0SpBQf2F/2tyS4rLm+49rP +fcOajiXEuyhpcmzgusAj/1FjrtlynH1r9mnNaX4e+rLWzvU5AgMBAAGjUDBOMB0G +A1UdDgQWBBTkwyoJFGfYTVISTpM8E+igjdq28zAfBgNVHSMEGDAWgBTkwyoJFGfY +TVISTpM8E+igjdq28zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQAR +OXnYwu3g1ZjHyley3fZI5aLPsaE17cOImVTehC8DcIphm2HOMR/hYTTL+V0G4P+u +gH+6xeRLKSHMHZTtSBIa6GDL03434y9CBuwGvAFCMU2GV8w92/Z7apkAhdLToZA/ +X/iWP2jeaVJhxgEcH8uPrnSlqoPBcKC9PrgUzQYfSZJkLmB+3jEa3HKruy1abJP5 +gAdQvwvcPpvYRnIzUc9fZODsVmlHVFBCl2dlu/iHh2h4GmL4Da2rRkUMlbVTdioB +UYIvMycdOkpH5wJftzw7cpjsudGas0PARDXCFfGyKhwBRFY7Xp7lbjtU5Rz0Gc04 +lPrhDf0pFE98Aw4jJRpFeWMjpXUEaG1cq7D641RpgcMfPFvOHY47rvDTS7XJOaUT +BwRjmDt896s6vMDcaG/uXJbQjuzmmx3W2Idyh3s5SI0GTHb0IwMKYb4eBUIpQOnB +cE77VnCYqKvN1NVYAqhWjXbY7XasZvszCRcOG+W3FqNaHOK/n/0ueb0uijdLan+U +f4p1bjbAox8eAOQS/8a3bzkJzdyBNUKGx1BIK2IBL9bn/HravSDOiNRSnZ/R3l9G +ZauX0tu7IIDlRCILXSyeazu0aj/vdT3YFQXPcvt5Fkf5wiNTo53f72/jYEJd6qph +WrpoKqrwGwTpRUCMhYIUt65hsTxCiJJ5nKe39h46sg== +-----END CERTIFICATE----- diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index 8074ad2ee..eeb9fa389 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -68,10 +68,12 @@ public final class Constants {          public static final String LANGUAGE = "language";          public static final String FORCE_V3_SIGNATURES = "forceV3Signatures";          public static final String KEY_SERVERS = "keyServers"; +        public static final String KEY_SERVERS_DEFAULT_VERSION = "keyServersDefaultVersion";      }      public static final class Defaults { -        public static final String KEY_SERVERS = "pool.sks-keyservers.net, subkeys.pgp.net, pgp.mit.edu"; +        public static final String KEY_SERVERS = "hkps://hkps.pool.sks-keyservers.net, subkeys.pgp.net, hkps://pgp.mit.edu"; +        public static final int KEY_SERVERS_VERSION = 2;      }      public static final class DrawerItems { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index d28c4d63c..be9c1e405 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -26,6 +26,8 @@ import android.graphics.drawable.Drawable;  import android.os.Environment;  import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.sufficientlysecure.keychain.helper.Preferences; +import org.sufficientlysecure.keychain.helper.TlsHelper;  import org.sufficientlysecure.keychain.util.Log;  import org.sufficientlysecure.keychain.util.PRNGFixes; @@ -78,6 +80,11 @@ public class KeychainApplication extends Application {                  getApplicationContext().getResources().getColor(R.color.emphasis));          setupAccountAsNeeded(this); + +        // Update keyserver list as needed +        Preferences.getPreferences(this).updateKeyServers(); + +        TlsHelper.addStaticCA("pool.sks-keyservers.net", getAssets(), "sks-keyservers.netCA.cer");      }      public static void setupAccountAsNeeded(Context context) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java index d8a7e8427..e639824ec 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java @@ -22,8 +22,10 @@ import android.accounts.AccountManager;  import android.content.*;  import android.database.Cursor;  import android.net.Uri; +import android.os.Build;  import android.provider.ContactsContract;  import android.util.Patterns; +  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.pgp.KeyRing; @@ -58,7 +60,27 @@ public class ContactHelper {              ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "=?";      public static final String ID_SELECTION = ContactsContract.RawContacts._ID + "=?"; -    public static List<String> getMailAccounts(Context context) { +    public static List<String> getPossibleUserEmails(Context context) { +        Set<String> accountMails = getAccountEmails(context); +        accountMails.addAll(getMainProfileContactEmails(context)); +        // now return the Set (without duplicates) as a List +        return new ArrayList<String>(accountMails); +    } + +    public static List<String> getPossibleUserNames(Context context) { +        Set<String> accountMails = getAccountEmails(context); +        Set<String> names = getContactNamesFromEmails(context, accountMails); +        names.addAll(getMainProfileContactName(context)); +        return new ArrayList<String>(names); +    } + +    /** +     * Get emails from AccountManager +     * +     * @param context +     * @return +     */ +    private static Set<String> getAccountEmails(Context context) {          final Account[] accounts = AccountManager.get(context).getAccounts();          final Set<String> emailSet = new HashSet<String>();          for (Account account : accounts) { @@ -66,7 +88,118 @@ public class ContactHelper {                  emailSet.add(account.name);              }          } -        return new ArrayList<String>(emailSet); +        return emailSet; +    } + +    /** +     * Search for contact names based on a list of emails (to find out the names of the +     * device owner based on the email addresses from AccountsManager) +     * +     * @param context +     * @param emails +     * @return +     */ +    private static Set<String> getContactNamesFromEmails(Context context, Set<String> emails) { +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { +            Set<String> names = new HashSet<String>(); +            for (String email : emails) { +                ContentResolver resolver = context.getContentResolver(); +                Cursor profileCursor = resolver.query( +                        ContactsContract.CommonDataKinds.Email.CONTENT_URI, +                        new String[]{ContactsContract.CommonDataKinds.Email.ADDRESS, +                                ContactsContract.Contacts.DISPLAY_NAME}, +                        ContactsContract.CommonDataKinds.Email.ADDRESS + "=?", +                        new String[]{email}, null +                ); +                if (profileCursor == null) return null; + +                Set<String> currNames = new HashSet<String>(); +                while (profileCursor.moveToNext()) { +                    String name = profileCursor.getString(1); +                    Log.d(Constants.TAG, "name" + name); +                    if (name != null) { +                        currNames.add(name); +                    } +                } +                profileCursor.close(); +                names.addAll(currNames); +            } +            return names; +        } else { +            return new HashSet<String>(); +        } +    } + +    /** +     * Retrieves the emails of the primary profile contact +     * http://developer.android.com/reference/android/provider/ContactsContract.Profile.html +     * +     * @param context +     * @return +     */ +    private static Set<String> getMainProfileContactEmails(Context context) { +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { +            ContentResolver resolver = context.getContentResolver(); +            Cursor profileCursor = resolver.query( +                    Uri.withAppendedPath( +                            ContactsContract.Profile.CONTENT_URI, +                            ContactsContract.Contacts.Data.CONTENT_DIRECTORY), +                    new String[]{ContactsContract.CommonDataKinds.Email.ADDRESS, +                            ContactsContract.CommonDataKinds.Email.IS_PRIMARY}, + +                    // Selects only email addresses +                    ContactsContract.Contacts.Data.MIMETYPE + "=?", +                    new String[]{ +                            ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE, +                    }, +                    // Show primary rows first. Note that there won't be a primary email address if the +                    // user hasn't specified one. +                    ContactsContract.Contacts.Data.IS_PRIMARY + " DESC" +            ); +            if (profileCursor == null) return null; + +            Set<String> emails = new HashSet<String>(); +            while (profileCursor.moveToNext()) { +                String email = profileCursor.getString(0); +                if (email != null) { +                    emails.add(email); +                } +            } +            profileCursor.close(); +            return emails; +        } else { +            return new HashSet<String>(); +        } +    } + +    /** +     * Retrieves the name of the primary profile contact +     * http://developer.android.com/reference/android/provider/ContactsContract.Profile.html +     * +     * @param context +     * @return +     */ +    private static List<String> getMainProfileContactName(Context context) { +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { +            ContentResolver resolver = context.getContentResolver(); +            Cursor profileCursor = resolver.query(ContactsContract.Profile.CONTENT_URI, +                    new String[]{ContactsContract.Profile.DISPLAY_NAME}, +                    null, null, null); +            if (profileCursor == null) return null; + +            Set<String> names = new HashSet<String>(); +            // should only contain one entry! +            while (profileCursor.moveToNext()) { +                String name = profileCursor.getString(0); +                if (name != null) { +                    names.add(name); +                } +            } +            profileCursor.close(); +            return new ArrayList<String>(names); +        } else { +            return new ArrayList<String>(); +        }      }      public static List<String> getContactMails(Context context) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java index c82c5e115..6f3d38ccd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java @@ -169,4 +169,22 @@ public class Preferences {          editor.putString(Constants.Pref.KEY_SERVERS, rawData);          editor.commit();      } + +    public void updateKeyServers() { +        if (mSharedPreferences.getInt(Constants.Pref.KEY_SERVERS_DEFAULT_VERSION, 0) != +                Constants.Defaults.KEY_SERVERS_VERSION) { +            String[] servers = getKeyServers(); +            for (int i = 0; i < servers.length; i++) { +                if (servers[i].equals("pool.sks-keyservers.net")) { +                    servers[i] = "hkps://hkps.pool.sks-keyservers.net"; +                } else if (servers[i].equals("pgp.mit.edu")) { +                    servers[i] = "hkps://pgp.mit.edu"; +                } +            } +            setKeyServers(servers); +            mSharedPreferences.edit() +                    .putInt(Constants.Pref.KEY_SERVERS_DEFAULT_VERSION, Constants.Defaults.KEY_SERVERS_VERSION) +                    .commit(); +        } +    }  } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/TlsHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/TlsHelper.java new file mode 100644 index 000000000..4b09af04d --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/TlsHelper.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.helper; + +import android.content.res.AssetManager; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.Log; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.*; +import java.util.HashMap; +import java.util.Map; + +public class TlsHelper { + +    public static class TlsHelperException extends Exception { +        public TlsHelperException(Exception e) { +            super(e); +        } +    } + +    private static Map<String, byte[]> sStaticCA = new HashMap<String, byte[]>(); + +    public static void addStaticCA(String domain, byte[] certificate) { +        sStaticCA.put(domain, certificate); +    } + +    public static void addStaticCA(String domain, AssetManager assetManager, String name) { +        try { +            InputStream is = assetManager.open(name); +            ByteArrayOutputStream baos = new ByteArrayOutputStream(); +            int reads = is.read(); + +            while(reads != -1){ +                baos.write(reads); +                reads = is.read(); +            } + +            is.close(); + +            addStaticCA(domain, baos.toByteArray()); +        } catch (IOException e) { +            Log.w(Constants.TAG, e); +        } +    } + +    public static URLConnection openConnection(URL url) throws IOException, TlsHelperException { +        if (url.getProtocol().equals("https")) { +            for (String domain : sStaticCA.keySet()) { +                if (url.getHost().endsWith(domain)) { +                    return openCAConnection(sStaticCA.get(domain), url); +                } +            } +        } +        return url.openConnection(); +    } + +    /** +     * Opens a Connection that will only accept certificates signed with a specific CA and skips common name check. +     * This is required for some distributed Keyserver networks like sks-keyservers.net +     * +     * @param certificate The X.509 certificate used to sign the servers certificate +     * @param url         Connection target +     */ +    public static HttpsURLConnection openCAConnection(byte[] certificate, URL url) +            throws TlsHelperException, IOException { +        try { +            // Load CA +            CertificateFactory cf = CertificateFactory.getInstance("X.509"); +            Certificate ca = cf.generateCertificate(new ByteArrayInputStream(certificate)); + +            // Create a KeyStore containing our trusted CAs +            String keyStoreType = KeyStore.getDefaultType(); +            KeyStore keyStore = KeyStore.getInstance(keyStoreType); +            keyStore.load(null, null); +            keyStore.setCertificateEntry("ca", ca); + +            // Create a TrustManager that trusts the CAs in our KeyStore +            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); +            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); +            tmf.init(keyStore); + +            // Create an SSLContext that uses our TrustManager +            SSLContext context = SSLContext.getInstance("TLS"); +            context.init(null, tmf.getTrustManagers(), null); + +            // Tell the URLConnection to use a SocketFactory from our SSLContext +            HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); +            urlConnection.setSSLSocketFactory(context.getSocketFactory()); + +            return urlConnection; +        } catch (CertificateException e) { +            throw new TlsHelperException(e); +        } catch (NoSuchAlgorithmException e) { +            throw new TlsHelperException(e); +        } catch (KeyStoreException e) { +            throw new TlsHelperException(e); +        } catch (KeyManagementException e) { +            throw new TlsHelperException(e); +        } +    } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java index e49085a0e..44679ba18 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java @@ -22,37 +22,23 @@ import de.measite.minidns.Client;  import de.measite.minidns.Question;  import de.measite.minidns.Record;  import de.measite.minidns.record.SRV; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils;  import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.helper.TlsHelper;  import org.sufficientlysecure.keychain.pgp.PgpHelper;  import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;  import org.sufficientlysecure.keychain.util.Log; +import java.io.DataOutputStream;  import java.io.IOException; -import java.io.InputStream;  import java.io.UnsupportedEncodingException;  import java.net.HttpURLConnection; -import java.net.InetAddress; -import java.net.MalformedURLException;  import java.net.URL;  import java.net.URLDecoder;  import java.net.URLEncoder; -import java.net.UnknownHostException;  import java.util.ArrayList;  import java.util.Arrays;  import java.util.Comparator;  import java.util.GregorianCalendar; -import java.util.List;  import java.util.Locale;  import java.util.TimeZone;  import java.util.regex.Matcher; @@ -200,48 +186,37 @@ public class HkpKeyserver extends Keyserver {          return mSecure ? "https://" : "http://";      } -    private String query(String request) throws QueryFailedException, HttpError { -        List<String> urls = new ArrayList<String>(); -        if (mSecure) { -            urls.add(getUrlPrefix() + mHost + ":" + mPort + request); -        } else { -            InetAddress ips[]; -            try { -                ips = InetAddress.getAllByName(mHost); -            } catch (UnknownHostException e) { -                throw new QueryFailedException(e.toString()); -            } -            for (InetAddress ip : ips) { -                // Note: This is actually not HTTP 1.1 compliant, as we hide the real "Host" value, -                //       but Android's HTTPUrlConnection does not support any other way to set -                //       Socket's remote IP address... -                urls.add(getUrlPrefix() + ip.getHostAddress() + ":" + mPort + request); -            } +    private HttpURLConnection openConnection(URL url) throws IOException { +        HttpURLConnection conn = null; +        try { +            conn = (HttpURLConnection) TlsHelper.openConnection(url); +        } catch (TlsHelper.TlsHelperException e) { +            Log.w(Constants.TAG, e); +        } +        if (conn == null) { +            conn = (HttpURLConnection) url.openConnection();          } +        conn.setConnectTimeout(5000); +        conn.setReadTimeout(25000); +        return conn; +    } -        for (String url : urls) { -            try { -                Log.d(Constants.TAG, "hkp keyserver query: " + url); -                URL realUrl = new URL(url); -                HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection(); -                conn.setConnectTimeout(5000); -                conn.setReadTimeout(25000); -                conn.connect(); -                int response = conn.getResponseCode(); -                if (response >= 200 && response < 300) { -                    return readAll(conn.getInputStream(), conn.getContentEncoding()); -                } else { -                    String data = readAll(conn.getErrorStream(), conn.getContentEncoding()); -                    throw new HttpError(response, data); -                } -            } catch (MalformedURLException e) { -                // nothing to do, try next IP -            } catch (IOException e) { -                // nothing to do, try next IP +    private String query(String request) throws QueryFailedException, HttpError { +        try { +            URL url = new URL(getUrlPrefix() + mHost + ":" + mPort + request); +            Log.d(Constants.TAG, "hkp keyserver query: " + url); +            HttpURLConnection conn = openConnection(url); +            conn.connect(); +            int response = conn.getResponseCode(); +            if (response >= 200 && response < 300) { +                return readAll(conn.getInputStream(), conn.getContentEncoding()); +            } else { +                String data = readAll(conn.getErrorStream(), conn.getContentEncoding()); +                throw new HttpError(response, data);              } +        } catch (IOException e) { +            throw new QueryFailedException("querying server(s) for '" + mHost + "' failed");          } - -        throw new QueryFailedException("querying server(s) for '" + mHost + "' failed");      }      @Override @@ -341,52 +316,44 @@ public class HkpKeyserver extends Keyserver {      @Override      public String get(String keyIdHex) throws QueryFailedException { -        HttpClient client = new DefaultHttpClient(); +        String request = "/pks/lookup?op=get&options=mr&search=" + keyIdHex; +        Log.d(Constants.TAG, "hkp keyserver get: " + request); +        String data;          try { -            String query = getUrlPrefix() + mHost + ":" + mPort + -                    "/pks/lookup?op=get&options=mr&search=" + keyIdHex; -            Log.d(Constants.TAG, "hkp keyserver get: " + query); -            HttpGet get = new HttpGet(query); -            HttpResponse response = client.execute(get); -            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { -                throw new QueryFailedException("not found"); -            } - -            HttpEntity entity = response.getEntity(); -            InputStream is = entity.getContent(); -            String data = readAll(is, EntityUtils.getContentCharSet(entity)); -            Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(data); -            if (matcher.find()) { -                return matcher.group(1); -            } -        } catch (IOException e) { -            // nothing to do, better luck on the next keyserver -        } finally { -            client.getConnectionManager().shutdown(); +            data = query(request); +        } catch (HttpError httpError) { +            throw new QueryFailedException("not found"); +        } +        Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(data); +        if (matcher.find()) { +            return matcher.group(1);          } -          return null;      }      @Override      public void add(String armoredKey) throws AddKeyException { -        HttpClient client = new DefaultHttpClient();          try {              String query = getUrlPrefix() + mHost + ":" + mPort + "/pks/add"; -            HttpPost post = new HttpPost(query); -            Log.d(Constants.TAG, "hkp keyserver add: " + query); -            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); -            nameValuePairs.add(new BasicNameValuePair("keytext", armoredKey)); -            post.setEntity(new UrlEncodedFormEntity(nameValuePairs)); - -            HttpResponse response = client.execute(post); -            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { +            String params; +            try { +                params = "keytext=" + URLEncoder.encode(armoredKey, "utf8"); +            } catch (UnsupportedEncodingException e) {                  throw new AddKeyException();              } +            Log.d(Constants.TAG, "hkp keyserver add: " + query); + +            HttpURLConnection connection = openConnection(new URL(query)); +            connection.setRequestMethod("POST"); +            connection.addRequestProperty("Content-Type", "application/x-www-form-urlencoded"); +            connection.setRequestProperty("Content-Length", Integer.toString(params.getBytes().length)); +            connection.setDoOutput(true); +            DataOutputStream wr = new DataOutputStream(connection.getOutputStream()); +            wr.writeBytes(params); +            wr.flush(); +            wr.close();          } catch (IOException e) { -            // nothing to do, better luck on the next keyserver -        } finally { -            client.getConnectionManager().shutdown(); +            throw new AddKeyException();          }      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java index c50d92f7a..6fc55cfb8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -123,11 +123,16 @@ public class PgpImportExport {      }      /** Imports keys from given data. If keyIds is given only those are imported */ -    public ImportResult importKeyRings(List<ParcelableKeyRing> entries) -            throws PgpGeneralException, PGPException, IOException { +    public ImportResult importKeyRings(List<ParcelableKeyRing> entries) {          updateProgress(R.string.progress_importing, 0, 100); +        // If there aren't even any keys, do nothing here. +        if (entries == null || entries.size() == 0) { +            return new ImportResult( +                    ImportResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0); +        } +          int newKeys = 0, oldKeys = 0, badKeys = 0;          int position = 0; @@ -165,6 +170,9 @@ public class PgpImportExport {                      newKeys += 1;                  } +            } catch (IOException e) { +                Log.e(Constants.TAG, "Encountered bad key on import!", e); +                ++badKeys;              } catch (PgpGeneralException e) {                  Log.e(Constants.TAG, "Encountered bad key on import!", e);                  ++badKeys; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 9b3e5bc54..1b59e7cc0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -33,7 +33,6 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;  import org.spongycastle.openpgp.PGPSignature;  import org.spongycastle.openpgp.PGPSignatureGenerator;  import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; -import org.spongycastle.openpgp.PGPSignatureSubpacketVector;  import org.spongycastle.openpgp.PGPUtil;  import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;  import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor; @@ -51,7 +50,6 @@ import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;  import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;  import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;  import org.sufficientlysecure.keychain.service.SaveKeyringParcel; -import org.sufficientlysecure.keychain.util.IterableIterator;  import org.sufficientlysecure.keychain.util.Primes;  import java.io.IOException; @@ -65,7 +63,6 @@ import java.security.SignatureException;  import java.util.Arrays;  import java.util.Calendar;  import java.util.Date; -import java.util.List;  import java.util.TimeZone;  /** @@ -268,18 +265,18 @@ public class PgpKeyOperation {          // 4a. For each subkey change, generate new subkey binding certificate              for (SaveKeyringParcel.SubkeyChange change : saveParcel.changeSubKeys) {                  log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_CHANGE, -                        new String[]{PgpKeyHelper.convertKeyIdToHex(change.mKeyId)}, indent); +                        indent, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));                  PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId);                  if (sKey == null) {                      log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING, -                            new String[]{PgpKeyHelper.convertKeyIdToHex(change.mKeyId)}, indent + 1); +                            indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));                      return null;                  }                  PGPPublicKey pKey = sKey.getPublicKey();                  if (change.mExpiry != null && new Date(change.mExpiry).before(new Date())) {                      log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY, -                            new String[]{PgpKeyHelper.convertKeyIdToHex(change.mKeyId)}, indent + 1); +                            indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));                      return null;                  } @@ -293,11 +290,11 @@ public class PgpKeyOperation {              // 4b. For each subkey revocation, generate new subkey revocation certificate              for (long revocation : saveParcel.revokeSubKeys) {                  log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_REVOKE, -                        new String[] { PgpKeyHelper.convertKeyIdToHex(revocation) }, indent); +                        indent, PgpKeyHelper.convertKeyIdToHex(revocation));                  PGPSecretKey sKey = sKR.getSecretKey(revocation);                  if (sKey == null) {                      log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING, -                            new String[] { PgpKeyHelper.convertKeyIdToHex(revocation) }, indent+1); +                            indent+1, PgpKeyHelper.convertKeyIdToHex(revocation));                      return null;                  }                  PGPPublicKey pKey = sKey.getPublicKey(); @@ -321,7 +318,7 @@ public class PgpKeyOperation {                      log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent);                      PGPSecretKey sKey = createKey(add.mAlgorithm, add.mKeysize, passphrase, false);                      log.add(LogLevel.DEBUG, LogType.MSG_MF_SUBKEY_NEW_ID, -                            new String[] { PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID()) }, indent+1); +                            indent+1, PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID()));                      PGPPublicKey pKey = sKey.getPublicKey();                      PGPSignature cert = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index 371202217..441e2762a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -207,7 +207,7 @@ public class UncachedKeyRing {      public UncachedKeyRing canonicalize(OperationLog log, int indent) {          log.add(LogLevel.START, isSecret() ? LogType.MSG_KC_SECRET : LogType.MSG_KC_PUBLIC, -                new String[]{PgpKeyHelper.convertKeyIdToHex(getMasterKeyId())}, indent); +                indent, PgpKeyHelper.convertKeyIdToHex(getMasterKeyId()));          indent += 1;          final Date now = new Date(); @@ -220,7 +220,7 @@ public class UncachedKeyRing {          {              log.add(LogLevel.DEBUG, LogType.MSG_KC_MASTER, -                    new String[]{PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID())}, indent); +                    indent, PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID()));              indent += 1;              PGPPublicKey modified = masterKey; @@ -240,9 +240,7 @@ public class UncachedKeyRing {                  if (type != PGPSignature.KEY_REVOCATION) {                      // Unknown type, just remove -                    log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TYPE, new String[]{ -                            "0x" + Integer.toString(type, 16) -                    }, indent); +                    log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TYPE, indent, "0x" + Integer.toString(type, 16));                      modified = PGPPublicKey.removeCertification(modified, zert);                      badCerts += 1;                      continue; @@ -250,7 +248,7 @@ public class UncachedKeyRing {                  if (cert.getCreationTime().after(now)) {                      // Creation date in the future? No way! -                    log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TIME, null, indent); +                    log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TIME, indent);                      modified = PGPPublicKey.removeCertification(modified, zert);                      badCerts += 1;                      continue; @@ -258,7 +256,7 @@ public class UncachedKeyRing {                  if (cert.isLocal()) {                      // Creation date in the future? No way! -                    log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_LOCAL, null, indent); +                    log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_LOCAL, indent);                      modified = PGPPublicKey.removeCertification(modified, zert);                      badCerts += 1;                      continue; @@ -267,13 +265,13 @@ public class UncachedKeyRing {                  try {                      cert.init(masterKey);                      if (!cert.verifySignature(masterKey)) { -                        log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD, null, indent); +                        log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD, indent);                          modified = PGPPublicKey.removeCertification(modified, zert);                          badCerts += 1;                          continue;                      }                  } catch (PgpGeneralException e) { -                    log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_ERR, null, indent); +                    log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_ERR, indent);                      modified = PGPPublicKey.removeCertification(modified, zert);                      badCerts += 1;                      continue; @@ -286,12 +284,12 @@ public class UncachedKeyRing {                  } else if (revocation.getCreationTime().before(zert.getCreationTime())) {                      modified = PGPPublicKey.removeCertification(modified, revocation);                      redundantCerts += 1; -                    log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, null, indent); +                    log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, indent);                      revocation = zert;                  } else {                      modified = PGPPublicKey.removeCertification(modified, zert);                      redundantCerts += 1; -                    log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, null, indent); +                    log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, indent);                  }              } @@ -312,16 +310,14 @@ public class UncachedKeyRing {                              && type != PGPSignature.POSITIVE_CERTIFICATION                              && type != PGPSignature.CERTIFICATION_REVOCATION) {                          log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD_TYPE, -                                new String[] { -                                        "0x" + Integer.toString(zert.getSignatureType(), 16) -                                }, indent); +                                indent, "0x" + Integer.toString(zert.getSignatureType(), 16));                          modified = PGPPublicKey.removeCertification(modified, userId, zert);                          badCerts += 1;                      }                      if (cert.getCreationTime().after(now)) {                          // Creation date in the future? No way! -                        log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TIME, null, indent); +                        log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TIME, indent);                          modified = PGPPublicKey.removeCertification(modified, zert);                          badCerts += 1;                          continue; @@ -329,7 +325,7 @@ public class UncachedKeyRing {                      if (cert.isLocal()) {                          // Creation date in the future? No way! -                        log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_LOCAL, null, indent); +                        log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_LOCAL, indent);                          modified = PGPPublicKey.removeCertification(modified, zert);                          badCerts += 1;                          continue; @@ -340,7 +336,7 @@ public class UncachedKeyRing {                          // never mind any further for public keys, but remove them from secret ones                          if (isSecret()) {                              log.add(LogLevel.WARN, LogType.MSG_KC_UID_FOREIGN, -                                    new String[] { PgpKeyHelper.convertKeyIdToHex(certId) }, indent); +                                    indent, PgpKeyHelper.convertKeyIdToHex(certId));                              modified = PGPPublicKey.removeCertification(modified, userId, zert);                              badCerts += 1;                          } @@ -352,14 +348,14 @@ public class UncachedKeyRing {                          cert.init(masterKey);                          if (!cert.verifySignature(masterKey, userId)) {                              log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD, -                                    new String[] { userId }, indent); +                                    indent, userId);                              modified = PGPPublicKey.removeCertification(modified, userId, zert);                              badCerts += 1;                              continue;                          }                      } catch (PgpGeneralException e) {                          log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD_ERR, -                                new String[] { userId }, indent); +                                indent, userId);                          modified = PGPPublicKey.removeCertification(modified, userId, zert);                          badCerts += 1;                          continue; @@ -376,13 +372,13 @@ public class UncachedKeyRing {                                  modified = PGPPublicKey.removeCertification(modified, userId, selfCert);                                  redundantCerts += 1;                                  log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP, -                                        new String[] { userId }, indent); +                                        indent, userId);                                  selfCert = zert;                              } else {                                  modified = PGPPublicKey.removeCertification(modified, userId, zert);                                  redundantCerts += 1;                                  log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP, -                                        new String[] { userId }, indent); +                                        indent, userId);                              }                              // If there is a revocation certificate, and it's older than this, drop it                              if (revocation != null @@ -391,7 +387,7 @@ public class UncachedKeyRing {                                  revocation = null;                                  redundantCerts += 1;                                  log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_OLD, -                                        new String[] { userId }, indent); +                                        indent, userId);                              }                              break; @@ -401,7 +397,7 @@ public class UncachedKeyRing {                                  modified = PGPPublicKey.removeCertification(modified, userId, zert);                                  redundantCerts += 1;                                  log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_OLD, -                                        new String[] { userId }, indent); +                                        indent, userId);                                  continue;                              }                              // first revocation? remember it. @@ -412,13 +408,13 @@ public class UncachedKeyRing {                                  modified = PGPPublicKey.removeCertification(modified, userId, revocation);                                  redundantCerts += 1;                                  log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_DUP, -                                        new String[] { userId }, indent); +                                        indent, userId);                                  revocation = zert;                              } else {                                  modified = PGPPublicKey.removeCertification(modified, userId, zert);                                  redundantCerts += 1;                                  log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_DUP, -                                        new String[] { userId }, indent); +                                        indent, userId);                              }                              break; @@ -430,13 +426,13 @@ public class UncachedKeyRing {                  if (selfCert == null && revocation == null) {                      modified = PGPPublicKey.removeCertification(modified, userId);                      log.add(LogLevel.ERROR, LogType.MSG_KC_UID_REVOKE_DUP, -                            new String[] { userId }, indent); +                            indent, userId);                  }              }              // If NO user ids remain, error out!              if (!modified.getUserIDs().hasNext()) { -                log.add(LogLevel.ERROR, LogType.MSG_KC_FATAL_NO_UID, null, indent); +                log.add(LogLevel.ERROR, LogType.MSG_KC_FATAL_NO_UID, indent);                  return null;              } @@ -453,7 +449,7 @@ public class UncachedKeyRing {                  continue;              }              log.add(LogLevel.DEBUG, LogType.MSG_KC_SUB, -                    new String[]{PgpKeyHelper.convertKeyIdToHex(key.getKeyID())}, indent); +                    indent, PgpKeyHelper.convertKeyIdToHex(key.getKeyID()));              indent += 1;              // A subkey needs exactly one subkey binding certificate, and optionally one revocation              // certificate. @@ -468,29 +464,27 @@ public class UncachedKeyRing {                  // filter out bad key types...                  if (cert.getKeyId() != masterKey.getKeyID()) { -                    log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_KEYID, null, indent); +                    log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_KEYID, indent);                      badCerts += 1;                      continue;                  }                  if (type != PGPSignature.SUBKEY_BINDING && type != PGPSignature.SUBKEY_REVOCATION) { -                    log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_TYPE, new String[]{ -                            "0x" + Integer.toString(type, 16) -                    }, indent); +                    log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_TYPE, indent, "0x" + Integer.toString(type, 16));                      badCerts += 1;                      continue;                  }                  if (cert.getCreationTime().after(now)) {                      // Creation date in the future? No way! -                    log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_TIME, null, indent); +                    log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_TIME, indent);                      badCerts += 1;                      continue;                  }                  if (cert.isLocal()) {                      // Creation date in the future? No way! -                    log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_LOCAL, null, indent); +                    log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_LOCAL, indent);                      badCerts += 1;                      continue;                  } @@ -501,12 +495,12 @@ public class UncachedKeyRing {                      try {                          cert.init(masterKey);                          if (!cert.verifySignature(masterKey, key)) { -                            log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD, null, indent); +                            log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD, indent);                              badCerts += 1;                              continue;                          }                      } catch (PgpGeneralException e) { -                        log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_ERR, null, indent); +                        log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_ERR, indent);                          badCerts += 1;                          continue;                      } @@ -526,19 +520,19 @@ public class UncachedKeyRing {                                          if (subsig.verifySignature(masterKey, key)) {                                              ok = true;                                          } else { -                                            log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_BAD, null, indent); +                                            log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_BAD, indent);                                              badCerts += 1;                                              continue uids;                                          }                                      }                                  }                                  if (!ok) { -                                    log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_NONE, null, indent); +                                    log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_NONE, indent);                                      badCerts += 1;                                      continue;                                  }                              } catch (Exception e) { -                                log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_BAD_ERR, null, indent); +                                log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_BAD_ERR, indent);                                  badCerts += 1;                                  continue;                              } @@ -565,12 +559,12 @@ public class UncachedKeyRing {                      try {                          cert.init(masterKey);                          if (!cert.verifySignature(key)) { -                            log.add(LogLevel.WARN, LogType.MSG_KC_SUB_REVOKE_BAD, null, indent); +                            log.add(LogLevel.WARN, LogType.MSG_KC_SUB_REVOKE_BAD, indent);                              badCerts += 1;                              continue;                          }                      } catch (PgpGeneralException e) { -                        log.add(LogLevel.WARN, LogType.MSG_KC_SUB_REVOKE_BAD_ERR, null, indent); +                        log.add(LogLevel.WARN, LogType.MSG_KC_SUB_REVOKE_BAD_ERR, indent);                          badCerts += 1;                          continue;                      } @@ -591,7 +585,7 @@ public class UncachedKeyRing {                  ring = replacePublicKey(ring, modified);                  log.add(LogLevel.ERROR, LogType.MSG_KC_SUB_NO_CERT, -                        new String[]{ PgpKeyHelper.convertKeyIdToHex(key.getKeyID()) }, indent); +                        indent, PgpKeyHelper.convertKeyIdToHex(key.getKeyID()));                  indent -= 1;                  continue;              } @@ -608,17 +602,17 @@ public class UncachedKeyRing {          }          if (badCerts > 0 && redundantCerts > 0) { +            // multi plural would make this complex, just leaving this as is...              log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS_BAD_AND_RED, -                    new String[] { Integer.toString(badCerts), -                            Integer.toString(redundantCerts) }, indent); +                    indent, Integer.toString(badCerts), Integer.toString(redundantCerts));          } else if (badCerts > 0) {              log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS_BAD, -                    new String[] { Integer.toString(badCerts) }, indent); +                    indent, badCerts);          } else if (redundantCerts > 0) {              log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS_REDUNDANT, -                    new String[] { Integer.toString(redundantCerts) }, indent); +                    indent, redundantCerts);          } else { -            log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS, null, indent); +            log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS, indent);          }          return new UncachedKeyRing(ring, true); @@ -638,13 +632,13 @@ public class UncachedKeyRing {      public UncachedKeyRing merge(UncachedKeyRing other, OperationLog log, int indent) {          log.add(LogLevel.DEBUG, isSecret() ? LogType.MSG_MG_SECRET : LogType.MSG_MG_PUBLIC, -                new String[]{ PgpKeyHelper.convertKeyIdToHex(getMasterKeyId()) }, indent); +                indent, PgpKeyHelper.convertKeyIdToHex(getMasterKeyId()));          indent += 1;          long masterKeyId = other.getMasterKeyId();          if (getMasterKeyId() != masterKeyId) { -            log.add(LogLevel.ERROR, LogType.MSG_MG_HETEROGENEOUS, null, indent); +            log.add(LogLevel.ERROR, LogType.MSG_MG_HETEROGENEOUS, indent);              return null;          } @@ -683,7 +677,7 @@ public class UncachedKeyRing {                  final PGPPublicKey resultKey = result.getPublicKey(key.getKeyID());                  if (resultKey == null) { -                    log.add(LogLevel.DEBUG, LogType.MSG_MG_NEW_SUBKEY, null, indent); +                    log.add(LogLevel.DEBUG, LogType.MSG_MG_NEW_SUBKEY, indent);                      result = replacePublicKey(result, key);                      continue;                  } @@ -751,12 +745,12 @@ public class UncachedKeyRing {              }              log.add(LogLevel.DEBUG, LogType.MSG_MG_FOUND_NEW, -                    new String[] { Integer.toString(newCerts) }, indent); +                    indent, Integer.toString(newCerts));              return new UncachedKeyRing(result);          } catch (IOException e) { -            log.add(LogLevel.ERROR, LogType.MSG_MG_FATAL_ENCODE, null, indent); +            log.add(LogLevel.ERROR, LogType.MSG_MG_FATAL_ENCODE, indent);              return null;          } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index ceaa93f9b..7a63ec3d7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -165,10 +165,10 @@ public class KeychainDatabase extends SQLiteOpenHelper {          // make sure this is only done once, on the first instance!          boolean iAmIt = false; -        synchronized(apgHack) { -            if(!apgHack) { +        synchronized(KeychainDatabase.class) { +            if(!KeychainDatabase.apgHack) {                  iAmIt = true; -                apgHack = true; +                KeychainDatabase.apgHack = true;              }          }          // if it's us, do the import @@ -206,6 +206,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {              try {                  db.execSQL("ALTER TABLE keys ADD COLUMN has_secret BOOLEAN");              } catch (Exception e) { +                // never mind, the column probably already existed              }          }      } @@ -261,8 +262,8 @@ public class KeychainDatabase extends SQLiteOpenHelper {              cursor = db.rawQuery("SELECT key_ring_data FROM key_rings WHERE type = 1 OR EXISTS ("                      + " SELECT 1 FROM key_rings d2 WHERE key_rings.master_key_id = d2.master_key_id"                      + " AND d2.type = 1) ORDER BY type ASC", null); -            Log.d(Constants.TAG, "Importing " + cursor.getCount() + " secret keyrings from apg.db...");              if (cursor != null) { +                Log.d(Constants.TAG, "Importing " + cursor.getCount() + " secret keyrings from apg.db...");                  for (int i = 0; i < cursor.getCount(); i++) {                      cursor.moveToPosition(i);                      byte[] data = cursor.getBlob(0); @@ -285,8 +286,8 @@ public class KeychainDatabase extends SQLiteOpenHelper {                      + " SELECT 1 FROM key_rings d2 WHERE key_rings.master_key_id = d2.master_key_id AND"                      + " d2.type = 1)) DESC, type DESC", null);              // import from old database -            Log.d(Constants.TAG, "Importing " + cursor.getCount() + " keyrings from apg.db...");              if (cursor != null) { +                Log.d(Constants.TAG, "Importing " + cursor.getCount() + " keyrings from apg.db...");                  for (int i = 0; i < cursor.getCount(); i++) {                      cursor.moveToPosition(i);                      byte[] data = cursor.getBlob(0); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index f4e19d21a..28495d51d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -116,12 +116,12 @@ public class ProviderHelper {      public void log(LogLevel level, LogType type) {          if(mLog != null) { -            mLog.add(level, type, null, mIndent); +            mLog.add(level, type, mIndent);          }      } -    public void log(LogLevel level, LogType type, String[] parameters) { +    public void log(LogLevel level, LogType type, Object... parameters) {          if(mLog != null) { -            mLog.add(level, type, parameters, mIndent); +            mLog.add(level, type, mIndent, parameters);          }      } @@ -320,9 +320,9 @@ public class ProviderHelper {                  int rank = 0;                  for (UncachedPublicKey key : new IterableIterator<UncachedPublicKey>(keyRing.getPublicKeys())) {                      long keyId = key.getKeyId(); -                    log(LogLevel.DEBUG, keyId == masterKeyId ? LogType.MSG_IP_MASTER : LogType.MSG_IP_SUBKEY, new String[]{ +                    log(LogLevel.DEBUG, keyId == masterKeyId ? LogType.MSG_IP_MASTER : LogType.MSG_IP_SUBKEY,                              PgpKeyHelper.convertKeyIdToHex(keyId) -                    }); +                    );                      mIndent += 1;                      ContentValues values = new ContentValues(); @@ -343,36 +343,36 @@ public class ProviderHelper {                          if (c) {                              if (e) {                                  log(LogLevel.DEBUG, s ? LogType.MSG_IP_MASTER_FLAGS_CES -                                        : LogType.MSG_IP_MASTER_FLAGS_CEX, null); +                                        : LogType.MSG_IP_MASTER_FLAGS_CEX);                              } else {                                  log(LogLevel.DEBUG, s ? LogType.MSG_IP_MASTER_FLAGS_CXS -                                        : LogType.MSG_IP_MASTER_FLAGS_CXX, null); +                                        : LogType.MSG_IP_MASTER_FLAGS_CXX);                              }                          } else {                              if (e) {                                  log(LogLevel.DEBUG, s ? LogType.MSG_IP_MASTER_FLAGS_XES -                                        : LogType.MSG_IP_MASTER_FLAGS_XEX, null); +                                        : LogType.MSG_IP_MASTER_FLAGS_XEX);                              } else {                                  log(LogLevel.DEBUG, s ? LogType.MSG_IP_MASTER_FLAGS_XXS -                                        : LogType.MSG_IP_MASTER_FLAGS_XXX, null); +                                        : LogType.MSG_IP_MASTER_FLAGS_XXX);                              }                          }                      } else {                          if (c) {                              if (e) {                                  log(LogLevel.DEBUG, s ? LogType.MSG_IP_SUBKEY_FLAGS_CES -                                        : LogType.MSG_IP_SUBKEY_FLAGS_CEX, null); +                                        : LogType.MSG_IP_SUBKEY_FLAGS_CEX);                              } else {                                  log(LogLevel.DEBUG, s ? LogType.MSG_IP_SUBKEY_FLAGS_CXS -                                        : LogType.MSG_IP_SUBKEY_FLAGS_CXX, null); +                                        : LogType.MSG_IP_SUBKEY_FLAGS_CXX);                              }                          } else {                              if (e) {                                  log(LogLevel.DEBUG, s ? LogType.MSG_IP_SUBKEY_FLAGS_XES -                                        : LogType.MSG_IP_SUBKEY_FLAGS_XEX, null); +                                        : LogType.MSG_IP_SUBKEY_FLAGS_XEX);                              } else {                                  log(LogLevel.DEBUG, s ? LogType.MSG_IP_SUBKEY_FLAGS_XXS -                                        : LogType.MSG_IP_SUBKEY_FLAGS_XXX, null); +                                        : LogType.MSG_IP_SUBKEY_FLAGS_XXX);                              }                          }                      } @@ -385,11 +385,11 @@ public class ProviderHelper {                          if (key.isExpired()) {                              log(LogLevel.DEBUG, keyId == masterKeyId ?                                      LogType.MSG_IP_MASTER_EXPIRED : LogType.MSG_IP_SUBKEY_EXPIRED, -                                    new String[]{ expiryDate.toString() }); +                                    expiryDate.toString());                          } else {                              log(LogLevel.DEBUG, keyId == masterKeyId ?                                      LogType.MSG_IP_MASTER_EXPIRES : LogType.MSG_IP_SUBKEY_EXPIRES, -                                    new String[] { expiryDate.toString() }); +                                    expiryDate.toString());                          }                      } @@ -405,9 +405,7 @@ public class ProviderHelper {              // classify and order user ids. primary are moved to the front, revoked to the back,              // otherwise the order in the keyfile is preserved. -            log(LogLevel.INFO, LogType.MSG_IP_UID_CLASSIFYING, new String[]{ -                    Integer.toString(trustedKeys.size()) -            }); +            log(LogLevel.INFO, LogType.MSG_IP_UID_CLASSIFYING, trustedKeys.size());              mIndent += 1;              List<UserIdItem> uids = new ArrayList<UserIdItem>();              for (String userId : new IterableIterator<String>( @@ -418,7 +416,7 @@ public class ProviderHelper {                  int unknownCerts = 0; -                log(LogLevel.INFO, LogType.MSG_IP_UID_PROCESSING, new String[]{ userId }); +                log(LogLevel.INFO, LogType.MSG_IP_UID_PROCESSING, userId);                  mIndent += 1;                  // look through signatures for this specific key                  for (WrappedSignature cert : new IterableIterator<WrappedSignature>( @@ -447,10 +445,10 @@ public class ProviderHelper {                              cert.init(trustedKey);                              if (cert.verifySignature(masterKey, userId)) {                                  item.trustedCerts.add(cert); -                                log(LogLevel.INFO, LogType.MSG_IP_UID_CERT_GOOD, new String[] { +                                log(LogLevel.INFO, LogType.MSG_IP_UID_CERT_GOOD,                                          PgpKeyHelper.convertKeyIdToHexShort(trustedKey.getKeyId()),                                          trustedKey.getPrimaryUserId() -                                }); +                                );                              } else {                                  log(LogLevel.WARN, LogType.MSG_IP_UID_CERT_BAD);                              } @@ -459,16 +457,13 @@ public class ProviderHelper {                          unknownCerts += 1;                      } catch (PgpGeneralException e) { -                        log(LogLevel.WARN, LogType.MSG_IP_UID_CERT_ERROR, new String[]{ -                                PgpKeyHelper.convertKeyIdToHex(cert.getKeyId()) -                        }); +                        log(LogLevel.WARN, LogType.MSG_IP_UID_CERT_ERROR, +                                PgpKeyHelper.convertKeyIdToHex(cert.getKeyId()));                      }                  }                  if (unknownCerts > 0) { -                    log(LogLevel.DEBUG, LogType.MSG_IP_UID_CERTS_UNKNOWN, new String[]{ -                            Integer.toString(unknownCerts) -                    }); +                    log(LogLevel.DEBUG, LogType.MSG_IP_UID_CERTS_UNKNOWN, unknownCerts);                  }                  mIndent -= 1; @@ -574,8 +569,7 @@ public class ProviderHelper {          }          long masterKeyId = keyRing.getMasterKeyId(); -        log(LogLevel.START, LogType.MSG_IS, -                new String[]{ PgpKeyHelper.convertKeyIdToHex(masterKeyId) }); +        log(LogLevel.START, LogType.MSG_IS, PgpKeyHelper.convertKeyIdToHex(masterKeyId));          mIndent += 1;          try { @@ -625,18 +619,18 @@ public class ProviderHelper {                          int upd = mContentResolver.update(uri, values, Keys.KEY_ID + " = ?",                                  new String[]{Long.toString(id)});                          if (upd == 1) { -                            log(LogLevel.DEBUG, LogType.MSG_IS_SUBKEY_OK, new String[]{ +                            log(LogLevel.DEBUG, LogType.MSG_IS_SUBKEY_OK,                                      PgpKeyHelper.convertKeyIdToHex(id) -                            }); +                            );                          } else { -                            log(LogLevel.WARN, LogType.MSG_IS_SUBKEY_NONEXISTENT, new String[]{ +                            log(LogLevel.WARN, LogType.MSG_IS_SUBKEY_NONEXISTENT,                                      PgpKeyHelper.convertKeyIdToHex(id) -                            }); +                            );                          }                      } else { -                        log(LogLevel.INFO, LogType.MSG_IS_SUBKEY_STRIPPED, new String[]{ +                        log(LogLevel.INFO, LogType.MSG_IS_SUBKEY_STRIPPED,                                  PgpKeyHelper.convertKeyIdToHex(id) -                        }); +                        );                      }                  }                  mIndent -= 1; @@ -654,8 +648,6 @@ public class ProviderHelper {      } - -    @Deprecated      public SaveKeyringResult savePublicKeyRing(UncachedKeyRing keyRing) {          return savePublicKeyRing(keyRing, new NullProgressable());      } @@ -669,8 +661,7 @@ public class ProviderHelper {          try {              long masterKeyId = publicRing.getMasterKeyId(); -            log(LogLevel.START, LogType.MSG_IP, -                    new String[]{ PgpKeyHelper.convertKeyIdToHex(masterKeyId) }); +            log(LogLevel.START, LogType.MSG_IP, PgpKeyHelper.convertKeyIdToHex(masterKeyId));              mIndent += 1;              // If there is an old keyring, merge it @@ -694,8 +685,8 @@ public class ProviderHelper {                  // Early breakout if nothing changed                  if (Arrays.hashCode(publicRing.getEncoded())                          == Arrays.hashCode(oldPublicRing.getEncoded())) { -                    log(LogLevel.OK, LogType.MSG_IP_SUCCESS_IDENTICAL, null); -                    return new SaveKeyringResult(SaveKeyringResult.RESULT_OK, mLog); +                    log(LogLevel.OK, LogType.MSG_IP_SUCCESS_IDENTICAL); +                    return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog);                  }              } catch (NotFoundException e) {                  // Not an issue, just means we are dealing with a new keyring. @@ -754,8 +745,7 @@ public class ProviderHelper {          try {              long masterKeyId = secretRing.getMasterKeyId(); -            log(LogLevel.START, LogType.MSG_IS, -                    new String[]{ PgpKeyHelper.convertKeyIdToHex(masterKeyId) }); +            log(LogLevel.START, LogType.MSG_IS, PgpKeyHelper.convertKeyIdToHex(masterKeyId));              mIndent += 1;              // If there is an old secret key, merge it. @@ -780,8 +770,8 @@ public class ProviderHelper {                  if (Arrays.hashCode(secretRing.getEncoded())                          == Arrays.hashCode(oldSecretRing.getEncoded())) {                      log(LogLevel.OK, LogType.MSG_IS_SUCCESS_IDENTICAL, -                            new String[]{ PgpKeyHelper.convertKeyIdToHex(masterKeyId) }); -                    return new SaveKeyringResult(SaveKeyringResult.RESULT_OK, mLog); +                            PgpKeyHelper.convertKeyIdToHex(masterKeyId) ); +                    return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog);                  }              } catch (NotFoundException e) {                  // Not an issue, just means we are dealing with a new keyring @@ -812,7 +802,7 @@ public class ProviderHelper {                  }              } catch (NotFoundException e) { -                log(LogLevel.DEBUG, LogType.MSG_IS_PUBRING_GENERATE, null); +                log(LogLevel.DEBUG, LogType.MSG_IS_PUBRING_GENERATE);                  publicRing = secretRing.extractPublicKeyRing();              } @@ -833,7 +823,7 @@ public class ProviderHelper {              return new SaveKeyringResult(result, mLog);          } catch (IOException e) { -            log(LogLevel.ERROR, LogType.MSG_IS_FAIL_IO_EXC, null); +            log(LogLevel.ERROR, LogType.MSG_IS_FAIL_IO_EXC);              return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);          } finally {              mIndent -= 1; @@ -842,21 +832,6 @@ public class ProviderHelper {      }      /** -     * Saves (or updates) a pair of public and secret KeyRings in the database -     */ -    @Deprecated // scheduled for deletion after merge with new-edit branch -    public void savePairedKeyRing(UncachedKeyRing pubRing, UncachedKeyRing secRing) throws IOException { -        long masterKeyId = pubRing.getMasterKeyId(); - -        // delete secret keyring (so it isn't unnecessarily saved by public-savePublicKeyRing below) -        mContentResolver.delete(KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null); - -        // save public keyring -        internalSavePublicKeyRing(pubRing, null, true); -        internalSaveSecretKeyRing(secRing); -    } - -    /**       * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing       */      private ContentProviderOperation diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java index cb58f8734..e49c11e08 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java @@ -28,8 +28,7 @@ import android.widget.AdapterView;  import android.widget.AdapterView.OnItemSelectedListener;  import android.widget.Spinner;  import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; +import android.widget.Button;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; @@ -57,7 +56,7 @@ public class AccountSettingsFragment extends Fragment implements      private Spinner mCompression;      private SelectSecretKeyLayoutFragment mSelectKeyFragment; -    private BootstrapButton mCreateKeyButton; +    private Button mCreateKeyButton;      KeyValueSpinnerAdapter mEncryptionAdapter;      KeyValueSpinnerAdapter mHashAdapter; @@ -107,7 +106,7 @@ public class AccountSettingsFragment extends Fragment implements                  .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 = (BootstrapButton) view.findViewById(R.id.api_account_settings_create_key); +        mCreateKeyButton = (Button) view.findViewById(R.id.api_account_settings_create_key);          mCreateKeyButton.setOnClickListener(new View.OnClickListener() {              @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java index f88df5301..7f91ab490 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java @@ -59,23 +59,23 @@ public class OperationResultParcel implements Parcelable {      public static class LogEntryParcel implements Parcelable {          public final LogLevel mLevel;          public final LogType mType; -        public final String[] mParameters; +        public final Object[] mParameters;          public final int mIndent; -        public LogEntryParcel(LogLevel level, LogType type, String[] parameters, int indent) { +        public LogEntryParcel(LogLevel level, LogType type, int indent, Object... parameters) {              mLevel = level;              mType = type;              mParameters = parameters;              mIndent = indent;          } -        public LogEntryParcel(LogLevel level, LogType type, String[] parameters) { -            this(level, type, parameters, 0); +        public LogEntryParcel(LogLevel level, LogType type, Object... parameters) { +            this(level, type, 0, parameters);          }          public LogEntryParcel(Parcel source) {              mLevel = LogLevel.values()[source.readInt()];              mType = LogType.values()[source.readInt()]; -            mParameters = source.createStringArray(); +            mParameters = (Object[]) source.readSerializable();              mIndent = source.readInt();          } @@ -88,7 +88,7 @@ public class OperationResultParcel implements Parcelable {          public void writeToParcel(Parcel dest, int flags) {              dest.writeInt(mLevel.ordinal());              dest.writeInt(mType.ordinal()); -            dest.writeStringArray(mParameters); +            dest.writeSerializable(mParameters);              dest.writeInt(mIndent);          } @@ -164,8 +164,8 @@ public class OperationResultParcel implements Parcelable {          MSG_IP_UID_CERT_BAD (R.string.msg_ip_uid_cert_bad),          MSG_IP_UID_CERT_ERROR (R.string.msg_ip_uid_cert_error),          MSG_IP_UID_CERT_GOOD (R.string.msg_ip_uid_cert_good), -        MSG_IP_UID_CERTS_UNKNOWN (R.string.msg_ip_uid_certs_unknown), -        MSG_IP_UID_CLASSIFYING (R.string.msg_ip_uid_classifying), +        MSG_IP_UID_CERTS_UNKNOWN (R.plurals.msg_ip_uid_certs_unknown), +        MSG_IP_UID_CLASSIFYING (R.plurals.msg_ip_uid_classifying),          MSG_IP_UID_REORDER(R.string.msg_ip_uid_reorder),          MSG_IP_UID_PROCESSING (R.string.msg_ip_uid_processing),          MSG_IP_UID_REVOKED (R.string.msg_ip_uid_revoked), @@ -209,9 +209,9 @@ public class OperationResultParcel implements Parcelable {          MSG_KC_SUB_REVOKE_BAD_ERR (R.string.msg_kc_sub_revoke_bad_err),          MSG_KC_SUB_REVOKE_BAD (R.string.msg_kc_sub_revoke_bad),          MSG_KC_SUB_REVOKE_DUP (R.string.msg_kc_sub_revoke_dup), -        MSG_KC_SUCCESS_BAD (R.string.msg_kc_success_bad), +        MSG_KC_SUCCESS_BAD (R.plurals.msg_kc_success_bad),          MSG_KC_SUCCESS_BAD_AND_RED (R.string.msg_kc_success_bad_and_red), -        MSG_KC_SUCCESS_REDUNDANT (R.string.msg_kc_success_redundant), +        MSG_KC_SUCCESS_REDUNDANT (R.plurals.msg_kc_success_redundant),          MSG_KC_SUCCESS (R.string.msg_kc_success),          MSG_KC_UID_BAD_ERR (R.string.msg_kc_uid_bad_err),          MSG_KC_UID_BAD_LOCAL (R.string.msg_kc_uid_bad_local), @@ -296,13 +296,13 @@ public class OperationResultParcel implements Parcelable {      public static class OperationLog extends ArrayList<LogEntryParcel> {          /// Simple convenience method -        public void add(LogLevel level, LogType type, String[] parameters, int indent) { +        public void add(LogLevel level, LogType type, int indent, Object... parameters) {              Log.d(Constants.TAG, type.toString()); -            add(new OperationResultParcel.LogEntryParcel(level, type, parameters, indent)); +            add(new OperationResultParcel.LogEntryParcel(level, type, indent, parameters));          }          public void add(LogLevel level, LogType type, int indent) { -            add(new OperationResultParcel.LogEntryParcel(level, type, null, indent)); +            add(new OperationResultParcel.LogEntryParcel(level, type, indent, (Object[]) null));          }          public boolean containsWarnings() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java index 6c44b01f1..fd3d4ed00 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java @@ -1,6 +1,19 @@  package org.sufficientlysecure.keychain.service; +import android.app.Activity; +import android.content.Intent;  import android.os.Parcel; +import android.os.Parcelable; +import android.view.View; + +import com.github.johnpersano.supertoasts.SuperCardToast; +import com.github.johnpersano.supertoasts.SuperToast; +import com.github.johnpersano.supertoasts.util.OnClickWrapper; +import com.github.johnpersano.supertoasts.util.Style; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.LogDisplayActivity; +import org.sufficientlysecure.keychain.ui.LogDisplayFragment;  public abstract class OperationResults { @@ -67,6 +80,87 @@ public abstract class OperationResults {              }          }; +        public void displayNotify(final Activity activity) { + +            int resultType = getResult(); + +            String str; +            int duration, color; + +            // Not an overall failure +            if ((resultType & ImportResult.RESULT_ERROR) == 0) { +                String withWarnings; + +                // Any warnings? +                if ((resultType & ImportResult.RESULT_WITH_WARNINGS) > 0) { +                    duration = 0; +                    color = Style.ORANGE; +                    withWarnings = activity.getResources().getString(R.string.import_with_warnings); +                } else { +                    duration = SuperToast.Duration.LONG; +                    color = Style.GREEN; +                    withWarnings = ""; +                } + +                // New and updated keys +                if (this.isOkBoth()) { +                    str = activity.getResources().getQuantityString( +                            R.plurals.import_keys_added_and_updated_1, mNewKeys, mNewKeys); +                    str += activity.getResources().getQuantityString( +                            R.plurals.import_keys_added_and_updated_2, mUpdatedKeys, mUpdatedKeys, withWarnings); +                } else if (isOkUpdated()) { +                    str = activity.getResources().getQuantityString( +                            R.plurals.import_keys_updated, mUpdatedKeys, mUpdatedKeys, withWarnings); +                } else if (isOkNew()) { +                    str = activity.getResources().getQuantityString( +                            R.plurals.import_keys_added, mNewKeys, mNewKeys, withWarnings); +                } else { +                    duration = 0; +                    color = Style.RED; +                    str = "internal error"; +                } + +            } else { +                duration = 0; +                color = Style.RED; +                if (isFailNothing()) { +                    str = activity.getString(R.string.import_error_nothing); +                } else { +                    str = activity.getString(R.string.import_error); +                } +            } + +            // TODO: externalize into Notify class? +            boolean button = getLog() != null && !getLog().isEmpty(); +            SuperCardToast toast = new SuperCardToast(activity, +                    button ? SuperToast.Type.BUTTON : SuperToast.Type.STANDARD, +                    Style.getStyle(color, SuperToast.Animations.POPUP)); +            toast.setText(str); +            toast.setDuration(duration); +            toast.setIndeterminate(duration == 0); +            toast.setSwipeToDismiss(true); +            // If we have a log and it's non-empty, show a View Log button +            if (button) { +                toast.setButtonIcon(R.drawable.ic_action_view_as_list, +                        activity.getResources().getString(R.string.import_view_log)); +                toast.setButtonTextColor(activity.getResources().getColor(R.color.black)); +                toast.setTextColor(activity.getResources().getColor(R.color.black)); +                toast.setOnClickWrapper(new OnClickWrapper("supercardtoast", +                        new SuperToast.OnClickListener() { +                            @Override +                            public void onClick(View view, Parcelable token) { +                                Intent intent = new Intent( +                                        activity, LogDisplayActivity.class); +                                intent.putExtra(LogDisplayFragment.EXTRA_RESULT, ImportResult.this); +                                activity.startActivity(intent); +                            } +                        } +                )); +            } +            toast.show(); + +        } +      }      public static class SaveKeyringResult extends OperationResultParcel { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/KeyringTestingHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/KeyringTestingHelper.java index d4bc6c541..a565f0707 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/KeyringTestingHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/KeyringTestingHelper.java @@ -5,9 +5,10 @@ import android.content.Context;  import org.sufficientlysecure.keychain.pgp.NullProgressable;  import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;  import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.remote.AppSettings;  import org.sufficientlysecure.keychain.service.OperationResults; +import java.util.Collection; +  /**   * Helper for tests of the Keyring import in ProviderHelper.   */ @@ -19,13 +20,11 @@ public class KeyringTestingHelper {          this.context = robolectricContext;      } -    public boolean addKeyring() throws Exception { +    public boolean addKeyring(Collection<String> blobFiles) throws Exception {          ProviderHelper providerHelper = new ProviderHelper(context); -//        providerHelper.insertApiApp(new AppSettings("robo-test-package", new byte[]{5, 4, 3, 2, 1})); - -        byte[] data = TestDataUtil.readFully(getClass().getResourceAsStream("/public-key-for-sample.blob")); +        byte[] data = TestDataUtil.readAllFully(blobFiles);          UncachedKeyRing ring = UncachedKeyRing.decodeFromData(data);          long masterKeyId = ring.getMasterKeyId(); @@ -45,6 +44,7 @@ public class KeyringTestingHelper {          return saveSuccess;      } +      private void retrieveKeyAndExpectNotFound(ProviderHelper providerHelper, long masterKeyId) {          try {              providerHelper.getWrappedPublicKeyRing(masterKeyId); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/TestDataUtil.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/TestDataUtil.java index 06dc08eab..9e6ede761 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/TestDataUtil.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/TestDataUtil.java @@ -3,6 +3,7 @@ package org.sufficientlysecure.keychain.testsupport;  import java.io.ByteArrayOutputStream;  import java.io.IOException;  import java.io.InputStream; +import java.util.Collection;  /**   * Misc support functions. Would just use Guava / Apache Commons but @@ -10,9 +11,14 @@ import java.io.InputStream;   */  public class TestDataUtil {      public static byte[] readFully(InputStream input) { +        ByteArrayOutputStream output = new ByteArrayOutputStream(); +        appendToOutput(input, output); +        return output.toByteArray(); +    } + +    private static void appendToOutput(InputStream input, ByteArrayOutputStream output) {          byte[] buffer = new byte[8192];          int bytesRead; -        ByteArrayOutputStream output = new ByteArrayOutputStream();          try {              while ((bytesRead = input.read(buffer)) != -1) {                  output.write(buffer, 0, bytesRead); @@ -20,6 +26,19 @@ public class TestDataUtil {          } catch (IOException e) {              throw new RuntimeException(e);          } +    } + +    public static byte[] readAllFully(Collection<String> inputResources) { +        ByteArrayOutputStream output = new ByteArrayOutputStream(); + +        for (String inputResource : inputResources) { +            appendToOutput(getResourceAsStream(inputResource), output); +        }          return output.toByteArray();      } + + +    public static InputStream getResourceAsStream(String resourceName) { +        return TestDataUtil.class.getResourceAsStream(resourceName); +    }  } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java index 3df3b24b2..430f85b6f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java @@ -29,8 +29,7 @@ import android.view.View;  import android.view.ViewGroup;  import android.widget.CheckBox;  import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; +import android.widget.ImageButton;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; @@ -53,7 +52,7 @@ public class DecryptFileFragment extends DecryptFragment {      // view      private TextView mFilename;      private CheckBox mDeleteAfter; -    private BootstrapButton mBrowse; +    private ImageButton mBrowse;      private View mDecryptButton;      // model @@ -68,7 +67,7 @@ public class DecryptFileFragment extends DecryptFragment {          View view = inflater.inflate(R.layout.decrypt_file_fragment, container, false);          mFilename = (TextView) view.findViewById(R.id.decrypt_file_filename); -        mBrowse = (BootstrapButton) view.findViewById(R.id.decrypt_file_browse); +        mBrowse = (ImageButton) view.findViewById(R.id.decrypt_file_browse);          mDeleteAfter = (CheckBox) view.findViewById(R.id.decrypt_file_delete_after_decryption);          mDecryptButton = view.findViewById(R.id.decrypt_file_action_decrypt);          mBrowse.setOnClickListener(new View.OnClickListener() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index f67e54cf3..6b8358538 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -29,8 +29,7 @@ import android.widget.ImageView;  import android.widget.LinearLayout;  import android.widget.RelativeLayout;  import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; +import android.widget.Button;  import org.openintents.openpgp.OpenPgpSignatureResult;  import org.sufficientlysecure.keychain.R; @@ -52,7 +51,7 @@ public class DecryptFragment extends Fragment {      protected TextView mUserId;      protected TextView mUserIdRest; -    protected BootstrapButton mLookupKey; +    protected Button mLookupKey;      @Override @@ -65,7 +64,7 @@ public class DecryptFragment extends Fragment {          mSignatureStatusImage = (ImageView) getView().findViewById(R.id.ic_signature_status);          mUserId = (TextView) getView().findViewById(R.id.mainUserId);          mUserIdRest = (TextView) getView().findViewById(R.id.mainUserIdRest); -        mLookupKey = (BootstrapButton) getView().findViewById(R.id.lookup_key); +        mLookupKey = (Button) getView().findViewById(R.id.lookup_key);          mLookupKey.setOnClickListener(new OnClickListener() {              @Override              public void onClick(View v) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java index 9a5050eba..586442bb0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java @@ -37,8 +37,7 @@ import android.widget.AdapterView;  import android.widget.ArrayAdapter;  import android.widget.ListView;  import android.widget.TextView; - -import com.beardedhen.androidbootstrap.FontAwesomeText; +import android.widget.ImageView;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; @@ -79,10 +78,10 @@ public class DrawerActivity extends ActionBarActivity {          }          NavItem mItemIconTexts[] = new NavItem[]{ -                new NavItem("fa-user", getString(R.string.nav_keys)), -                new NavItem("fa-lock", getString(R.string.nav_encrypt)), -                new NavItem("fa-unlock", getString(R.string.nav_decrypt)), -                new NavItem("fa-android", getString(R.string.nav_apps))}; +                new NavItem(R.drawable.ic_action_person, getString(R.string.nav_keys)), +                new NavItem(R.drawable.ic_action_secure, getString(R.string.nav_encrypt)), +                new NavItem(R.drawable.ic_action_not_secure, getString(R.string.nav_decrypt)), +                new NavItem(R.drawable.ic_action_view_as_list, getString(R.string.nav_apps))};          mDrawerList.setAdapter(new NavigationDrawerAdapter(this, R.layout.drawer_list_item,                  mItemIconTexts)); @@ -239,10 +238,15 @@ public class DrawerActivity extends ActionBarActivity {      }      private class NavItem { -        public String icon; +        public int icon; // res-id          public String title; -        public NavItem(String icon, String title) { +        /** +         * NavItem constructor +         * @param icon The icons resource-id +         * @param title The title of the menu entry +         */ +        public NavItem(int icon, String title) {              super();              this.icon = icon;              this.title = title; @@ -271,7 +275,7 @@ public class DrawerActivity extends ActionBarActivity {                  row = inflater.inflate(mLayoutResourceId, parent, false);                  holder = new NavItemHolder(); -                holder.mImg = (FontAwesomeText) row.findViewById(R.id.drawer_item_icon); +                holder.mImg = (ImageView) row.findViewById(R.id.drawer_item_icon);                  holder.mTxtTitle = (TextView) row.findViewById(R.id.drawer_item_text);                  row.setTag(holder); @@ -281,7 +285,7 @@ public class DrawerActivity extends ActionBarActivity {              NavItem item = mData[position];              holder.mTxtTitle.setText(item.title); -            holder.mImg.setIcon(item.icon); +            holder.mImg.setImageResource(item.icon);              return row;          } @@ -289,7 +293,7 @@ public class DrawerActivity extends ActionBarActivity {      }      static class NavItemHolder { -        FontAwesomeText mImg; +        ImageView mImg;          TextView mTxtTitle;      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 4309e3505..d734c31db 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -34,13 +34,13 @@ import android.view.LayoutInflater;  import android.view.View;  import android.view.View.OnClickListener;  import android.view.ViewGroup; +import android.widget.Button;  import android.widget.CheckBox;  import android.widget.CompoundButton;  import android.widget.CompoundButton.OnCheckedChangeListener;  import android.widget.LinearLayout;  import android.widget.Toast; -import com.beardedhen.androidbootstrap.BootstrapButton;  import com.devspark.appmsg.AppMsg;  import org.sufficientlysecure.keychain.Constants; @@ -97,7 +97,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener      private boolean mNeedsSaving;      private boolean mIsBrandNewKeyring = false; -    private BootstrapButton mChangePassphrase; +    private Button mChangePassphrase;      private CheckBox mNoPassphrase; @@ -372,7 +372,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener          setContentView(R.layout.edit_key_activity);          // find views -        mChangePassphrase = (BootstrapButton) findViewById(R.id.edit_key_btn_change_passphrase); +        mChangePassphrase = (Button) findViewById(R.id.edit_key_btn_change_passphrase);          mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase);          // Build layout based on given userIds and keys diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityNew.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityNew.java index f2b5e68eb..b45e8a6bb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityNew.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityNew.java @@ -20,19 +20,13 @@ package org.sufficientlysecure.keychain.ui;  import android.net.Uri;  import android.os.Bundle;  import android.support.v7.app.ActionBarActivity; -import android.view.View; -import android.view.View.OnClickListener;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; -import org.sufficientlysecure.keychain.remote.ui.AccountsListFragment;  import org.sufficientlysecure.keychain.util.Log;  public class EditKeyActivityNew extends ActionBarActivity { -    private Uri mDataUri; -      private EditKeyFragment mEditKeyFragment;      @Override @@ -41,25 +35,6 @@ public class EditKeyActivityNew extends ActionBarActivity {          setContentView(R.layout.edit_key_activity_new); -//        // Inflate a "Done"/"Cancel" custom action bar view -//        ActionBarHelper.setTwoButtonView(getSupportActionBar(), -//                R.string.btn_save, R.drawable.ic_action_save, -//                new OnClickListener() { -//                    @Override -//                    public void onClick(View v) { -//                        // Save -// -//                    } -//                }, R.string.menu_key_edit_cancel, R.drawable.ic_action_cancel, -//                new OnClickListener() { -//                    @Override -//                    public void onClick(View v) { -//                        // Cancel -// -//                    } -//                } -//        ); -          Uri dataUri = getIntent().getData();          if (dataUri == null) {              Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index ac4390eac..b6a95a517 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -17,6 +17,8 @@  package org.sufficientlysecure.keychain.ui; +import android.app.ProgressDialog; +import android.content.Intent;  import android.database.Cursor;  import android.net.Uri;  import android.os.Bundle; @@ -42,11 +44,17 @@ import org.sufficientlysecure.keychain.helper.ActionBarHelper;  import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;  import org.sufficientlysecure.keychain.provider.KeychainContract;  import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.OperationResults; +import org.sufficientlysecure.keychain.service.PassphraseCacheService;  import org.sufficientlysecure.keychain.service.SaveKeyringParcel;  import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter;  import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; +import org.sufficientlysecure.keychain.ui.adapter.UserIdsArrayAdapter;  import org.sufficientlysecure.keychain.ui.dialog.AddUserIdDialogFragment;  import org.sufficientlysecure.keychain.ui.dialog.EditUserIdDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;  import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;  import org.sufficientlysecure.keychain.util.Log; @@ -68,6 +76,7 @@ public class EditKeyFragment extends LoaderFragment implements      private UserIdsAdapter mUserIdsAdapter;      private SubkeysAdapter mKeysAdapter; +    private UserIdsArrayAdapter mUserIdsAddedAdapter;      private Uri mDataUri; @@ -180,6 +189,10 @@ public class EditKeyFragment extends LoaderFragment implements              }          }); +        mUserIdsAddedAdapter = new UserIdsArrayAdapter(getActivity()); +        mUserIdsAddedList.setAdapter(mUserIdsAddedAdapter); +        mUserIdsAddedAdapter.setData(mSaveKeyringParcel.addUserIds); +          mKeysAdapter = new SubkeysAdapter(getActivity(), null, 0);          mKeysList.setAdapter(mKeysAdapter); @@ -253,8 +266,6 @@ public class EditKeyFragment extends LoaderFragment implements                      String newPassphrase = data                              .getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE); -//                    updatePassphraseButtonText(); -//                    somethingChanged();                      mSaveKeyringParcel.newPassphrase = newPassphrase;                  }              } @@ -263,14 +274,6 @@ public class EditKeyFragment extends LoaderFragment implements          // Create a new Messenger for the communication back          Messenger messenger = new Messenger(returnHandler); -        // set title based on isPassphraseSet() -//        int title; -//        if (isPassphraseSet()) { -//            title = R.string.title_change_passphrase; -//        } else { -//            title = R.string.title_set_passphrase; -//        } -          SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance(                  messenger, R.string.title_change_passphrase); @@ -321,9 +324,17 @@ public class EditKeyFragment extends LoaderFragment implements          Handler returnHandler = new Handler() {              @Override              public void handleMessage(Message message) { -                if (message.what == AddUserIdDialogFragment.MESSAGE_OK) { +                switch (message.what) { +                    case AddUserIdDialogFragment.MESSAGE_OKAY: +                        Bundle data = message.getData(); +                        String userId = data.getString(AddUserIdDialogFragment.MESSAGE_DATA_USER_ID); +                        if (userId != null) { +                            mSaveKeyringParcel.addUserIds.add(userId); +                            mUserIdsAddedAdapter.setData(mSaveKeyringParcel.addUserIds); +                        }                  } +                getLoaderManager().getLoader(LOADER_ID_USER_IDS).forceLoad();              }          }; @@ -341,9 +352,73 @@ public class EditKeyFragment extends LoaderFragment implements      }      private void save() { -        getActivity().finish(); -        // TODO +        String passphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), +                mSaveKeyringParcel.mMasterKeyId); +        if (passphrase == null) { +            PassphraseDialogFragment.show(getActivity(), mSaveKeyringParcel.mMasterKeyId, +                    new Handler() { +                        @Override +                        public void handleMessage(Message message) { +                            if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { +                                saveFinal(); +                            } +                        } +                    } +            ); + +        } +      } +    private void saveFinal() { +        // Message is received after importing is done in KeychainIntentService +        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( +                getActivity(), +                getString(R.string.progress_saving), +                ProgressDialog.STYLE_HORIZONTAL) { +            public void handleMessage(Message message) { +                // handle messages by standard KeychainIntentServiceHandler first +                super.handleMessage(message); + +                if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { +                    // get returned data bundle +                    Bundle returnData = message.getData(); +                    if (returnData == null) { +                        return; +                    } +                    final OperationResults.SaveKeyringResult result = +                            returnData.getParcelable(KeychainIntentService.RESULT); +                    if (result == null) { +                        return; +                    } -} +                    // if good -> finish, return result to showkey and display there! +                    // if bad -> display here! + +//                    result.displayNotify(ImportKeysActivity.this); + +//                    getActivity().finish(); +                } +            } +        }; + +        // Send all information needed to service to import key in other thread +        Intent intent = new Intent(getActivity(), KeychainIntentService.class); +        intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING); + +        // fill values for this action +        Bundle data = new Bundle(); +        data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, mSaveKeyringParcel); +        intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + +        // Create a new Messenger for the communication back +        Messenger messenger = new Messenger(saveHandler); +        intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + +        // show progress dialog +        saveHandler.showProgressDialog(getActivity()); + +        // start service with intent +        getActivity().startService(intent); +    } +}
\ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index e4ba6ebd0..51963e963 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -27,8 +27,7 @@ import android.view.View;  import android.view.ViewGroup;  import android.widget.CheckBox;  import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; +import android.widget.Button;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; @@ -52,7 +51,7 @@ public class EncryptAsymmetricFragment extends Fragment {      OnAsymmetricKeySelection mKeySelectionListener;      // view -    private BootstrapButton mSelectKeysButton; +    private Button mSelectKeysButton;      private CheckBox mSign;      private TextView mMainUserId;      private TextView mMainUserIdRest; @@ -99,7 +98,7 @@ public class EncryptAsymmetricFragment extends Fragment {      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {          View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false); -        mSelectKeysButton = (BootstrapButton) view.findViewById(R.id.btn_selectEncryptKeys); +        mSelectKeysButton = (Button) view.findViewById(R.id.btn_selectEncryptKeys);          mSign = (CheckBox) view.findViewById(R.id.sign);          mMainUserId = (TextView) view.findViewById(R.id.mainUserId);          mMainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); @@ -204,7 +203,7 @@ public class EncryptAsymmetricFragment extends Fragment {                  userId = null;              }              if (userId != null && userId[0] != null) { -                mMainUserId.setText(userId[0]); +                mMainUserId.setText(String.format("%#16x", Long.parseLong(userId[0])));              } else {                  mMainUserId.setText(getResources().getString(R.string.user_id_no_name));              } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java index 4da76bdfb..2fabeb82c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java @@ -33,8 +33,8 @@ import android.widget.ArrayAdapter;  import android.widget.CheckBox;  import android.widget.Spinner;  import android.widget.TextView; +import android.widget.ImageButton; -import com.beardedhen.androidbootstrap.BootstrapButton;  import com.devspark.appmsg.AppMsg;  import org.sufficientlysecure.keychain.Constants; @@ -66,7 +66,7 @@ public class EncryptFileFragment extends Fragment {      private TextView mFilename = null;      private CheckBox mDeleteAfter = null;      private CheckBox mShareAfter = null; -    private BootstrapButton mBrowse = null; +    private ImageButton mBrowse = null;      private View mEncryptFile;      // model @@ -99,7 +99,7 @@ public class EncryptFileFragment extends Fragment {          });          mFilename = (TextView) view.findViewById(R.id.filename); -        mBrowse = (BootstrapButton) view.findViewById(R.id.btn_browse); +        mBrowse = (ImageButton) view.findViewById(R.id.btn_browse);          mBrowse.setOnClickListener(new View.OnClickListener() {              public void onClick(View v) {                  if (Constants.KITKAT) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index f7455905d..3ff3b56bf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -36,11 +36,6 @@ import android.view.View;  import android.view.View.OnClickListener;  import android.view.ViewGroup; -import com.github.johnpersano.supertoasts.SuperCardToast; -import com.github.johnpersano.supertoasts.SuperToast; -import com.github.johnpersano.supertoasts.util.OnClickWrapper; -import com.github.johnpersano.supertoasts.util.Style; -  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.helper.OtherHelper; @@ -54,6 +49,7 @@ import org.sufficientlysecure.keychain.service.OperationResults.ImportResult;  import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;  import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout;  import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Notify;  import java.util.ArrayList;  import java.util.Locale; @@ -64,8 +60,12 @@ public class ImportKeysActivity extends ActionBarActivity {              + "IMPORT_KEY_FROM_QR_CODE";      public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = Constants.INTENT_PREFIX              + "IMPORT_KEY_FROM_KEYSERVER"; +    public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT = +            Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_KEY_SERVER_AND_RETURN_RESULT";      public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN = Constants.INTENT_PREFIX              + "IMPORT_KEY_FROM_KEY_SERVER_AND_RETURN"; +    public static final String ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN = Constants.INTENT_PREFIX +            + "IMPORT_KEY_FROM_FILE_AND_RETURN";      public static final String ACTION_IMPORT_KEY_FROM_KEYBASE = Constants.INTENT_PREFIX              + "IMPORT_KEY_FROM_KEYBASE"; @@ -75,6 +75,8 @@ public class ImportKeysActivity extends ActionBarActivity {      public static final String ACTION_IMPORT_KEY_FROM_NFC = Constants.INTENT_PREFIX              + "IMPORT_KEY_FROM_NFC"; +    public static final String EXTRA_RESULT = "result"; +      // only used by ACTION_IMPORT_KEY      public static final String EXTRA_KEY_BYTES = "key_bytes"; @@ -165,7 +167,8 @@ public class ImportKeysActivity extends ActionBarActivity {                  startListFragment(savedInstanceState, importData, null, null);              }          } else if (ACTION_IMPORT_KEY_FROM_KEYSERVER.equals(action) -                || ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN.equals(action)) { +                || ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN.equals(action) +                || ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(action)) {              // only used for OpenPgpService              if (extras.containsKey(EXTRA_PENDING_INTENT_DATA)) { @@ -224,7 +227,8 @@ public class ImportKeysActivity extends ActionBarActivity {                  );                  return;              } -        } else if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)) { +        } else if (ACTION_IMPORT_KEY_FROM_FILE.equals(action) +                    || ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(action)) {              // NOTE: this only displays the appropriate fragment, no actions are taken              mSwitchToTab = TAB_FILE; @@ -373,11 +377,7 @@ public class ImportKeysActivity extends ActionBarActivity {      private boolean isFingerprintValid(String fingerprint) {          if (fingerprint == null || fingerprint.length() < 40) { -            SuperCardToast toast = SuperCardToast.create(this, -                    getString(R.string.import_qr_code_too_short_fingerprint), -                    SuperToast.Duration.LONG); -            toast.setBackground(SuperToast.Background.RED); -            toast.show(); +            Notify.showNotify(this, R.string.import_qr_code_too_short_fingerprint, Notify.Style.ERROR);              return false;          } else {              return true; @@ -386,9 +386,6 @@ public class ImportKeysActivity extends ActionBarActivity {      /**       * Scroll ViewPager left and right -     * -     * @param event -     * @return       */      @Override      public boolean onTouchEvent(MotionEvent event) { @@ -427,94 +424,34 @@ public class ImportKeysActivity extends ActionBarActivity {                  if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {                      // get returned data bundle                      Bundle returnData = message.getData(); +                    if (returnData == null) { +                        return; +                    }                      final ImportResult result = -                            returnData.<ImportResult>getParcelable(KeychainIntentService.RESULT); - -                    int resultType = result.getResult(); - -                    String str; -                    int duration, color; - -                    // Not an overall failure -                    if ((resultType & ImportResult.RESULT_ERROR) == 0) { -                        String withWarnings; - -                        // Any warnings? -                        if ((resultType & ImportResult.RESULT_WITH_WARNINGS) > 0) { -                            duration = 0; -                            color = Style.ORANGE; -                            withWarnings = getResources().getString(R.string.import_with_warnings); -                        } else { -                            duration = SuperToast.Duration.LONG; -                            color = Style.GREEN; -                            withWarnings = ""; -                        } - -                        // New and updated keys -                        if (result.isOkBoth()) { -                            str = getResources().getQuantityString( -                                    R.plurals.import_keys_added_and_updated_1, result.mNewKeys, result.mNewKeys); -                            str += getResources().getQuantityString( -                                    R.plurals.import_keys_added_and_updated_2, result.mUpdatedKeys, result.mUpdatedKeys, withWarnings); -                        } else if (result.isOkUpdated()) { -                            str = getResources().getQuantityString( -                                    R.plurals.import_keys_updated, result.mUpdatedKeys, result.mUpdatedKeys, withWarnings); -                        } else if (result.isOkNew()) { -                            str = getResources().getQuantityString( -                                    R.plurals.import_keys_added, result.mNewKeys, result.mNewKeys, withWarnings); -                        } else { -                            duration = 0; -                            color = Style.RED; -                            str = "internal error"; -                        } - -                    } else { -                        duration = 0; -                        color = Style.RED; -                        if (result.isFailNothing()) { -                            str = getString(R.string.import_error_nothing); -                        } else { -                            str = getString(R.string.import_error); -                        } +                            returnData.getParcelable(KeychainIntentService.RESULT); +                    if (result == null) { +                        return;                      } -                    SuperCardToast toast = new SuperCardToast(ImportKeysActivity.this, -                            SuperToast.Type.BUTTON, Style.getStyle(color, SuperToast.Animations.POPUP)); -                    toast.setText(str); -                    toast.setDuration(duration); -                    toast.setIndeterminate(duration == 0); -                    toast.setSwipeToDismiss(true); -                    toast.setButtonIcon(R.drawable.ic_action_view_as_list, -                            getResources().getString(R.string.import_view_log)); -                    toast.setButtonTextColor(getResources().getColor(R.color.black)); -                    toast.setTextColor(getResources().getColor(R.color.black)); -                    toast.setOnClickWrapper(new OnClickWrapper("supercardtoast", -                            new SuperToast.OnClickListener() { -                                @Override -                                public void onClick(View view, Parcelable token) { -                                    Intent intent = new Intent( -                                            ImportKeysActivity.this, LogDisplayActivity.class); -                                    intent.putExtra(LogDisplayFragment.EXTRA_RESULT, result); -                                    startActivity(intent); -                                } -                            } -                    )); -                    toast.show(); - -                    /* -                    if (bad > 0) { -                        BadImportKeyDialogFragment badImportKeyDialogFragment = -                                BadImportKeyDialogFragment.newInstance(bad); -                        badImportKeyDialogFragment.show(getSupportFragmentManager(), "badKeyDialog"); +                    if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction())) { +                        Intent intent = new Intent(); +                        intent.putExtra(EXTRA_RESULT, result); +                        ImportKeysActivity.this.setResult(RESULT_OK, intent); +                        ImportKeysActivity.this.finish(); +                        return;                      } -                    */ - -                    /*                      if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN.equals(getIntent().getAction())) { -                        ImportKeysActivity.this.setResult(Activity.RESULT_OK, mPendingIntentData); -                        finish(); +                        ImportKeysActivity.this.setResult(RESULT_OK, mPendingIntentData); +                        ImportKeysActivity.this.finish(); +                        return; +                    } +                    if (ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(getIntent().getAction())) { +                        ImportKeysActivity.this.setResult(RESULT_OK); +                        ImportKeysActivity.this.finish(); +                        return;                      } -                    */ + +                    result.displayNotify(ImportKeysActivity.this);                  }              }          }; @@ -600,11 +537,7 @@ public class ImportKeysActivity extends ActionBarActivity {              startService(intent);          } else { -            SuperCardToast toast = SuperCardToast.create(this, -                    getString(R.string.error_nothing_import), -                    SuperToast.Duration.LONG); -            toast.setBackground(SuperToast.Background.RED); -            toast.show(); +            Notify.showNotify(this, R.string.error_nothing_import, Notify.Style.ERROR);          }      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java index 84fd513a0..9a39b6cc3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -35,6 +35,7 @@ import org.sufficientlysecure.keychain.helper.Preferences;  import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;  import org.sufficientlysecure.keychain.keyimport.Keyserver;  import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;  import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper;  import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter;  import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListKeybaseLoader; @@ -79,6 +80,7 @@ public class ImportKeysListFragment extends ListFragment implements      public ArrayList<ParcelableKeyRing> getSelectedData() {          ArrayList<ParcelableKeyRing> result = new ArrayList<ParcelableKeyRing>();          for (ImportKeysListEntry entry : getSelectedEntries()) { +            Log.d(Constants.TAG, "code" + Integer.toString(entry.hashCode()));              result.add(mCachedKeyData.get(entry.hashCode()));          }          return result; @@ -207,7 +209,9 @@ public class ImportKeysListFragment extends ListFragment implements          if (getLoaderManager().getLoader(LOADER_ID_KEYBASE) != null) {              getLoaderManager().destroyLoader(LOADER_ID_KEYBASE);          } -        setListShown(true); +        if (getView() != null) { +            setListShown(true); +        }      }      private void restartLoaders() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java index de16142d6..7ce7a06aa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java @@ -113,10 +113,10 @@ public class KeyListActivity extends DrawerActivity {      }      private void createKey() { -        Intent intent = new Intent(this, EditKeyActivity.class); -        intent.setAction(EditKeyActivity.ACTION_CREATE_KEY); -        intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true); -        intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, ""); // show user id view +        Intent intent = new Intent(this, WizardActivity.class); +//        intent.setAction(EditKeyActivity.ACTION_CREATE_KEY); +//        intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true); +//        intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, ""); // show user id view          startActivityForResult(intent, 0);      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 48ad13425..0940d5632 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -51,8 +51,8 @@ import android.widget.ImageButton;  import android.widget.ImageView;  import android.widget.ListView;  import android.widget.TextView; +import android.widget.Button; -import com.beardedhen.androidbootstrap.BootstrapButton;  import com.devspark.appmsg.AppMsg;  import org.sufficientlysecure.keychain.Constants; @@ -85,8 +85,8 @@ public class KeyListFragment extends LoaderFragment      private String mQuery;      private SearchView mSearchView;      // empty list layout -    private BootstrapButton mButtonEmptyCreate; -    private BootstrapButton mButtonEmptyImport; +    private Button mButtonEmptyCreate; +    private Button mButtonEmptyImport;      /** @@ -101,7 +101,7 @@ public class KeyListFragment extends LoaderFragment          mStickyList.setOnItemClickListener(this);          // empty view -        mButtonEmptyCreate = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_create); +        mButtonEmptyCreate = (Button) view.findViewById(R.id.key_list_empty_button_create);          mButtonEmptyCreate.setOnClickListener(new OnClickListener() {              @Override @@ -113,7 +113,7 @@ public class KeyListFragment extends LoaderFragment                  startActivityForResult(intent, 0);              }          }); -        mButtonEmptyImport = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_import); +        mButtonEmptyImport = (Button) view.findViewById(R.id.key_list_empty_button_import);          mButtonEmptyImport.setOnClickListener(new OnClickListener() {              @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java index e42d9d00b..67317de6e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java @@ -173,7 +173,14 @@ public class LogDisplayFragment extends ListFragment implements OnTouchListener                  ih = (ItemHolder) convertView.getTag();              } -            ih.mText.setText(getResources().getString(entry.mType.getMsgId(), (Object[]) entry.mParameters)); +            // special case: first parameter may be a quantity +            if (entry.mParameters != null && entry.mParameters.length > 0 +                    && entry.mParameters[0] instanceof Integer) { +                ih.mText.setText(getResources().getQuantityString(entry.mType.getMsgId(), +                        (Integer) entry.mParameters[0], entry.mParameters)); +            } else { +                ih.mText.setText(getResources().getString(entry.mType.getMsgId(), entry.mParameters)); +            }              ih.mText.setTextColor(entry.mLevel == LogLevel.DEBUG ? Color.GRAY : Color.BLACK);              convertView.setPadding((entry.mIndent) * dipFactor, 0, 0, 0);              switch (entry.mLevel) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java index b36270981..e156b8b9c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java @@ -30,10 +30,9 @@ import android.view.LayoutInflater;  import android.view.View;  import android.view.View.OnClickListener;  import android.view.ViewGroup; +import android.widget.Button;  import android.widget.TextView; -import com.beardedhen.androidbootstrap.BootstrapButton; -  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.pgp.KeyRing;  import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; @@ -45,7 +44,7 @@ public class SelectSecretKeyLayoutFragment extends Fragment implements LoaderMan      private TextView mKeyUserIdRest;      private TextView mKeyMasterKeyIdHex;      private TextView mNoKeySelected; -    private BootstrapButton mSelectKeyButton; +    private Button mSelectKeyButton;      private Boolean mFilterCertify, mFilterSign;      private Uri mReceivedUri = null; @@ -117,8 +116,7 @@ public class SelectSecretKeyLayoutFragment extends Fragment implements LoaderMan          mKeyUserId = (TextView) view.findViewById(R.id.select_secret_key_user_id);          mKeyUserIdRest = (TextView) view.findViewById(R.id.select_secret_key_user_id_rest);          mKeyMasterKeyIdHex = (TextView) view.findViewById(R.id.select_secret_key_master_key_hex); -        mSelectKeyButton = (BootstrapButton) view -                .findViewById(R.id.select_secret_key_select_key_button); +        mSelectKeyButton = (Button) view.findViewById(R.id.select_secret_key_select_key_button);          mFilterCertify = false;          mFilterSign = false;          mSelectKeyButton.setOnClickListener(new OnClickListener() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java index d9be88d68..c7fffe263 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -152,7 +152,7 @@ public class ViewCertActivity extends ActionBarActivity                      sig.init(signerRing.getSubkey());                      if (sig.verifySignature(signeeRing.getSubkey(), signeeUid)) {                          mStatus.setText(R.string.cert_verify_ok); -                        mStatus.setTextColor(getResources().getColor(R.color.bbutton_success)); +                        mStatus.setTextColor(getResources().getColor(R.color.result_green));                      } else {                          mStatus.setText(R.string.cert_verify_failed);                          mStatus.setTextColor(getResources().getColor(R.color.alert)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 6dc6990e0..22a23e6a5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -54,6 +54,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;  import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;  import org.sufficientlysecure.keychain.provider.KeychainContract;  import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.OperationResults.ImportResult;  import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;  import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout.TabColorizer;  import org.sufficientlysecure.keychain.util.Log; @@ -329,7 +330,7 @@ public class ViewKeyActivity extends ActionBarActivity implements          String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob);          Intent queryIntent = new Intent(this, ImportKeysActivity.class); -        queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN); +        queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT);          queryIntent.putExtra(ImportKeysActivity.EXTRA_FINGERPRINT, fingerprint);          startActivityForResult(queryIntent, REQUEST_CODE_LOOKUP_KEY); @@ -353,7 +354,10 @@ public class ViewKeyActivity extends ActionBarActivity implements          switch (requestCode) {              case REQUEST_CODE_LOOKUP_KEY: {                  if (resultCode == Activity.RESULT_OK) { -                    // TODO: reload key??? move this into fragment? +                    ImportResult result = data.getParcelableExtra(ImportKeysActivity.EXTRA_RESULT); +                    if (result != null) { +                        result.displayNotify(this); +                    }                  }                  break;              } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java index eccd2a5e5..52b573f47 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java @@ -152,7 +152,11 @@ public class ViewKeyShareFragment extends LoaderFragment implements                          KeyRings.buildUnifiedKeyRingUri(dataUri),                          Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);                  String fingerprint = PgpKeyHelper.convertFingerprintToHex(data); -                content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; +                if(!toClipboard){ +                    content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; +                } else { +                    content = fingerprint; +                }              } else {                  // get public keyring as ascii armored string                  Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java new file mode 100644 index 000000000..20b47ed01 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui; + +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.ActionBarActivity; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Patterns; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.RadioGroup; +import android.widget.TextView; + +import org.sufficientlysecure.htmltextview.HtmlTextView; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.ContactHelper; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.regex.Matcher; + + +public class WizardActivity extends ActionBarActivity { + +    private State mCurrentState; + +    // values for mCurrentScreen +    private enum State { +        START, CREATE_KEY, IMPORT_KEY, K9 +    } + +    public static final int REQUEST_CODE_IMPORT = 0x00007703; + +    Button mBackButton; +    Button mNextButton; +    StartFragment mStartFragment; +    CreateKeyFragment mCreateKeyFragment; +    K9Fragment mK9Fragment; + +    private static final String K9_PACKAGE = "com.fsck.k9"; +    //    private static final String K9_MARKET_INTENT_URI_BASE = "market://details?id=%s"; +//    private static final Intent K9_MARKET_INTENT = new Intent(Intent.ACTION_VIEW, Uri.parse( +//            String.format(K9_MARKET_INTENT_URI_BASE, K9_PACKAGE))); +    private static final Intent K9_MARKET_INTENT = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/k9mail/k-9/releases/tag/4.904")); + +    LinearLayout mProgressLayout; +    View mProgressLine; +    ProgressBar mProgressBar; +    ImageView mProgressImage; +    TextView mProgressText; + +    /** +     * Checks if text of given EditText is not empty. If it is empty an error is +     * set and the EditText gets the focus. +     * +     * @param context +     * @param editText +     * @return true if EditText is not empty +     */ +    private static boolean isEditTextNotEmpty(Context context, EditText editText) { +        boolean output = true; +        if (editText.getText().toString().length() == 0) { +            editText.setError("empty!"); +            editText.requestFocus(); +            output = false; +        } else { +            editText.setError(null); +        } + +        return output; +    } + +    public static class StartFragment extends Fragment { +        public static StartFragment newInstance() { +            StartFragment myFragment = new StartFragment(); + +            Bundle args = new Bundle(); +            myFragment.setArguments(args); + +            return myFragment; +        } + +        @Override +        public View onCreateView(LayoutInflater inflater, ViewGroup container, +                                 Bundle savedInstanceState) { +            return inflater.inflate(R.layout.wizard_start_fragment, +                    container, false); +        } +    } + +    public static class CreateKeyFragment extends Fragment { +        public static CreateKeyFragment newInstance() { +            CreateKeyFragment myFragment = new CreateKeyFragment(); + +            Bundle args = new Bundle(); +            myFragment.setArguments(args); + +            return myFragment; +        } + +        @Override +        public View onCreateView(LayoutInflater inflater, ViewGroup container, +                                 Bundle savedInstanceState) { +            View view = inflater.inflate(R.layout.wizard_create_key_fragment, +                    container, false); + +            final AutoCompleteTextView emailView = (AutoCompleteTextView) view.findViewById(R.id.email); +            emailView.setThreshold(1); // Start working from first character +            emailView.setAdapter( +                    new ArrayAdapter<String> +                            (getActivity(), android.R.layout.simple_dropdown_item_1line, +                                    ContactHelper.getPossibleUserEmails(getActivity()) +                            ) +            ); +            emailView.addTextChangedListener(new TextWatcher() { +                @Override +                public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { +                } + +                @Override +                public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { +                } + +                @Override +                public void afterTextChanged(Editable editable) { +                    String email = editable.toString(); +                    if (email.length() > 0) { +                        Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email); +                        if (emailMatcher.matches()) { +                            emailView.setCompoundDrawablesWithIntrinsicBounds(0, 0, +                                    R.drawable.uid_mail_ok, 0); +                        } else { +                            emailView.setCompoundDrawablesWithIntrinsicBounds(0, 0, +                                    R.drawable.uid_mail_bad, 0); +                        } +                    } else { +                        // remove drawable if email is empty +                        emailView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); +                    } +                } +            }); +            final AutoCompleteTextView nameView = (AutoCompleteTextView) view.findViewById(R.id.name); +            nameView.setThreshold(1); // Start working from first character +            nameView.setAdapter( +                    new ArrayAdapter<String> +                            (getActivity(), android.R.layout.simple_dropdown_item_1line, +                                    ContactHelper.getPossibleUserNames(getActivity()) +                            ) +            ); +            return view; +        } +    } + +    public static class K9Fragment extends Fragment { +        public static K9Fragment newInstance() { +            K9Fragment myFragment = new K9Fragment(); + +            Bundle args = new Bundle(); +            myFragment.setArguments(args); + +            return myFragment; +        } + +        @Override +        public View onCreateView(LayoutInflater inflater, ViewGroup container, +                                 Bundle savedInstanceState) { +            View v = inflater.inflate(R.layout.wizard_k9_fragment, +                    container, false); + +            HtmlTextView text = (HtmlTextView) v +                    .findViewById(R.id.wizard_k9_text); +            text.setHtmlFromString("Install K9. It's good for you! Here is a screenhot how to enable OK in K9: (TODO)", true); + +            return v; +        } + +    } + +    /** +     * Loads new fragment +     * +     * @param fragment +     */ +    private void loadFragment(Fragment fragment) { +        FragmentManager fragmentManager = getSupportFragmentManager(); +        FragmentTransaction fragmentTransaction = fragmentManager +                .beginTransaction(); +        fragmentTransaction.replace(R.id.wizard_container, +                fragment); +        fragmentTransaction.commit(); +    } + +    /** +     * Instantiate View and initialize fragments for this Activity +     */ +    @Override +    protected void onCreate(Bundle savedInstanceState) { +        super.onCreate(savedInstanceState); + +        setContentView(R.layout.wizard_activity); +        mBackButton = (Button) findViewById(R.id.wizard_back); +        mNextButton = (Button) findViewById(R.id.wizard_next); + +        // progress layout +        mProgressLayout = (LinearLayout) findViewById(R.id.wizard_progress); +        mProgressLine = findViewById(R.id.wizard_progress_line); +        mProgressBar = (ProgressBar) findViewById(R.id.wizard_progress_progressbar); +        mProgressImage = (ImageView) findViewById(R.id.wizard_progress_image); +        mProgressText = (TextView) findViewById(R.id.wizard_progress_text); + +        changeToState(State.START); +    } + +    private enum ProgressState { +        WORKING, ENABLED, DISABLED, ERROR +    } + +    private void showProgress(ProgressState state, String text) { +        switch (state) { +            case WORKING: +                mProgressBar.setVisibility(View.VISIBLE); +                mProgressImage.setVisibility(View.GONE); +                break; +            case ENABLED: +                mProgressBar.setVisibility(View.GONE); +                mProgressImage.setVisibility(View.VISIBLE); +//			mProgressImage.setImageDrawable(getResources().getDrawable( +//					R.drawable.status_enabled)); +                break; +            case DISABLED: +                mProgressBar.setVisibility(View.GONE); +                mProgressImage.setVisibility(View.VISIBLE); +//			mProgressImage.setImageDrawable(getResources().getDrawable( +//					R.drawable.status_disabled)); +                break; +            case ERROR: +                mProgressBar.setVisibility(View.GONE); +                mProgressImage.setVisibility(View.VISIBLE); +//			mProgressImage.setImageDrawable(getResources().getDrawable( +//					R.drawable.status_fail)); +                break; + +            default: +                break; +        } +        mProgressText.setText(text); + +        mProgressLine.setVisibility(View.VISIBLE); +        mProgressLayout.setVisibility(View.VISIBLE); +    } + +    private void hideProgress() { +        mProgressLine.setVisibility(View.GONE); +        mProgressLayout.setVisibility(View.GONE); +    } + +    public void nextOnClick(View view) { +        // close keyboard +        if (getCurrentFocus() != null) { +            InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); +            inputManager.hideSoftInputFromWindow(getCurrentFocus() +                    .getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); +        } + +        switch (mCurrentState) { +            case START: { +                RadioGroup radioGroup = (RadioGroup) findViewById(R.id.wizard_start_radio_group); +                int selectedId = radioGroup.getCheckedRadioButtonId(); +                switch (selectedId) { +                    case R.id.wizard_start_new_key: { +                        changeToState(State.CREATE_KEY); +                        break; +                    } +                    case R.id.wizard_start_import: { +                        changeToState(State.IMPORT_KEY); +                        break; +                    } +                    case R.id.wizard_start_skip: { +                        finish(); +                        break; +                    } +                } + +                mBackButton.setText(R.string.btn_back); +                break; +            } +            case CREATE_KEY: +                EditText nameEdit = (EditText) findViewById(R.id.name); +                EditText emailEdit = (EditText) findViewById(R.id.email); +                EditText passphraseEdit = (EditText) findViewById(R.id.passphrase); + +                if (isEditTextNotEmpty(this, nameEdit) +                        && isEditTextNotEmpty(this, emailEdit) +                        && isEditTextNotEmpty(this, passphraseEdit)) { + +//                    SaveKeyringParcel newKey = new SaveKeyringParcel(); +//                    newKey.addUserIds.add(nameEdit.getText().toString() + " <" +//                            + emailEdit.getText().toString() + ">"); + + +                    AsyncTask<String, Boolean, Boolean> generateTask = new AsyncTask<String, Boolean, Boolean>() { + +                        @Override +                        protected void onPreExecute() { +                            super.onPreExecute(); + +                            showProgress(ProgressState.WORKING, "generating key..."); +                        } + +                        @Override +                        protected Boolean doInBackground(String... params) { +                            return true; +                        } + +                        @Override +                        protected void onPostExecute(Boolean result) { +                            super.onPostExecute(result); + +                            if (result) { +                                showProgress(ProgressState.ENABLED, "key generated successfully!"); + +                                changeToState(State.K9); +                            } else { +                                showProgress(ProgressState.ERROR, "error in key gen"); +                            } +                        } + +                    }; + +                    generateTask.execute(""); +                } +                break; +            case K9: { +                RadioGroup radioGroup = (RadioGroup) findViewById(R.id.wizard_k9_radio_group); +                int selectedId = radioGroup.getCheckedRadioButtonId(); +                switch (selectedId) { +                    case R.id.wizard_k9_install: { +                        try { +                            startActivity(K9_MARKET_INTENT); +                        } catch (ActivityNotFoundException e) { +                            Log.e(Constants.TAG, "Activity not found for: " + K9_MARKET_INTENT); +                        } +                        break; +                    } +                    case R.id.wizard_k9_skip: { +                        finish(); +                        break; +                    } +                } + +                finish(); +                break; +            } +            default: +                break; +        } +    } + +    @Override +    protected void onActivityResult(int requestCode, int resultCode, Intent data) { +        super.onActivityResult(requestCode, resultCode, data); +        switch (requestCode) { +            case REQUEST_CODE_IMPORT: { +                if (resultCode == Activity.RESULT_OK) { +                    // imported now... +                    changeToState(State.K9); +                } else { +                    // back to start +                    changeToState(State.START); +                } +                break; +            } + +            default: { +                super.onActivityResult(requestCode, resultCode, data); + +                break; +            } +        } +    } + +    public void backOnClick(View view) { +        switch (mCurrentState) { +            case START: +                finish(); +                break; +            case CREATE_KEY: +                changeToState(State.START); +                break; +            case IMPORT_KEY: +                changeToState(State.START); +                break; +            default: +                changeToState(State.START); +                break; +        } +    } + +    private void changeToState(State state) { +        switch (state) { +            case START: { +                mCurrentState = State.START; +                mStartFragment = StartFragment.newInstance(); +                loadFragment(mStartFragment); +                mBackButton.setText(android.R.string.cancel); +                mNextButton.setText(R.string.btn_next); +                break; +            } +            case CREATE_KEY: { +                mCurrentState = State.CREATE_KEY; +                mCreateKeyFragment = CreateKeyFragment.newInstance(); +                loadFragment(mCreateKeyFragment); +                break; +            } +            case IMPORT_KEY: { +                mCurrentState = State.IMPORT_KEY; +                Intent intent = new Intent(this, ImportKeysActivity.class); +                intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN); +                startActivityForResult(intent, REQUEST_CODE_IMPORT); +                break; +            } +            case K9: { +                mCurrentState = State.K9; +                mBackButton.setEnabled(false); // don't go back to import/create key +                mK9Fragment = K9Fragment.newInstance(); +                loadFragment(mK9Fragment); +                break; +            } +        } +    } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index a44d32e5b..7a55f9aaa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -85,6 +85,10 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {      public ArrayList<ImportKeysListEntry> getSelectedEntries() {          ArrayList<ImportKeysListEntry> selectedData = new ArrayList<ImportKeysListEntry>(); +        // Nothing to select, nvm. +        if (mData == null) { +            return selectedData; +        }          for (ImportKeysListEntry entry : mData) {              if (entry.isSelected()) {                  selectedData.add(entry); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index 7a7acfe89..7fc78dc41 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -144,7 +144,6 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC              vComment.setVisibility(View.GONE);          } -        // show small star icon for primary user ids          boolean isPrimary = cursor.getInt(mIsPrimary) != 0;          boolean isRevoked = cursor.getInt(mIsRevoked) > 0; @@ -185,6 +184,8 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC              vName.setEnabled(true);              vAddress.setEnabled(true); +            // verified: has been verified +            // isPrimary: show small star icon for primary user ids              int verified = cursor.getInt(mVerifiedId);              switch (verified) {                  case Certs.VERIFIED_SECRET: diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java new file mode 100644 index 000000000..e6445c074 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui.adapter; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.os.Build; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.KeyRing; + +import java.util.List; + +public class UserIdsArrayAdapter extends ArrayAdapter<String> { +    protected LayoutInflater mInflater; +    protected Activity mActivity; + +    protected List<String> mData; + +    static class ViewHolder { +        public TextView vName; +        public TextView vAddress; +        public TextView vComment; +        public ImageView vVerified; +        public ImageView vHasChanges; +        public CheckBox vCheckBox; +    } + +    public UserIdsArrayAdapter(Activity activity) { +        super(activity, -1); +        mActivity = activity; +        mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); +    } + +    @TargetApi(Build.VERSION_CODES.HONEYCOMB) +    public void setData(List<String> data) { +        clear(); +        if (data != null) { +            this.mData = data; + +            // add data to extended ArrayAdapter +            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { +                addAll(data); +            } else { +                for (String entry : data) { +                    add(entry); +                } +            } +        } +    } + +    public List<String> getData() { +        return mData; +    } + +    @Override +    public boolean hasStableIds() { +        return true; +    } + +    public View getView(int position, View convertView, ViewGroup parent) { +        String entry = mData.get(position); +        ViewHolder holder; +        if (convertView == null) { +            holder = new ViewHolder(); +            convertView = mInflater.inflate(R.layout.view_key_userids_item, null); +            holder.vName = (TextView) convertView.findViewById(R.id.userId); +            holder.vAddress = (TextView) convertView.findViewById(R.id.address); +            holder.vComment = (TextView) convertView.findViewById(R.id.comment); +            holder.vVerified = (ImageView) convertView.findViewById(R.id.certified); +            holder.vHasChanges = (ImageView) convertView.findViewById(R.id.has_changes); +            holder.vCheckBox = (CheckBox) convertView.findViewById(R.id.checkBox); +            convertView.setTag(holder); +        } else { +            holder = (ViewHolder) convertView.getTag(); +        } + +        // user id +        String[] splitUserId = KeyRing.splitUserId(entry); +        if (splitUserId[0] != null) { +            holder.vName.setText(splitUserId[0]); +        } else { +            holder.vName.setText(R.string.user_id_no_name); +        } +        if (splitUserId[1] != null) { +            holder.vAddress.setText(splitUserId[1]); +            holder.vAddress.setVisibility(View.VISIBLE); +        } else { +            holder.vAddress.setVisibility(View.GONE); +        } +        if (splitUserId[2] != null) { +            holder.vComment.setText(splitUserId[2]); +            holder.vComment.setVisibility(View.VISIBLE); +        } else { +            holder.vComment.setVisibility(View.GONE); +        } + +        holder.vCheckBox.setVisibility(View.GONE); + +        holder.vVerified.setImageResource(R.drawable.key_certify_ok_depth0); + +        // all items are "new" +        holder.vHasChanges.setVisibility(View.VISIBLE); + +        return convertView; +    } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java index db7c38e71..c27266e3f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java @@ -24,17 +24,32 @@ import android.os.Message;  import android.os.Messenger;  import android.os.RemoteException;  import android.support.v4.app.DialogFragment; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; +import android.widget.TextView;  import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.util.Log; -public class AddUserIdDialogFragment extends DialogFragment { +public class AddUserIdDialogFragment extends DialogFragment implements EditText.OnEditorActionListener {      private static final String ARG_MESSENGER = "messenger"; -    public static final int MESSAGE_OK = 1; +    public static final int MESSAGE_OKAY = 1; + +    public static final String MESSAGE_DATA_USER_ID = "user_id";      private Messenger mMessenger; +    EditText mName; +    EditText mAddress; +    EditText mComment; +      /**       * Creates new instance of this dialog fragment       */ @@ -55,34 +70,75 @@ public class AddUserIdDialogFragment extends DialogFragment {      public Dialog onCreateDialog(Bundle savedInstanceState) {          mMessenger = getArguments().getParcelable(ARG_MESSENGER); -        CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(getActivity()); -//        CharSequence[] array = {"change to primary user id", "revoke"}; -// -//        builder.setTitle("select action!"); -//        builder.setItems(array, new DialogInterface.OnClickListener() { -// -//            @Override -//            public void onClick(DialogInterface dialog, int which) { -//                switch (which) { -//                    case 0: -//                        sendMessageToHandler(MESSAGE_CHANGE_PRIMARY_USER_ID, null); -//                        break; -//                    case 1: -//                        sendMessageToHandler(MESSAGE_REVOKE, null); -//                        break; -//                    default: -//                        break; -//                } -//            } -//        }); -//        builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() { -//            @Override -//            public void onClick(DialogInterface dialog, int id) { -//                dismiss(); -//            } -//        }); - -        return builder.show(); +        CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(getActivity()); +        LayoutInflater inflater = getActivity().getLayoutInflater(); +        View view = inflater.inflate(R.layout.add_user_id_dialog, null); +        alert.setView(view); +        alert.setTitle("Add Identity"); + +        mName = (EditText) view.findViewById(R.id.name); +        mAddress = (EditText) view.findViewById(R.id.address); +        mComment = (EditText) view.findViewById(R.id.comment); + +        alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + +            @Override +            public void onClick(DialogInterface dialog, int id) { +                done(); +            } +        }); + +        alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + +            @Override +            public void onClick(DialogInterface dialog, int id) { +                dialog.cancel(); +            } +        }); + + +        return alert.show(); +    } + +    @Override +    public void onActivityCreated(Bundle arg0) { +        super.onActivityCreated(arg0); +        // Show soft keyboard automatically +        mName.requestFocus(); +        getDialog().getWindow().setSoftInputMode( +                WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); +        mComment.setOnEditorActionListener(this); +    } + +    @Override +    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { +        if (EditorInfo.IME_ACTION_DONE == actionId) { +            done(); +            return true; +        } +        return false; +    } + +    private void done() { +        String name = mName.getText().toString(); +        String email = mAddress.getText().toString(); +        String comment = mComment.getText().toString(); + +        String userId = null; +        if (!TextUtils.isEmpty(name)) { +            userId = name; +            if (!TextUtils.isEmpty(comment)) { +                userId += " (" + comment + ")"; +            } +            if (!TextUtils.isEmpty(email)) { +                userId += " <" + email + ">"; +            } +        } +        Bundle data = new Bundle(); +        data.putString(MESSAGE_DATA_USER_ID, userId); +        sendMessageToHandler(MESSAGE_OKAY, data); + +        this.dismiss();      }      /** @@ -105,4 +161,5 @@ public class AddUserIdDialogFragment extends DialogFragment {              Log.w(Constants.TAG, "Messenger is null!", e);          }      } +  } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java index c02c37055..15d50d7ed 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java @@ -33,11 +33,8 @@ import android.view.LayoutInflater;  import android.view.View;  import android.widget.CheckBox;  import android.widget.EditText; +import android.widget.ImageButton;  import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; - -import com.devspark.appmsg.AppMsg;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.helper.FileHelper; @@ -63,7 +60,7 @@ public class FileDialogFragment extends DialogFragment {      private Messenger mMessenger;      private EditText mFilename; -    private BootstrapButton mBrowse; +    private ImageButton mBrowse;      private CheckBox mCheckBox;      private TextView mMessageTextView; @@ -120,7 +117,7 @@ public class FileDialogFragment extends DialogFragment {          mFilename = (EditText) view.findViewById(R.id.input);          mFilename.setText(mFile.getName()); -        mBrowse = (BootstrapButton) view.findViewById(R.id.btn_browse); +        mBrowse = (ImageButton) view.findViewById(R.id.btn_browse);          mBrowse.setOnClickListener(new View.OnClickListener() {              public void onClick(View v) {                  // only .asc or .gpg files diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java index 24641a9cc..a29c17d37 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java @@ -26,8 +26,7 @@ import android.view.animation.AlphaAnimation;  import android.view.animation.Animation;  import android.widget.LinearLayout;  import android.widget.TextView; - -import com.beardedhen.androidbootstrap.FontAwesomeText; +import android.widget.ImageButton;  import org.sufficientlysecure.keychain.R; @@ -50,7 +49,7 @@ import org.sufficientlysecure.keychain.R;   */  public class FoldableLinearLayout extends LinearLayout { -    private FontAwesomeText mFoldableIcon; +    private ImageButton mFoldableIcon;      private boolean mFolded;      private boolean mHasMigrated = false;      private Integer mShortAnimationDuration = null; @@ -58,8 +57,6 @@ public class FoldableLinearLayout extends LinearLayout {      private LinearLayout mFoldableContainer = null;      private View mFoldableLayout = null; -    private String mFoldedIconName; -    private String mUnFoldedIconName;      private String mFoldedLabel;      private String mUnFoldedLabel; @@ -87,15 +84,11 @@ public class FoldableLinearLayout extends LinearLayout {          if (attrs != null) {              TypedArray a = context.obtainStyledAttributes(attrs,                      R.styleable.FoldableLinearLayout, 0, 0); -            mFoldedIconName = a.getString(R.styleable.FoldableLinearLayout_foldedIcon); -            mUnFoldedIconName = a.getString(R.styleable.FoldableLinearLayout_unFoldedIcon);              mFoldedLabel = a.getString(R.styleable.FoldableLinearLayout_foldedLabel);              mUnFoldedLabel = a.getString(R.styleable.FoldableLinearLayout_unFoldedLabel);              a.recycle();          }          // If any attribute isn't found then set a default one -        mFoldedIconName = (mFoldedIconName == null) ? "fa-chevron-right" : mFoldedIconName; -        mUnFoldedIconName = (mUnFoldedIconName == null) ? "fa-chevron-down" : mUnFoldedIconName;          mFoldedLabel = (mFoldedLabel == null) ? context.getString(R.id.none) : mFoldedLabel;          mUnFoldedLabel = (mUnFoldedLabel == null) ? context.getString(R.id.none) : mUnFoldedLabel;      } @@ -146,8 +139,8 @@ public class FoldableLinearLayout extends LinearLayout {      }      private void initialiseInnerViews() { -        mFoldableIcon = (FontAwesomeText) mFoldableLayout.findViewById(R.id.foldableIcon); -        mFoldableIcon.setIcon(mFoldedIconName); +        mFoldableIcon = (ImageButton) mFoldableLayout.findViewById(R.id.foldableIcon); +        mFoldableIcon.setImageResource(R.drawable.ic_action_expand);          mFoldableTextView = (TextView) mFoldableLayout.findViewById(R.id.foldableText);          mFoldableTextView.setText(mFoldedLabel); @@ -160,7 +153,7 @@ public class FoldableLinearLayout extends LinearLayout {              public void onClick(View view) {                  mFolded = !mFolded;                  if (mFolded) { -                    mFoldableIcon.setIcon(mUnFoldedIconName); +                    mFoldableIcon.setImageResource(R.drawable.ic_action_collapse);                      mFoldableContainer.setVisibility(View.VISIBLE);                      AlphaAnimation animation = new AlphaAnimation(0f, 1f);                      animation.setDuration(mShortAnimationDuration); @@ -168,7 +161,7 @@ public class FoldableLinearLayout extends LinearLayout {                      mFoldableTextView.setText(mUnFoldedLabel);                  } else { -                    mFoldableIcon.setIcon(mFoldedIconName); +                    mFoldableIcon.setImageResource(R.drawable.ic_action_expand);                      AlphaAnimation animation = new AlphaAnimation(1f, 0f);                      animation.setDuration(mShortAnimationDuration);                      animation.setAnimationListener(new Animation.AnimationListener() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java index 40fe7665c..c23b4c3ff 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java @@ -31,12 +31,12 @@ import android.view.ViewGroup;  import android.widget.CheckBox;  import android.widget.CompoundButton;  import android.widget.DatePicker; +import android.widget.ImageButton;  import android.widget.LinearLayout;  import android.widget.TableLayout;  import android.widget.TableRow;  import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; +import android.widget.Button;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; @@ -54,11 +54,11 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {      private EditorListener mEditorListener = null;      private boolean mIsMasterKey; -    BootstrapButton mDeleteButton; +    ImageButton mDeleteButton;      TextView mAlgorithm;      TextView mKeyId;      TextView mCreationDate; -    BootstrapButton mExpiryDateButton; +    Button mExpiryDateButton;      Calendar mCreatedDate;      Calendar mExpiryDate;      Calendar mOriginalExpiryDate = null; @@ -122,9 +122,9 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {          mAlgorithm = (TextView) findViewById(R.id.algorithm);          mKeyId = (TextView) findViewById(R.id.keyId);          mCreationDate = (TextView) findViewById(R.id.creation); -        mExpiryDateButton = (BootstrapButton) findViewById(R.id.expiry); +        mExpiryDateButton = (Button) findViewById(R.id.expiry); -        mDeleteButton = (BootstrapButton) findViewById(R.id.delete); +        mDeleteButton = (ImageButton) findViewById(R.id.delete);          mDeleteButton.setOnClickListener(this);          mChkCertify = (CheckBox) findViewById(R.id.chkCertify);          mChkCertify.setOnCheckedChangeListener(mCheckChanged); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java index dc4c13b1a..3fd01958a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java @@ -22,17 +22,16 @@ import android.util.AttributeSet;  import android.view.View;  import android.view.View.OnClickListener;  import android.view.ViewGroup; +import android.widget.ImageButton;  import android.widget.LinearLayout;  import android.widget.TextView; -import com.beardedhen.androidbootstrap.BootstrapButton; -  import org.sufficientlysecure.keychain.R;  public class KeyServerEditor extends LinearLayout implements Editor, OnClickListener {      private EditorListener mEditorListener = null; -    BootstrapButton mDeleteButton; +    ImageButton mDeleteButton;      TextView mServer;      public KeyServerEditor(Context context) { @@ -50,7 +49,7 @@ public class KeyServerEditor extends LinearLayout implements Editor, OnClickList          mServer = (TextView) findViewById(R.id.server); -        mDeleteButton = (BootstrapButton) findViewById(R.id.delete); +        mDeleteButton = (ImageButton) findViewById(R.id.delete);          mDeleteButton.setOnClickListener(this);          super.onFinishInflate(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java index b7336318f..4ecc96cee 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java @@ -32,8 +32,7 @@ import android.view.View.OnClickListener;  import android.view.ViewGroup;  import android.widget.LinearLayout;  import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; +import android.widget.ImageButton;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; @@ -52,7 +51,7 @@ import java.util.Vector;  public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Editor {      private LayoutInflater mInflater; -    private BootstrapButton mPlusButton; +    private ImageButton mPlusButton;      private ViewGroup mEditors;      private TextView mTitle;      private int mType = 0; @@ -126,7 +125,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor          setDrawingCacheEnabled(true);          setAlwaysDrawnWithCacheEnabled(true); -        mPlusButton = (BootstrapButton) findViewById(R.id.plusbutton); +        mPlusButton = (ImageButton) findViewById(R.id.plusbutton);          mPlusButton.setOnClickListener(this);          mEditors = (ViewGroup) findViewById(R.id.editors); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java index 9781dd213..9b561f819 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java @@ -31,8 +31,7 @@ import android.widget.AutoCompleteTextView;  import android.widget.EditText;  import android.widget.LinearLayout;  import android.widget.RadioButton; - -import com.beardedhen.androidbootstrap.BootstrapButton; +import android.widget.ImageButton;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.helper.ContactHelper; @@ -43,7 +42,7 @@ import java.util.regex.Matcher;  public class UserIdEditor extends LinearLayout implements Editor, OnClickListener {      private EditorListener mEditorListener = null; -    private BootstrapButton mDeleteButton; +    private ImageButton mDeleteButton;      private RadioButton mIsMainUserId;      private String mOriginalID;      private EditText mName; @@ -103,7 +102,7 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene          setDrawingCacheEnabled(true);          setAlwaysDrawnWithCacheEnabled(true); -        mDeleteButton = (BootstrapButton) findViewById(R.id.delete); +        mDeleteButton = (ImageButton) findViewById(R.id.delete);          mDeleteButton.setOnClickListener(this);          mIsMainUserId = (RadioButton) findViewById(R.id.isMainUserId);          mIsMainUserId.setOnClickListener(this); @@ -119,7 +118,7 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene          mEmail.setAdapter(                  new ArrayAdapter<String>                          (this.getContext(), android.R.layout.simple_dropdown_item_1line, -                                ContactHelper.getMailAccounts(getContext()) +                                ContactHelper.getPossibleUserEmails(getContext())                          ));          mEmail.addTextChangedListener(new TextWatcher(){              @Override diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_accounts.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_accounts.pngBinary files differ new file mode 100644 index 000000000..7cc407315 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_accounts.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_collapse.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_collapse.pngBinary files differ new file mode 100644 index 000000000..e9d2dcb46 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_collapse.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_expand.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_expand.pngBinary files differ new file mode 100644 index 000000000..29f4de211 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_expand.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_new_account.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_new_account.pngBinary files differ new file mode 100644 index 000000000..790af372d --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_new_account.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_not_secure.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_not_secure.pngBinary files differ new file mode 100644 index 000000000..5ee148080 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_not_secure.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_view_as_list.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_view_as_list.pngBinary files differ index 86da228e9..e08afae85 100644 --- a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_view_as_list.png +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_view_as_list.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_accounts.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_accounts.pngBinary files differ new file mode 100644 index 000000000..2bf88c183 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_accounts.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_collapse.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_collapse.pngBinary files differ new file mode 100644 index 000000000..4ac28f270 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_collapse.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_expand.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_expand.pngBinary files differ new file mode 100644 index 000000000..bb46bb315 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_expand.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_new_account.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_new_account.pngBinary files differ new file mode 100644 index 000000000..69c801dcc --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_new_account.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_not_secure.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_not_secure.pngBinary files differ new file mode 100644 index 000000000..dd5289ee4 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_not_secure.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_view_as_list.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_view_as_list.pngBinary files differ index ccb4c7d7b..4fe0edfa3 100644 --- a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_view_as_list.png +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_view_as_list.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/minus.png b/OpenKeychain/src/main/res/drawable-mdpi/minus.pngBinary files differ new file mode 100644 index 000000000..d59e4a3e1 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/minus.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/plus.png b/OpenKeychain/src/main/res/drawable-mdpi/plus.pngBinary files differ new file mode 100644 index 000000000..88ee823af --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/plus.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_accounts.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_accounts.pngBinary files differ new file mode 100644 index 000000000..f1ec295d2 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_accounts.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_collapse.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_collapse.pngBinary files differ new file mode 100644 index 000000000..60ac6b066 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_collapse.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_expand.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_expand.pngBinary files differ new file mode 100644 index 000000000..76937f57a --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_expand.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_new_account.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_new_account.pngBinary files differ new file mode 100644 index 000000000..c6dfd0bcb --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_new_account.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_not_secure.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_not_secure.pngBinary files differ new file mode 100644 index 000000000..312a230e7 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_not_secure.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_view_as_list.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_view_as_list.pngBinary files differ index b9c93c8c2..a38638e4d 100644 --- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_view_as_list.png +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_view_as_list.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/minus.png b/OpenKeychain/src/main/res/drawable-xhdpi/minus.pngBinary files differ new file mode 100644 index 000000000..8a98ea967 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/minus.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/plus.png b/OpenKeychain/src/main/res/drawable-xhdpi/plus.pngBinary files differ new file mode 100644 index 000000000..def608491 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/plus.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_accounts.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_accounts.pngBinary files differ new file mode 100644 index 000000000..da24654eb --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_accounts.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_collapse.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_collapse.pngBinary files differ new file mode 100644 index 000000000..76ec594dc --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_collapse.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_expand.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_expand.pngBinary files differ new file mode 100644 index 000000000..22003198b --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_expand.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_new_account.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_new_account.pngBinary files differ new file mode 100644 index 000000000..38589ba0e --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_new_account.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_not_secure.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_not_secure.pngBinary files differ new file mode 100644 index 000000000..4aa9dc85c --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_not_secure.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_view_as_list.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_view_as_list.pngBinary files differ index 460041640..b00a85f6d 100644 --- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_view_as_list.png +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_view_as_list.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/minus.png b/OpenKeychain/src/main/res/drawable-xxhdpi/minus.pngBinary files differ new file mode 100644 index 000000000..c46bf00de --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/minus.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/plus.png b/OpenKeychain/src/main/res/drawable-xxhdpi/plus.pngBinary files differ new file mode 100644 index 000000000..e1f6e841f --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/plus.png diff --git a/OpenKeychain/src/main/res/drawable/button_edgy.xml b/OpenKeychain/src/main/res/drawable/button_edgy.xml new file mode 100644 index 000000000..fdb94d40e --- /dev/null +++ b/OpenKeychain/src/main/res/drawable/button_edgy.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> +    <item android:state_pressed="true" > +        <shape android:shape="rectangle"  > +            <padding +                android:bottom="6dip" +                android:left="6dip" +                android:right="6dip" +                android:top="6dip" /> +            <solid android:color="#ebebeb" /> +            <stroke android:color="#cccccc" android:width="1.5dip" /> +        </shape> +    </item> +    <item android:state_focused="true"> +        <shape android:shape="rectangle"  > +            <padding +                android:bottom="6dip" +                android:left="6dip" +                android:right="6dip" +                android:top="6dip" /> +            <solid android:color="#ebebeb"/> +            <stroke android:color="#cccccc" android:width="1.5dip" /> +        </shape> +    </item> +    <item > +        <shape android:shape="rectangle"  > +            <padding +                android:bottom="6dip" +                android:left="6dip" +                android:right="6dip" +                android:top="6dip" /> +            <solid android:color="#ffffff" /> +            <stroke android:color="#cccccc" android:width="1.5dip" /> +        </shape> +    </item> +</selector>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/drawable/button_no_style.xml b/OpenKeychain/src/main/res/drawable/button_no_style.xml new file mode 100644 index 000000000..e9571c2b0 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable/button_no_style.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + +</selector>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/drawable/button_rounded.xml b/OpenKeychain/src/main/res/drawable/button_rounded.xml new file mode 100644 index 000000000..f547b8cdb --- /dev/null +++ b/OpenKeychain/src/main/res/drawable/button_rounded.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> +    <item android:state_pressed="true" > +        <shape android:shape="rectangle"  > +            <padding +                android:bottom="6dip" +                android:left="6dip" +                android:right="6dip" +                android:top="6dip" /> +            <corners android:radius="6dip" /> +            <stroke android:color="#cccccc" android:width="1.5dip" /> +            <stroke android:color="#ebebeb" /> +        </shape> +    </item> +    <item android:state_focused="true"> +        <shape android:shape="rectangle"  > +            <padding +                android:bottom="6dip" +                android:left="6dip" +                android:right="6dip" +                android:top="6dip" /> +            <corners android:radius="6dip" /> +            <stroke android:color="#cccccc" android:width="1.5dip" /> +            <solid android:color="#ebebeb"/> +        </shape> +    </item> +    <item > +        <shape android:shape="rectangle"  > +            <padding +                android:bottom="6dip" +                android:left="6dip" +                android:right="6dip" +                android:top="6dip" /> +            <corners android:radius="6dip" /> +            <stroke android:color="#cccccc" android:width="1.5dip" /> +            <solid android:color="#ffffff" /> +        </shape> +    </item> +</selector>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/drawable/button_rounded_green.xml b/OpenKeychain/src/main/res/drawable/button_rounded_green.xml new file mode 100644 index 000000000..fc12fdf05 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable/button_rounded_green.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> +    <item android:state_pressed="true" > +        <shape android:shape="rectangle"  > +            <padding +                android:bottom="6dip" +                android:left="6dip" +                android:right="6dip" +                android:top="6dip" /> +            <corners android:radius="6dip" /> +            <solid android:color="#47a447" /> +        </shape> +    </item> +    <item android:state_focused="true"> +        <shape android:shape="rectangle"  > +            <padding +                android:bottom="6dip" +                android:left="6dip" +                android:right="6dip" +                android:top="6dip" /> +            <corners android:radius="6dip" /> +            <solid android:color="#47a447"/> +        </shape> +    </item> +    <item > +        <shape android:shape="rectangle"  > +            <padding +                android:bottom="6dip" +                android:left="6dip" +                android:right="6dip" +                android:top="6dip" /> +            <corners android:radius="6dip" /> +            <solid android:color="#5cb85c" /> +        </shape> +    </item> +</selector>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/drawable/button_rounded_red.xml b/OpenKeychain/src/main/res/drawable/button_rounded_red.xml new file mode 100644 index 000000000..330e83939 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable/button_rounded_red.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> +    <item android:state_pressed="true" > +        <shape android:shape="rectangle"  > +            <padding +                android:bottom="6dip" +                android:left="6dip" +                android:right="6dip" +                android:top="6dip" /> +            <corners android:radius="6dip" /> +            <solid android:color="#d2322d" /> +        </shape> +    </item> +    <item android:state_focused="true"> +        <shape android:shape="rectangle"  > +            <padding +                android:bottom="6dip" +                android:left="6dip" +                android:right="6dip" +                android:top="6dip" /> +            <corners android:radius="6dip" /> +            <solid android:color="#d2322d"/> +        </shape> +    </item> +    <item > +        <shape android:shape="rectangle"  > +            <padding +                android:bottom="6dip" +                android:left="6dip" +                android:right="6dip" +                android:top="6dip" /> +            <corners android:radius="6dip" /> +            <solid android:color="#d9534f" /> +        </shape> +    </item> +</selector>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml b/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml new file mode 100644 index 000000000..502ca1c70 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<TableLayout xmlns:android="http://schemas.android.com/apk/res/android" +    android:layout_width="match_parent" +    android:layout_height="wrap_content" +    android:paddingLeft="16dp" +    android:paddingRight="16dp" +    android:stretchColumns="1"> + +    <TableRow android:layout_marginBottom="5dip"> + +        <TextView +            android:layout_width="wrap_content" +            android:layout_height="wrap_content" +            android:layout_gravity="center_vertical" +            android:padding="4dp" +            android:text="Name" /> + +        <EditText +            android:id="@+id/name" +            android:layout_width="match_parent" +            android:layout_height="wrap_content" +            android:imeOptions="actionNext" +            android:padding="4dp" /> +    </TableRow> + +    <TableRow android:layout_marginBottom="10dip"> + +        <TextView +            android:layout_width="wrap_content" +            android:layout_height="wrap_content" +            android:layout_gravity="center_vertical" +            android:padding="4dp" +            android:text="Email" /> + +        <EditText +            android:id="@+id/address" +            android:layout_width="match_parent" +            android:layout_height="wrap_content" +            android:imeOptions="actionNext" +            android:padding="4dp" /> +    </TableRow> + +    <TableRow android:layout_marginBottom="10dip"> + +        <TextView +            android:layout_width="wrap_content" +            android:layout_height="wrap_content" +            android:layout_gravity="center_vertical" +            android:padding="4dp" +            android:text="Comment" /> + +        <EditText +            android:id="@+id/comment" +            android:layout_width="match_parent" +            android:layout_height="wrap_content" +            android:imeOptions="actionDone" +            android:padding="4dp" /> +    </TableRow> + +</TableLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/api_account_settings_fragment.xml b/OpenKeychain/src/main/res/layout/api_account_settings_fragment.xml index 32843eb29..7bb861547 100644 --- a/OpenKeychain/src/main/res/layout/api_account_settings_fragment.xml +++ b/OpenKeychain/src/main/res/layout/api_account_settings_fragment.xml @@ -1,6 +1,5 @@  <?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" -    xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"      xmlns:tools="http://schemas.android.com/tools"      xmlns:custom="http://schemas.android.com/apk/res-auto"      android:layout_width="match_parent" @@ -43,7 +42,7 @@          android:layout_height="wrap_content"          tools:layout="@layout/select_secret_key_layout_fragment" /> -    <com.beardedhen.androidbootstrap.BootstrapButton +    <Button          android:id="@+id/api_account_settings_create_key"          android:layout_width="wrap_content"          android:layout_height="wrap_content" @@ -52,9 +51,9 @@          android:layout_marginRight="4dp"          android:layout_marginTop="4dp"          android:text="@string/api_settings_create_key" -        bootstrapbutton:bb_icon_left="fa-key" -        bootstrapbutton:bb_size="default" -        bootstrapbutton:bb_type="default" /> +        android:background="@drawable/button_edgy" +        android:drawableLeft="@drawable/ic_action_accounts" +        android:textSize="14dip"/>      <org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout          android:layout_width="match_parent" diff --git a/OpenKeychain/src/main/res/layout/decrypt_content.xml b/OpenKeychain/src/main/res/layout/decrypt_content.xml index 866857143..ff75f20ee 100644 --- a/OpenKeychain/src/main/res/layout/decrypt_content.xml +++ b/OpenKeychain/src/main/res/layout/decrypt_content.xml @@ -6,7 +6,7 @@      android:layout_height="match_parent"      android:orientation="vertical"> -    <include layout="@layout/notification_area"/> +    <include layout="@layout/notify_area"/>      <android.support.v4.view.ViewPager          android:id="@+id/decrypt_pager" diff --git a/OpenKeychain/src/main/res/layout/decrypt_file_fragment.xml b/OpenKeychain/src/main/res/layout/decrypt_file_fragment.xml index d1db1c782..098aaaea1 100644 --- a/OpenKeychain/src/main/res/layout/decrypt_file_fragment.xml +++ b/OpenKeychain/src/main/res/layout/decrypt_file_fragment.xml @@ -1,6 +1,5 @@  <?xml version="1.0" encoding="utf-8"?>  <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" -    xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:fillViewport="true"> @@ -43,15 +42,14 @@                      android:minLines="2"                      android:scrollbars="vertical" /> -                <com.beardedhen.androidbootstrap.BootstrapButton +                <ImageButton                      android:id="@+id/decrypt_file_browse"                      android:layout_width="wrap_content"                      android:layout_height="wrap_content"                      android:layout_margin="4dp" -                    bootstrapbutton:bb_icon_left="fa-folder-open" -                    bootstrapbutton:bb_roundedCorners="true" -                    bootstrapbutton:bb_size="default" -                    bootstrapbutton:bb_type="default" /> +                    android:src="@drawable/ic_action_collection" +                    android:background="@drawable/button_rounded" +                    android:layout_gravity="center_vertical"/>              </LinearLayout>              <CheckBox diff --git a/OpenKeychain/src/main/res/layout/decrypt_result_include.xml b/OpenKeychain/src/main/res/layout/decrypt_result_include.xml index 3bc78d325..05877656b 100644 --- a/OpenKeychain/src/main/res/layout/decrypt_result_include.xml +++ b/OpenKeychain/src/main/res/layout/decrypt_result_include.xml @@ -1,6 +1,5 @@  <?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" -    xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"      android:id="@+id/result"      android:orientation="vertical"      android:layout_width="match_parent" @@ -83,16 +82,15 @@              android:layout_toRightOf="@+id/result_signature_image"              android:textColor="@color/white" /> -        <com.beardedhen.androidbootstrap.BootstrapButton +        <Button              android:id="@+id/lookup_key"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:text="@string/btn_lookup_key" -            bootstrapbutton:bb_icon_left="fa-download" -            bootstrapbutton:bb_type="info" -            bootstrapbutton:bb_size="small" +            android:drawableRight="@drawable/ic_action_download"              android:layout_alignParentRight="true" -            android:layout_centerVertical="true" /> +            android:layout_centerVertical="true" +            android:background="@drawable/button_edgy"/>      </RelativeLayout> diff --git a/OpenKeychain/src/main/res/layout/drawer_list_item.xml b/OpenKeychain/src/main/res/layout/drawer_list_item.xml index 72f4fec50..4719483da 100644 --- a/OpenKeychain/src/main/res/layout/drawer_list_item.xml +++ b/OpenKeychain/src/main/res/layout/drawer_list_item.xml @@ -3,17 +3,15 @@      android:layout_width="match_parent"      android:layout_height="wrap_content"> -    <com.beardedhen.androidbootstrap.FontAwesomeText +    <ImageView          android:id="@+id/drawer_item_icon" +        android:gravity="center_vertical"          android:layout_width="30dp"          android:layout_height="wrap_content" -        android:gravity="center_vertical" -        android:textSize="24sp"          android:layout_marginLeft="8dp" -        fontawesometext:fa_icon="fa-github" -        android:layout_centerVertical="true" +        android:layout_alignParentStart="true"          android:layout_alignParentLeft="true" -        android:layout_alignParentStart="true" /> +        android:layout_centerVertical="true" />      <TextView          android:id="@+id/drawer_item_text" @@ -28,6 +26,6 @@          android:textAppearance="@android:style/TextAppearance.Medium"          android:textColor="#111"          android:layout_alignParentTop="true" -        android:layout_toRightOf="@+id/drawer_item_icon" /> +        android:layout_toRightOf="@id/drawer_item_icon"/>  </RelativeLayout> diff --git a/OpenKeychain/src/main/res/layout/edit_key_activity.xml b/OpenKeychain/src/main/res/layout/edit_key_activity.xml index 1ce5c096f..b6c5a1c9a 100644 --- a/OpenKeychain/src/main/res/layout/edit_key_activity.xml +++ b/OpenKeychain/src/main/res/layout/edit_key_activity.xml @@ -26,14 +26,14 @@              android:layout_height="wrap_content"              android:text="@string/label_no_passphrase" /> -        <com.beardedhen.androidbootstrap.BootstrapButton +        <Button              android:id="@+id/edit_key_btn_change_passphrase"              android:layout_width="match_parent"              android:layout_height="60dp"              android:padding="4dp"              android:text="@string/btn_set_passphrase" -            bootstrapbutton:bb_icon_left="fa-pencil" -            bootstrapbutton:bb_type="default" /> +            android:drawableLeft="@drawable/ic_action_edit" +            android:background="@drawable/button_edgy" />          <LinearLayout              android:id="@+id/edit_key_container" diff --git a/OpenKeychain/src/main/res/layout/edit_key_fragment.xml b/OpenKeychain/src/main/res/layout/edit_key_fragment.xml index f652269e5..7f94cb3cd 100644 --- a/OpenKeychain/src/main/res/layout/edit_key_fragment.xml +++ b/OpenKeychain/src/main/res/layout/edit_key_fragment.xml @@ -45,6 +45,11 @@              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" /> +          <org.sufficientlysecure.keychain.ui.widget.FixedListView              android:id="@+id/edit_key_user_ids_added"              android:layout_width="match_parent" @@ -82,6 +87,11 @@              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" /> +          <org.sufficientlysecure.keychain.ui.widget.FixedListView              android:id="@+id/edit_key_keys_added"              android:layout_width="match_parent" diff --git a/OpenKeychain/src/main/res/layout/edit_key_key_item.xml b/OpenKeychain/src/main/res/layout/edit_key_key_item.xml index 090115d62..81fb643ab 100644 --- a/OpenKeychain/src/main/res/layout/edit_key_key_item.xml +++ b/OpenKeychain/src/main/res/layout/edit_key_key_item.xml @@ -1,6 +1,5 @@  <?xml version="1.0" encoding="utf-8"?>  <org.sufficientlysecure.keychain.ui.widget.KeyEditor xmlns:android="http://schemas.android.com/apk/res/android" -    xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"      android:layout_width="match_parent"      android:layout_height="wrap_content"      android:orientation="vertical" > @@ -80,13 +79,12 @@                      android:paddingRight="10dip"                      android:text="@string/label_expiry" /> -                <com.beardedhen.androidbootstrap.BootstrapButton +                <Button                      android:id="@+id/expiry"                      android:layout_width="match_parent"                      android:layout_height="40dp"                      android:text="@string/none" -                    bootstrapbutton:bb_size="small" -                    bootstrapbutton:bb_type="default" /> +                    android:background="@drawable/button_edgy" />              </TableRow>              <TableRow @@ -155,15 +153,13 @@              </TableRow>          </TableLayout> -        <com.beardedhen.androidbootstrap.BootstrapButton +        <ImageButton              android:id="@+id/delete"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:layout_margin="10dp" -            bootstrapbutton:bb_icon_left="fa-minus" -            bootstrapbutton:bb_roundedCorners="true" -            bootstrapbutton:bb_size="small" -            bootstrapbutton:bb_type="danger" /> +            android:src="@drawable/minus" +            android:background="@drawable/button_rounded_red"/>      </LinearLayout>      <View diff --git a/OpenKeychain/src/main/res/layout/edit_key_section.xml b/OpenKeychain/src/main/res/layout/edit_key_section.xml index 9f10ff8c1..6cfe18bd6 100644 --- a/OpenKeychain/src/main/res/layout/edit_key_section.xml +++ b/OpenKeychain/src/main/res/layout/edit_key_section.xml @@ -1,6 +1,5 @@  <?xml version="1.0" encoding="utf-8"?>  <org.sufficientlysecure.keychain.ui.widget.SectionView xmlns:android="http://schemas.android.com/apk/res/android" -    xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"      android:layout_width="match_parent"      android:layout_height="wrap_content"      android:orientation="vertical" > @@ -23,15 +22,13 @@              android:singleLine="true"              android:text="Section Name" /> -        <com.beardedhen.androidbootstrap.BootstrapButton +        <ImageButton              android:id="@+id/plusbutton"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:layout_margin="10dp" -            bootstrapbutton:bb_icon_left="fa-plus" -            bootstrapbutton:bb_roundedCorners="true" -            bootstrapbutton:bb_size="small" -            bootstrapbutton:bb_type="success" /> +            android:src="@drawable/plus" +            android:background="@drawable/button_rounded_green"/>      </LinearLayout>      <LinearLayout diff --git a/OpenKeychain/src/main/res/layout/edit_key_user_id_item.xml b/OpenKeychain/src/main/res/layout/edit_key_user_id_item.xml index a8d1dc674..3454d3668 100644 --- a/OpenKeychain/src/main/res/layout/edit_key_user_id_item.xml +++ b/OpenKeychain/src/main/res/layout/edit_key_user_id_item.xml @@ -1,6 +1,5 @@  <?xml version="1.0" encoding="utf-8"?>  <org.sufficientlysecure.keychain.ui.widget.UserIdEditor xmlns:android="http://schemas.android.com/apk/res/android" -    xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"      android:layout_width="match_parent"      android:layout_height="wrap_content"      android:orientation="vertical" > @@ -76,18 +75,16 @@              </TableRow>          </TableLayout> -        <com.beardedhen.androidbootstrap.BootstrapButton +        <ImageButton              android:id="@+id/delete"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:layout_gravity="center_vertical" -            android:layout_margin="10dp" +            android:layout_margin="10dip"              android:layout_marginLeft="4dip"              android:layout_marginRight="6dip" -            bootstrapbutton:bb_icon_left="fa-minus" -            bootstrapbutton:bb_roundedCorners="true" -            bootstrapbutton:bb_size="small" -            bootstrapbutton:bb_type="danger" /> +            android:src="@drawable/minus" +            android:background="@drawable/button_rounded_red" />      </LinearLayout>      <View diff --git a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml index fa1b03889..cde92b477 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml @@ -1,7 +1,6 @@  <?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" -    xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"      android:layout_width="match_parent"      android:layout_height="wrap_content"      android:orientation="vertical" @@ -65,15 +64,14 @@              android:text="@string/label_select_public_keys"              android:textAppearance="?android:attr/textAppearanceMedium" /> -        <com.beardedhen.androidbootstrap.BootstrapButton +        <Button              android:id="@+id/btn_selectEncryptKeys"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:layout_gravity="center_vertical"              android:layout_margin="4dp"              android:text="@string/select_keys_button_default" -            bootstrapbutton:bb_icon_left="fa-user" -            bootstrapbutton:bb_size="default" -            bootstrapbutton:bb_type="default" /> +            android:background="@drawable/button_edgy" +            android:drawableLeft="@drawable/ic_action_person" />      </LinearLayout>  </LinearLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/encrypt_file_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_file_fragment.xml index c8aaf77b8..4142b3de6 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_file_fragment.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_file_fragment.xml @@ -31,15 +31,14 @@                  android:minLines="2"                  android:scrollbars="vertical" /> -            <com.beardedhen.androidbootstrap.BootstrapButton +            <ImageButton                  android:id="@+id/btn_browse"                  android:layout_width="wrap_content"                  android:layout_height="wrap_content"                  android:layout_margin="4dp" -                bootstrapbutton:bb_icon_left="fa-folder-open" -                bootstrapbutton:bb_roundedCorners="true" -                bootstrapbutton:bb_size="default" -                bootstrapbutton:bb_type="default" /> +                android:layout_gravity="center_vertical" +                android:src="@drawable/ic_action_collection" +                android:background="@drawable/button_rounded"/>          </LinearLayout>          <org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout diff --git a/OpenKeychain/src/main/res/layout/file_dialog.xml b/OpenKeychain/src/main/res/layout/file_dialog.xml index 83d697001..dcf711679 100644 --- a/OpenKeychain/src/main/res/layout/file_dialog.xml +++ b/OpenKeychain/src/main/res/layout/file_dialog.xml @@ -1,6 +1,5 @@  <?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" -    xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"      android:layout_width="fill_parent"      android:layout_height="wrap_content"      android:orientation="vertical" @@ -31,17 +30,15 @@              android:minLines="2"              android:scrollbars="vertical" /> -        <com.beardedhen.androidbootstrap.BootstrapButton +        <ImageButton              android:id="@+id/btn_browse"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:layout_gravity="center_vertical"              android:layout_margin="4dp"              android:contentDescription="@string/filemanager_title_open" -            bootstrapbutton:bb_icon_left="fa-folder-open" -            bootstrapbutton:bb_roundedCorners="true" -            bootstrapbutton:bb_size="default" -            bootstrapbutton:bb_type="default" /> +            android:background="@drawable/button_rounded" +            android:src="@drawable/ic_action_collection"/>      </LinearLayout>      <CheckBox diff --git a/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml b/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml index 2b863d52b..3d2fb688b 100644 --- a/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml +++ b/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml @@ -1,7 +1,6 @@  <?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" -              xmlns:fontawesometext="http://schemas.android.com/apk/res-auto"                android:orientation="vertical"                android:layout_width="match_parent"                android:layout_height="match_parent"> @@ -12,23 +11,21 @@              android:orientation="horizontal"              android:clickable="true"> -        <com.beardedhen.androidbootstrap.FontAwesomeText +        <ImageButton                  android:id="@+id/foldableIcon"                  android:layout_width="wrap_content"                  android:layout_height="wrap_content" +                android:layout_gravity="center_vertical"                  android:layout_marginRight="10dp" -                android:textSize="12sp" -                android:paddingTop="@dimen/padding_medium" -                android:paddingBottom="@dimen/padding_medium" -                fontawesometext:fa_icon="fa-chevron-right"/> +                android:src="@drawable/ic_action_expand" +                android:background="@drawable/button_no_style"/>          <TextView                  android:id="@+id/foldableText"                  android:layout_width="wrap_content"                  android:layout_height="wrap_content"                  android:text="@string/none" -                android:paddingTop="@dimen/padding_medium" -                android:paddingBottom="@dimen/padding_medium" +                android:layout_gravity="center_vertical"                  android:textColor="@color/emphasis"/>      </LinearLayout> diff --git a/OpenKeychain/src/main/res/layout/import_keys_activity.xml b/OpenKeychain/src/main/res/layout/import_keys_activity.xml index b076debfe..81aa6d792 100644 --- a/OpenKeychain/src/main/res/layout/import_keys_activity.xml +++ b/OpenKeychain/src/main/res/layout/import_keys_activity.xml @@ -4,11 +4,7 @@      android:layout_height="match_parent"      android:orientation="vertical"> -    <LinearLayout -        android:id="@+id/card_container" -        android:layout_width="match_parent" -        android:layout_height="wrap_content" -        android:orientation="vertical" /> +    <include layout="@layout/notify_area"/>      <org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout          android:id="@+id/import_sliding_tab_layout" diff --git a/OpenKeychain/src/main/res/layout/key_list_fragment.xml b/OpenKeychain/src/main/res/layout/key_list_fragment.xml index c02854668..32b77baac 100644 --- a/OpenKeychain/src/main/res/layout/key_list_fragment.xml +++ b/OpenKeychain/src/main/res/layout/key_list_fragment.xml @@ -1,6 +1,5 @@  <?xml version="1.0" encoding="utf-8"?>  <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" -    xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:orientation="vertical"> @@ -49,14 +48,15 @@              android:text="@string/key_list_empty_text2"              android:textAppearance="?android:attr/textAppearanceSmall" /> -        <com.beardedhen.androidbootstrap.BootstrapButton +        <Button              android:id="@+id/key_list_empty_button_create"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:layout_margin="4dp" +            android:textSize="14sp"              android:text="@string/key_list_empty_button_create" -            bootstrapbutton:bb_icon_left="fa-plus" -            bootstrapbutton:bb_type="default" /> +            android:drawableLeft="@drawable/ic_action_new_account" +            android:background="@drawable/button_edgy"/>          <TextView              android:layout_width="wrap_content" @@ -66,14 +66,15 @@              android:text="@string/key_list_empty_text3"              android:textAppearance="?android:attr/textAppearanceSmall" /> -        <com.beardedhen.androidbootstrap.BootstrapButton +        <Button              android:id="@+id/key_list_empty_button_import"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:layout_margin="4dp" +            android:textSize="14sp"              android:text="@string/key_list_empty_button_import" -            bootstrapbutton:bb_icon_left="fa-download" -            bootstrapbutton:bb_type="default" /> +            android:drawableLeft="@drawable/ic_action_download" +            android:background="@drawable/button_edgy" />      </LinearLayout>  </FrameLayout> diff --git a/OpenKeychain/src/main/res/layout/key_server_editor.xml b/OpenKeychain/src/main/res/layout/key_server_editor.xml index 950978a0e..b07fdc50c 100644 --- a/OpenKeychain/src/main/res/layout/key_server_editor.xml +++ b/OpenKeychain/src/main/res/layout/key_server_editor.xml @@ -1,6 +1,5 @@  <?xml version="1.0" encoding="utf-8"?>  <org.sufficientlysecure.keychain.ui.widget.KeyServerEditor xmlns:android="http://schemas.android.com/apk/res/android" -    xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"      android:layout_width="match_parent"      android:layout_height="wrap_content"      android:orientation="vertical" > @@ -18,17 +17,15 @@              android:layout_weight="1"              android:inputType="textUri" /> -        <com.beardedhen.androidbootstrap.BootstrapButton +        <ImageButton              android:id="@+id/delete"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:layout_gravity="center_vertical"              android:layout_margin="10dp"              android:layout_marginRight="3dip" -            bootstrapbutton:bb_icon_left="fa-minus" -            bootstrapbutton:bb_roundedCorners="true" -            bootstrapbutton:bb_size="small" -            bootstrapbutton:bb_type="danger" /> +            android:background="@drawable/button_rounded_red" +            android:src="@drawable/minus" />      </LinearLayout>      <View diff --git a/OpenKeychain/src/main/res/layout/key_server_preference.xml b/OpenKeychain/src/main/res/layout/key_server_preference.xml index b8897a7b3..baf7111af 100644 --- a/OpenKeychain/src/main/res/layout/key_server_preference.xml +++ b/OpenKeychain/src/main/res/layout/key_server_preference.xml @@ -1,6 +1,5 @@  <?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" -    xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"      android:layout_width="fill_parent"      android:layout_height="fill_parent"      android:orientation="vertical" > @@ -42,7 +41,7 @@                  android:textAppearance="?android:attr/textAppearanceSmall" />          </RelativeLayout> -        <com.beardedhen.androidbootstrap.BootstrapButton +        <ImageButton              android:id="@+id/add"              android:layout_width="wrap_content"              android:layout_height="wrap_content" @@ -50,10 +49,8 @@              android:layout_margin="10dp"              android:layout_marginLeft="4dip"              android:layout_marginRight="6dip" -            bootstrapbutton:bb_icon_left="fa-plus" -            bootstrapbutton:bb_roundedCorners="true" -            bootstrapbutton:bb_size="small" -            bootstrapbutton:bb_type="success" /> +            android:src="@drawable/plus" +            android:background="@drawable/button_rounded_green"/>      </LinearLayout>      <View diff --git a/OpenKeychain/src/main/res/layout/notification_area.xml b/OpenKeychain/src/main/res/layout/notify_area.xml index d1ba265a5..d1ba265a5 100644 --- a/OpenKeychain/src/main/res/layout/notification_area.xml +++ b/OpenKeychain/src/main/res/layout/notify_area.xml diff --git a/OpenKeychain/src/main/res/layout/select_secret_key_layout_fragment.xml b/OpenKeychain/src/main/res/layout/select_secret_key_layout_fragment.xml index cc2ab0cac..63eeb8eaf 100644 --- a/OpenKeychain/src/main/res/layout/select_secret_key_layout_fragment.xml +++ b/OpenKeychain/src/main/res/layout/select_secret_key_layout_fragment.xml @@ -1,11 +1,10 @@  <?xml version="1.0" encoding="UTF-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" -    xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"      android:layout_width="match_parent"      android:layout_height="wrap_content"      android:orientation="horizontal"> -    <com.beardedhen.androidbootstrap.BootstrapButton +    <Button          android:id="@+id/select_secret_key_select_key_button"          android:layout_width="wrap_content"          android:layout_height="wrap_content" @@ -14,9 +13,9 @@          android:layout_marginRight="4dp"          android:layout_marginTop="4dp"          android:text="@string/api_settings_select_key" -        bootstrapbutton:bb_icon_left="fa-key" -        bootstrapbutton:bb_size="default" -        bootstrapbutton:bb_type="default" /> +        android:drawableLeft="@drawable/ic_action_accounts" +        android:background="@drawable/button_edgy" +        android:textSize="14dp"/>      <LinearLayout          android:layout_width="match_parent" diff --git a/OpenKeychain/src/main/res/layout/view_key_activity.xml b/OpenKeychain/src/main/res/layout/view_key_activity.xml index 5aa1cd167..481b1ddf5 100644 --- a/OpenKeychain/src/main/res/layout/view_key_activity.xml +++ b/OpenKeychain/src/main/res/layout/view_key_activity.xml @@ -4,6 +4,12 @@      android:layout_height="match_parent"      android:orientation="vertical"> +    <LinearLayout +        android:id="@+id/card_container" +        android:layout_width="match_parent" +        android:layout_height="wrap_content" +        android:orientation="vertical" /> +      <TextView          android:layout_width="match_parent"          android:layout_height="wrap_content" diff --git a/OpenKeychain/src/main/res/layout/wizard_activity.xml b/OpenKeychain/src/main/res/layout/wizard_activity.xml new file mode 100644 index 000000000..299d07a76 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/wizard_activity.xml @@ -0,0 +1,98 @@ +<?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"> + +    <LinearLayout +        android:id="@+id/wizard_buttons" +        android:layout_width="match_parent" +        android:layout_height="wrap_content" +        android:layout_alignParentBottom="true" +        android:orientation="horizontal"> + +        <Button +            android:id="@+id/wizard_back" +            android:layout_width="match_parent" +            android:layout_height="wrap_content" +            android:layout_weight="1" +            android:onClick="backOnClick" +            android:text="cancel" +            style="@style/SelectableItem" /> + +        <View +            android:layout_width="1dip" +            android:layout_height="match_parent" +            android:layout_marginBottom="4dip" +            android:layout_marginTop="4dip" +            android:background="?android:attr/listDivider" /> + +        <Button +            android:id="@+id/wizard_next" +            android:layout_width="match_parent" +            android:layout_height="wrap_content" +            android:layout_weight="1" +            android:onClick="nextOnClick" +            android:text="next" +            style="@style/SelectableItem" /> +    </LinearLayout> + +    <View +        android:id="@+id/wizard_progress_line" +        android:layout_width="match_parent" +        android:layout_height="1dip" +        android:layout_above="@+id/wizard_buttons" +        android:layout_marginLeft="4dip" +        android:layout_marginRight="4dip" +        android:background="?android:attr/listDivider" +        android:visibility="gone" /> + +    <LinearLayout +        android:id="@+id/wizard_progress" +        android:layout_width="match_parent" +        android:layout_height="wrap_content" +        android:layout_above="@+id/wizard_progress_line" +        android:visibility="gone"> + +        <ProgressBar +            android:id="@+id/wizard_progress_progressbar" +            android:layout_width="wrap_content" +            android:layout_height="wrap_content" /> + +        <ImageView +            android:id="@+id/wizard_progress_image" +            android:layout_width="wrap_content" +            android:layout_height="wrap_content" +            android:src="@drawable/icon_light_refresh" /> + +        <TextView +            android:id="@+id/wizard_progress_text" +            android:layout_width="wrap_content" +            android:layout_height="wrap_content" +            android:layout_gravity="center_vertical" +            android:text="asd" +            android:textAppearance="?android:attr/textAppearanceMedium" /> +    </LinearLayout> + +    <View +        android:id="@+id/wizard_line2" +        android:layout_width="match_parent" +        android:layout_height="1dip" +        android:layout_above="@+id/wizard_progress" +        android:layout_marginLeft="4dip" +        android:layout_marginRight="4dip" +        android:background="?android:attr/listDivider" /> + +    <ScrollView +        android:layout_width="match_parent" +        android:layout_height="match_parent" +        android:layout_above="@+id/wizard_line2"> + +        <LinearLayout +            android:id="@+id/wizard_container" +            android:layout_width="match_parent" +            android:layout_height="wrap_content" +            android:orientation="vertical" +            android:padding="16dp" /> +    </ScrollView> + +</RelativeLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/wizard_create_key_fragment.xml b/OpenKeychain/src/main/res/layout/wizard_create_key_fragment.xml new file mode 100644 index 000000000..258ea7223 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/wizard_create_key_fragment.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +    android:layout_width="match_parent" +    android:layout_height="wrap_content" +    android:orientation="vertical"> + +    <TextView +        android:layout_width="match_parent" +        android:layout_height="wrap_content" +        android:paddingBottom="4dp" +        android:text="Enter Full Name, Email and Passphrase!" +        android:textAppearance="?android:attr/textAppearanceMedium" /> + +    <AutoCompleteTextView +        android:layout_width="match_parent" +        android:layout_height="wrap_content" +        android:inputType="textPersonName" +        android:hint="Name" +        android:ems="10" +        android:id="@+id/name" /> + +    <AutoCompleteTextView +        android:id="@+id/email" +        android:layout_width="match_parent" +        android:layout_height="wrap_content" +        android:hint="bla@example.com" +        android:layout_weight="1" +        android:ems="10" +        android:inputType="textEmailAddress" /> + +    <EditText +        android:layout_width="match_parent" +        android:layout_height="wrap_content" +        android:inputType="textPassword" +        android:hint="passphrase" +        android:ems="10" +        android:id="@+id/passphrase" +        android:layout_gravity="center_horizontal" /> + + +</LinearLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/wizard_k9_fragment.xml b/OpenKeychain/src/main/res/layout/wizard_k9_fragment.xml new file mode 100644 index 000000000..342adc37e --- /dev/null +++ b/OpenKeychain/src/main/res/layout/wizard_k9_fragment.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +    android:layout_width="match_parent" +    android:layout_height="wrap_content" +    android:orientation="vertical" > + +    <org.sufficientlysecure.htmltextview.HtmlTextView +        android:id="@+id/wizard_k9_text" +        android:layout_width="match_parent" +        android:layout_height="wrap_content" +        android:paddingBottom="4dp" +        android:text="Text..." +        android:textAppearance="?android:attr/textAppearanceMedium" /> + +    <RadioGroup +        android:id="@+id/wizard_k9_radio_group" +        android:layout_width="match_parent" +        android:layout_height="wrap_content"> + +        <RadioButton +            android:layout_width="match_parent" +            android:layout_height="?android:attr/listPreferredItemHeight" +            android:checked="true" +            android:textAppearance="?android:attr/textAppearanceMedium" +            style="@style/SelectableItem" +            android:text="install K9" +            android:id="@+id/wizard_k9_install" /> + +        <View +            android:layout_width="match_parent" +            android:layout_height="1dip" +            android:background="?android:attr/listDivider" /> + +        <RadioButton +            android:layout_width="match_parent" +            android:layout_height="?android:attr/listPreferredItemHeight" +            android:textAppearance="?android:attr/textAppearanceMedium" +            style="@style/SelectableItem" +            android:text="skip install" +            android:id="@+id/wizard_k9_skip" /> +    </RadioGroup> + +</LinearLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/wizard_start_fragment.xml b/OpenKeychain/src/main/res/layout/wizard_start_fragment.xml new file mode 100644 index 000000000..9e1403f74 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/wizard_start_fragment.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +    android:layout_width="match_parent" +    android:layout_height="wrap_content" +    android:orientation="vertical"> + +    <TextView +        android:layout_width="match_parent" +        android:layout_height="wrap_content" +        android:paddingBottom="4dp" +        android:text="Welcome to OpenKeychain" +        android:textAppearance="?android:attr/textAppearanceMedium" /> + +    <TextView +        style="@style/SectionHeader" +        android:layout_width="wrap_content" +        android:layout_height="0dp" +        android:layout_marginTop="14dp" +        android:text="What you wanna do today?" +        android:layout_weight="1" /> + +    <RadioGroup +        android:id="@+id/wizard_start_radio_group" +        android:layout_width="match_parent" +        android:layout_height="wrap_content"> + +        <RadioButton +            android:layout_width="match_parent" +            android:layout_height="?android:attr/listPreferredItemHeight" +            android:checked="true" +            android:textAppearance="?android:attr/textAppearanceMedium" +            style="@style/SelectableItem" +            android:text="new key" +            android:id="@+id/wizard_start_new_key" /> + +        <View +            android:layout_width="match_parent" +            android:layout_height="1dip" +            android:background="?android:attr/listDivider" /> + +        <RadioButton +            android:layout_width="match_parent" +            android:layout_height="?android:attr/listPreferredItemHeight" +            android:textAppearance="?android:attr/textAppearanceMedium" +            style="@style/SelectableItem" +            android:text="import existing key" +            android:id="@+id/wizard_start_import" /> + +        <View +            android:layout_width="match_parent" +            android:layout_height="1dip" +            android:background="?android:attr/listDivider" /> + +        <RadioButton +            android:layout_width="match_parent" +            android:layout_height="?android:attr/listPreferredItemHeight" +            android:textAppearance="?android:attr/textAppearanceMedium" +            style="@style/SelectableItem" +            android:text="skip wizard" +            android:id="@+id/wizard_start_skip" /> +    </RadioGroup> + +</LinearLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/raw/help_faq.html b/OpenKeychain/src/main/res/raw/help_faq.html index e6757d0da..6f8763f36 100644 --- a/OpenKeychain/src/main/res/raw/help_faq.html +++ b/OpenKeychain/src/main/res/raw/help_faq.html @@ -12,5 +12,13 @@ And don't add newlines before or after p tags because of transifex -->  <h2>A wrong primary user id is shown when searching on a Keyserver</h2>  <p>Unfortunately, this is a bug in the SKS Keyserver software. Its machine-readable output returns the user ids in an arbitrary order. Read the <a href="https://bitbucket.org/skskeyserver/sks-keyserver/issue/28/primary-uid-in-machine-readable-index">related bug report</a> for more information.</p> +<h2>How do I activate OpenKeychain in K9-Mail?</h2> +<p>To use OpenKeychain with K9-Mail, you want to follow these steps:</p> +<ol> +    <li>Open K9-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> +<p>Thats it.</p>  </body>  </html> diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 5600aa06e..25cdfb541 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -9,8 +9,9 @@      <string name="title_authentication">Passphrase</string>      <string name="title_create_key">Create Key</string>      <string name="title_edit_key">Edit Key</string> +    <string name="title_wizard">Welcome to OpenKeychain</string>      <string name="title_preferences">Preferences</string> -    <string name="title_api_registered_apps">Registered Applications</string> +    <string name="title_api_registered_apps">Apps</string>      <string name="title_key_server_preference">Keyserver Preference</string>      <string name="title_change_passphrase">Change Passphrase</string>      <string name="title_set_passphrase">Set Passphrase</string> @@ -388,19 +389,19 @@      <!-- Import result toast -->      <plurals name="import_keys_added_and_updated_1"> -        <item quantity="one">Successfully added %1$d key</item> -        <item quantity="other">Successfully added %1$d keys</item> +        <item quantity="one">Successfully imported key</item> +        <item quantity="other">Successfully imported %1$d keys</item>      </plurals>      <plurals name="import_keys_added_and_updated_2"> -        <item quantity="one"> and updated %1$d key%2$s.</item> +        <item quantity="one"> and updated key%2$s.</item>          <item quantity="other"> and updated %1$d keys%2$s.</item>      </plurals>      <plurals name="import_keys_added"> -        <item quantity="one">Successfully added %1$d key%2$s.</item> -        <item quantity="other">Successfully added %1$d keys%2$s.</item> +        <item quantity="one">Successfully imported key%2$s.</item> +        <item quantity="other">Successfully imported %1$d keys%2$s.</item>      </plurals>      <plurals name="import_keys_updated"> -        <item quantity="one">Successfully updated %1$d key%2$s.</item> +        <item quantity="one">Successfully updated key%2$s.</item>          <item quantity="other">Successfully updated %1$d keys%2$s.</item>      </plurals>      <string name="import_view_log">View Log</string> @@ -477,7 +478,7 @@      <string name="nav_encrypt">Sign and Encrypt</string>      <string name="nav_decrypt">Decrypt and Verify</string>      <string name="nav_import">Import Keys</string> -    <string name="nav_apps">Registered Apps</string> +    <string name="nav_apps">Apps</string>      <string name="drawer_open">Open navigation drawer</string>      <string name="drawer_close">Close navigation drawer</string>      <string name="edit">Edit</string> @@ -542,8 +543,15 @@      <string name="msg_ip_uid_cert_bad">Encountered bad certificate!</string>      <string name="msg_ip_uid_cert_error">Error processing certificate!</string>      <string name="msg_ip_uid_cert_good">User id is certified by %1$s (%2$s)</string> -    <string name="msg_ip_uid_certs_unknown">Ignoring %s certificates from unknown pubkeys</string> -    <string name="msg_ip_uid_classifying">Classifying user ids, using %s trusted signatures</string> +    <plurals name="msg_ip_uid_certs_unknown"> +        <item quantity="one">Ignoring one certificate issued by an unknown public key</item> +        <item quantity="other">Ignoring %s certificates issued by unknown public keys</item> +    </plurals> +    <plurals name="msg_ip_uid_classifying"> +        <item quantity="zero">Classifying user ids (no trusted keys available)</item> +        <item quantity="one">Classifying user ids (using one trusted key)</item> +        <item quantity="other">Classifying user ids (using %s trusted keys)</item> +    </plurals>      <string name="msg_ip_uid_reorder">Re-ordering user ids</string>      <string name="msg_ip_uid_processing">Processing user id %s</string>      <string name="msg_ip_uid_revoked">User id is revoked</string> @@ -588,9 +596,15 @@      <string name="msg_kc_sub_revoke_bad">Removing bad subkey revocation certificate</string>      <string name="msg_kc_sub_revoke_dup">Removing redundant subkey revocation certificate</string>      <string name="msg_kc_success">Keyring canonicalization successful, no changes</string> -    <string name="msg_kc_success_bad">Keyring canonicalization successful, removed %s erroneous certificates</string> +    <plurals name="msg_kc_success_bad"> +        <item quantity="one">Keyring canonicalization successful, removed one erroneous certificate</item> +        <item quantity="other">Keyring canonicalization successful, removed %d erroneous certificates</item> +    </plurals>      <string name="msg_kc_success_bad_and_red">Keyring canonicalization successful, removed %1$s erroneous and %2$s redundant certificates</string> -    <string name="msg_kc_success_redundant">Keyring canonicalization successful, removed %s redundant certificates</string> +    <plurals name="msg_kc_success_redundant"> +        <item quantity="one">Keyring canonicalization successful, removed one redundant certificate</item> +        <item quantity="other">Keyring canonicalization successful, removed %d redundant certificates</item> +    </plurals>      <string name="msg_kc_uid_bad_err">Removing bad self certificate for user id %s</string>      <string name="msg_kc_uid_bad_local">Removing user id certificate with "local" flag</string>      <string name="msg_kc_uid_bad_time">Removing user id with future timestamp</string> diff --git a/OpenKeychain/src/test/java/tests/ProviderHelperKeyringTest.java b/OpenKeychain/src/test/java/tests/ProviderHelperKeyringTest.java index 265e01170..3d48c2f97 100644 --- a/OpenKeychain/src/test/java/tests/ProviderHelperKeyringTest.java +++ b/OpenKeychain/src/test/java/tests/ProviderHelperKeyringTest.java @@ -1,5 +1,10 @@  package tests; +import java.util.Collections; +import java.util.Arrays; +import java.util.Collection; +import java.util.ArrayList; +  import org.junit.Assert;  import org.junit.Test;  import org.junit.runner.RunWith; @@ -14,7 +19,68 @@ public class ProviderHelperKeyringTest {      @Test      public void testSavePublicKeyring() throws Exception { -        Assert.assertTrue(new KeyringTestingHelper(Robolectric.application).addKeyring()); +        Assert.assertTrue(new KeyringTestingHelper(Robolectric.application).addKeyring(Collections.singleton( +                "/public-key-for-sample.blob" +        ))); +    } + +    @Test +    public void testSavePublicKeyringRsa() throws Exception { +        Assert.assertTrue(new KeyringTestingHelper(Robolectric.application).addKeyring(prependResourcePath(Arrays.asList( +                        "000001-006.public_key", +                        "000002-013.user_id", +                        "000003-002.sig", +                        "000004-012.ring_trust", +                        "000005-002.sig", +                        "000006-012.ring_trust", +                        "000007-002.sig", +                        "000008-012.ring_trust", +                        "000009-002.sig", +                        "000010-012.ring_trust", +                        "000011-002.sig", +                        "000012-012.ring_trust", +                        "000013-014.public_subkey", +                        "000014-002.sig", +                        "000015-012.ring_trust" +                ))));      } +    @Test +    public void testSavePublicKeyringDsa() throws Exception { +        Assert.assertTrue(new KeyringTestingHelper(Robolectric.application).addKeyring(prependResourcePath(Arrays.asList( +                        "000016-006.public_key", +                        "000017-002.sig", +                        "000018-012.ring_trust", +                        "000019-013.user_id", +                        "000020-002.sig", +                        "000021-012.ring_trust", +                        "000022-002.sig", +                        "000023-012.ring_trust", +                        "000024-014.public_subkey", +                        "000025-002.sig", +                        "000026-012.ring_trust" +                )))); +    } + +    @Test +    public void testSavePublicKeyringDsa2() throws Exception { +        Assert.assertTrue(new KeyringTestingHelper(Robolectric.application).addKeyring(prependResourcePath(Arrays.asList( +                        "000027-006.public_key", +                        "000028-002.sig", +                        "000029-012.ring_trust", +                        "000030-013.user_id", +                        "000031-002.sig", +                        "000032-012.ring_trust", +                        "000033-002.sig", +                        "000034-012.ring_trust" +                )))); +    } + +    private static Collection<String> prependResourcePath(Collection<String> files) { +        Collection<String> prependedFiles = new ArrayList<String>(); +        for (String file: files) { +            prependedFiles.add("/extern/OpenPGP-Haskell/tests/data/" + file); +        } +        return prependedFiles; +    }  } diff --git a/OpenKeychain/src/test/resources/extern/OpenPGP-Haskell b/OpenKeychain/src/test/resources/extern/OpenPGP-Haskell new file mode 160000 +Subproject eba7e4fdce3de6622b4ec3862b405b0acd01637 diff --git a/build.gradle b/build.gradle index fa6c7278e..ceb963cd8 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript {      dependencies {          // NOTE: Always use fixed version codes not dynamic ones, e.g. 0.7.3 instead of 0.7.+, see README for more information -        classpath 'com.android.tools.build:gradle:0.11.1' +        classpath 'com.android.tools.build:gradle:0.12.0'          classpath 'org.robolectric:robolectric-gradle-plugin:0.11.0'      }  } diff --git a/extern/AndroidBootstrap b/extern/AndroidBootstrap deleted file mode 160000 -Subproject 02f02391e3eee9331e07d7690d3b533a8b0f69e diff --git a/extern/KeybaseLib b/extern/KeybaseLib -Subproject 838800d2cb57fdd4caca1bdbd919e9d96dae13e +Subproject e214906a52233bb6f230bc6759ac7be803d24bf diff --git a/extern/openkeychain-api-lib b/extern/openkeychain-api-lib -Subproject 175a3cb772c88c9b50985abc98f81c9ea69c365 +Subproject 48941ca6ec58c4583cdcf9d647ad5174925e2f2 diff --git a/extern/openpgp-api-lib b/extern/openpgp-api-lib -Subproject 289d48b633b7493f2a760583c88670b9fc4ef96 +Subproject aa9ecf871ce4db462034662675b258f9839d3f6 diff --git a/settings.gradle b/settings.gradle index 4776ae5ee..d8802320c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,7 +3,6 @@ include ':extern:openpgp-api-lib'  include ':extern:openkeychain-api-lib'  include ':extern:html-textview'  include ':extern:StickyListHeaders:library' -include ':extern:AndroidBootstrap:AndroidBootstrap'  include ':extern:zxing-qr-code'  include ':extern:zxing-android-integration'  include ':extern:spongycastle:core' | 
