diff options
| author | Dominik Schürmann <dominik@dominikschuermann.de> | 2015-03-27 00:40:37 +0100 | 
|---|---|---|
| committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2015-03-27 00:40:37 +0100 | 
| commit | 13f4cc4ad32eb412e2ecdb649dcdd0788d30d5b2 (patch) | |
| tree | d6ebffd33b8ace849b04ab6470cd1c444888345c /OpenKeychain | |
| parent | adbe5ab63ff76a112d1a5fbd3ef9700ec59484e0 (diff) | |
| download | open-keychain-13f4cc4ad32eb412e2ecdb649dcdd0788d30d5b2.tar.gz open-keychain-13f4cc4ad32eb412e2ecdb649dcdd0788d30d5b2.tar.bz2 open-keychain-13f4cc4ad32eb412e2ecdb649dcdd0788d30d5b2.zip | |
Refactoring of EncryptTextActivity
Diffstat (limited to 'OpenKeychain')
9 files changed, 418 insertions, 404 deletions
| diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 949a595d3..a1edf808c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -37,7 +37,6 @@ import org.sufficientlysecure.keychain.service.ServiceProgressHandler;  import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.util.Passphrase; -  public abstract class EncryptActivity extends BaseActivity {      public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java deleted file mode 100644 index 2a102c6c4..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.net.Uri; - -import org.sufficientlysecure.keychain.util.Passphrase; - -import java.util.ArrayList; - -public interface EncryptActivityInterface { - -    public interface UpdateListener { -        void onNotifyUpdate(); -    } - -    public boolean isUseArmor(); -    public boolean isUseCompression(); -    public boolean isEncryptFilenames(); -    public boolean isHiddenRecipients(); - -    public long getSignatureKey(); -    public long[] getEncryptionKeys(); -    public String[] getEncryptionUsers(); -    public void setSignatureKey(long signatureKey); -    public void setEncryptionKeys(long[] encryptionKeys); -    public void setEncryptionUsers(String[] encryptionUsers); - -    public void setPassphrase(Passphrase passphrase); - -    // ArrayList on purpose as only those are parcelable -    public ArrayList<Uri> getInputUris(); -    public ArrayList<Uri> getOutputUris(); -    public void setInputUris(ArrayList<Uri> uris); -    public void setOutputUris(ArrayList<Uri> uris); - -    public String getMessage(); -    public void setMessage(String message); - -    /** -     * Call this to notify the UI for changes done on the array lists or arrays, -     * automatically called if setter is used -     */ -    public void notifyUpdate(); - -    public void startEncrypt(boolean share); -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java index 269fdde8e..64e908b1a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -18,11 +18,13 @@  package org.sufficientlysecure.keychain.ui; +import android.app.Activity;  import android.content.Intent;  import android.net.Uri;  import android.os.Bundle;  import android.support.v4.app.Fragment;  import android.support.v4.app.FragmentTransaction; +import android.view.View;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; @@ -33,7 +35,7 @@ import org.sufficientlysecure.keychain.util.Passphrase;  import java.util.ArrayList;  public class EncryptFilesActivity extends BaseActivity implements -        EncryptAsymmetricFragment.IAsymmetric, EncryptSymmetricFragment.ISymmetric, +        EncryptModeAsymmetricFragment.IAsymmetric, EncryptModeSymmetricFragment.ISymmetric,          EncryptFilesFragment.IMode {      /* Intents */ @@ -53,6 +55,13 @@ public class EncryptFilesActivity extends BaseActivity implements      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState); +        setFullScreenDialogClose(new View.OnClickListener() { +            @Override +            public void onClick(View v) { +                finish(); +            } +        }, false); +          // Handle intent actions          handleActions(getIntent(), savedInstanceState);      } @@ -101,7 +110,7 @@ public class EncryptFilesActivity extends BaseActivity implements          if (savedInstanceState == null) {              FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); -            mModeFragment = EncryptAsymmetricFragment.newInstance(mSigningKeyId, mEncryptionKeyIds); +            mModeFragment = EncryptModeAsymmetricFragment.newInstance(mSigningKeyId, mEncryptionKeyIds);              transaction.replace(R.id.encrypt_mode_container, mModeFragment, "mode");              mEncryptFragment = EncryptFilesFragment.newInstance(uris, useArmor); @@ -119,8 +128,8 @@ public class EncryptFilesActivity extends BaseActivity implements          getSupportFragmentManager().beginTransaction()                  .replace(R.id.encrypt_mode_container,                          symmetric -                                ? EncryptSymmetricFragment.newInstance() -                                : EncryptAsymmetricFragment.newInstance(0, null) +                                ? EncryptModeSymmetricFragment.newInstance() +                                : EncryptModeAsymmetricFragment.newInstance(0, null)                  )                  .commitAllowingStateLoss();          getSupportFragmentManager().executePendingTransactions(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index 771800245..fb9a86b07 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -68,17 +68,18 @@ import java.util.Set;  public class EncryptFilesFragment extends CryptoOperationFragment { -    private static final int REQUEST_CODE_INPUT = 0x00007003; -    private static final int REQUEST_CODE_OUTPUT = 0x00007007; -      public interface IMode { -          public void onModeChanged(boolean symmetric);      } +    public static final String ARG_USE_ASCII_ARMOR = "use_ascii_armor"; +    public static final String ARG_URIS = "uris"; + +    private static final int REQUEST_CODE_INPUT = 0x00007003; +    private static final int REQUEST_CODE_OUTPUT = 0x00007007; +      private IMode mModeInterface; -    // model used by fragments      private boolean mSymmetricMode = true;      private boolean mUseArmor = false;      private boolean mUseCompression = true; @@ -99,11 +100,6 @@ public class EncryptFilesFragment extends CryptoOperationFragment {      private SelectedFilesAdapter mAdapter = new SelectedFilesAdapter();      private final Map<Uri, Bitmap> thumbnailCache = new HashMap<>(); - -    public static final String ARG_USE_ASCII_ARMOR = "use_ascii_armor"; -    public static final String ARG_URIS = "uris"; - -      /**       * Creates new instance of this fragment       */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java index 06c711b92..8c117deca 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java @@ -40,7 +40,7 @@ import java.util.ArrayList;  import java.util.Iterator;  import java.util.List; -public class EncryptAsymmetricFragment extends Fragment { +public class EncryptModeAsymmetricFragment extends Fragment {      public interface IAsymmetric { @@ -74,8 +74,8 @@ public class EncryptAsymmetricFragment extends Fragment {      /**       * Creates new instance of this fragment       */ -    public static EncryptAsymmetricFragment newInstance(long signatureKey, long[] encryptionKeyIds) { -        EncryptAsymmetricFragment frag = new EncryptAsymmetricFragment(); +    public static EncryptModeAsymmetricFragment newInstance(long signatureKey, long[] encryptionKeyIds) { +        EncryptModeAsymmetricFragment frag = new EncryptModeAsymmetricFragment();          Bundle args = new Bundle();          args.putLong(ARG_SINGATURE_KEY_ID, signatureKey); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeSymmetricFragment.java index 22e116a42..48b1f4983 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeSymmetricFragment.java @@ -30,7 +30,7 @@ import android.widget.EditText;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.util.Passphrase; -public class EncryptSymmetricFragment extends Fragment { +public class EncryptModeSymmetricFragment extends Fragment {      public interface ISymmetric { @@ -45,8 +45,8 @@ public class EncryptSymmetricFragment extends Fragment {      /**       * Creates new instance of this fragment       */ -    public static EncryptSymmetricFragment newInstance() { -        EncryptSymmetricFragment frag = new EncryptSymmetricFragment(); +    public static EncryptModeSymmetricFragment newInstance() { +        EncryptModeSymmetricFragment frag = new EncryptModeSymmetricFragment();          Bundle args = new Bundle();          frag.setArguments(args); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 56f0b198e..2ffb29b09 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -1,5 +1,5 @@  /* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2012-2015 Dominik Schürmann <dominik@dominikschuermann.de>   * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>   *   * This program is free software: you can redistribute it and/or modify @@ -19,30 +19,21 @@  package org.sufficientlysecure.keychain.ui;  import android.content.Intent; -import android.net.Uri;  import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.view.View; -import org.spongycastle.bcpg.CompressionAlgorithmTags;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.api.OpenKeychainIntents; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; -import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.PgpConstants; -import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; -import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.base.BaseActivity;  import org.sufficientlysecure.keychain.util.Log;  import org.sufficientlysecure.keychain.util.Passphrase; -import org.sufficientlysecure.keychain.util.ShareHelper; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; - -public class EncryptTextActivity extends EncryptActivity { +public class EncryptTextActivity extends BaseActivity implements +        EncryptModeAsymmetricFragment.IAsymmetric, EncryptModeSymmetricFragment.ISymmetric, +        EncryptTextFragment.IMode {      /* Intents */      public static final String ACTION_ENCRYPT_TEXT = OpenKeychainIntents.ENCRYPT_TEXT; @@ -54,244 +45,22 @@ public class EncryptTextActivity extends EncryptActivity {      public static final String EXTRA_SIGNATURE_KEY_ID = Constants.EXTRA_PREFIX + "EXTRA_SIGNATURE_KEY_ID";      public static final String EXTRA_ENCRYPTION_KEY_IDS = Constants.EXTRA_PREFIX + "EXTRA_SIGNATURE_KEY_IDS"; -    // view -    private int mCurrentMode = MODE_ASYMMETRIC; - -    // tabs -    private static final int MODE_ASYMMETRIC = 0; -    private static final int MODE_SYMMETRIC = 1; - -    // model used by fragments -    private boolean mShareAfterEncrypt = false; -    private boolean mUseCompression = true; -    private boolean mHiddenRecipients = false; - -    private long mEncryptionKeyIds[] = null; -    private String mEncryptionUserIds[] = null; -    // TODO Constants.key.none? What's wrong with a null value? -    private long mSigningKeyId = Constants.key.none; -    private Passphrase mPassphrase = new Passphrase(); - -    private ArrayList<Uri> mInputUris; -    private ArrayList<Uri> mOutputUris; -    private String mMessage = ""; - -    public boolean isModeSymmetric() { -        return MODE_SYMMETRIC == mCurrentMode; -    } - -    public boolean isUseCompression() { -        return mUseCompression; -    } - -    public boolean isHiddenRecipients() { -        return mHiddenRecipients; -    } - -    public long getSignatureKey() { -        return mSigningKeyId; -    } - -    public long[] getEncryptionKeys() { -        return mEncryptionKeyIds; -    } - -    public String[] getEncryptionUsers() { -        return mEncryptionUserIds; -    } - -    public void setSignatureKey(long signatureKey) { -        mSigningKeyId = signatureKey; -    } - -    public void setEncryptionKeys(long[] encryptionKeys) { -        mEncryptionKeyIds = encryptionKeys; -    } - -    public void setEncryptionUsers(String[] encryptionUsers) { -        mEncryptionUserIds = encryptionUsers; -    } - -    public void setPassphrase(Passphrase passphrase) { -        if (mPassphrase != null) { -            mPassphrase.removeFromMemory(); -        } -        mPassphrase = passphrase; -    } - -    public ArrayList<Uri> getInputUris() { -        if (mInputUris == null) mInputUris = new ArrayList<>(); -        return mInputUris; -    } - -    public ArrayList<Uri> getOutputUris() { -        if (mOutputUris == null) mOutputUris = new ArrayList<>(); -        return mOutputUris; -    } - -    public void setInputUris(ArrayList<Uri> uris) { -        mInputUris = uris; -    } - -    public void setOutputUris(ArrayList<Uri> uris) { -        mOutputUris = uris; -    } - -    public String getMessage() { -        return mMessage; -    } - -    public void setMessage(String message) { -        mMessage = message; -    } - -    public void startEncrypt(boolean share) { -        mShareAfterEncrypt = share; -        startEncrypt(); -    } - -    @Override -    protected void onEncryptSuccess(SignEncryptResult result) { -        if (mShareAfterEncrypt) { -            // Share encrypted message/file -            startActivity(sendWithChooserExcludingEncrypt(result.getResultBytes())); -        } else { -            // Copy to clipboard -            copyToClipboard(result.getResultBytes()); -            result.createNotify(EncryptTextActivity.this).show(); -            // Notify.create(EncryptTextActivity.this, -            // R.string.encrypt_sign_clipboard_successful, Notify.Style.OK) -            // .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment)); -        } -    } - -    @Override -    protected SignEncryptParcel createEncryptBundle() { -        // fill values for this action -        SignEncryptParcel data = new SignEncryptParcel(); - -        data.setBytes(mMessage.getBytes()); -        data.setCleartextSignature(true); - -        if (mUseCompression) { -            data.setCompressionId(PgpConstants.sPreferredCompressionAlgorithms.get(0)); -        } else { -            data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED); -        } -        data.setHiddenRecipients(mHiddenRecipients); -        data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); -        data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); - -        // Always use armor for messages -        data.setEnableAsciiArmorOutput(true); - -        if (isModeSymmetric()) { -            Log.d(Constants.TAG, "Symmetric encryption enabled!"); -            Passphrase passphrase = mPassphrase; -            if (passphrase.isEmpty()) { -                passphrase = null; -            } -            data.setSymmetricPassphrase(passphrase); -        } else { -            data.setEncryptionMasterKeyIds(mEncryptionKeyIds); -            data.setSignatureMasterKeyId(mSigningKeyId); -            data.setSignaturePassphrase(mSigningKeyPassphrase); -        } -        return data; -    } - -    private void copyToClipboard(byte[] resultBytes) { -        ClipboardReflection.copyToClipboard(this, new String(resultBytes)); -    } - -    /** -     * Create Intent Chooser but exclude OK's EncryptActivity. -     */ -    private Intent sendWithChooserExcludingEncrypt(byte[] resultBytes) { -        Intent prototype = createSendIntent(resultBytes); -        String title = getString(R.string.title_share_message); - -        // we don't want to encrypt the encrypted, no inception ;) -        String[] blacklist = new String[]{ -                Constants.PACKAGE_NAME + ".ui.EncryptTextActivity", -                "org.thialfihar.android.apg.ui.EncryptActivity" -        }; - -        return new ShareHelper(this).createChooserExcluding(prototype, title, blacklist); -    } - -    private Intent createSendIntent(byte[] resultBytes) { -        Intent sendIntent; -        sendIntent = new Intent(Intent.ACTION_SEND); -        sendIntent.setType(Constants.ENCRYPTED_TEXT_MIME); -        sendIntent.putExtra(Intent.EXTRA_TEXT, new String(resultBytes)); - -        if (!isModeSymmetric() && mEncryptionUserIds != null) { -            Set<String> users = new HashSet<>(); -            for (String user : mEncryptionUserIds) { -                KeyRing.UserId userId = KeyRing.splitUserId(user); -                if (userId.email != null) { -                    users.add(userId.email); -                } -            } -            // pass trough email addresses as extra for email applications -            sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()])); -        } -        return sendIntent; -    } - -    protected boolean inputIsValid() { -        if (mMessage == null) { -            Notify.create(this, R.string.error_message, Notify.Style.ERROR) -                    .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment)); -            return false; -        } - -        if (isModeSymmetric()) { -            // symmetric encryption checks - -            if (mPassphrase == null) { -                Notify.create(this, R.string.passphrases_do_not_match, Notify.Style.ERROR) -                        .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment)); -                return false; -            } -            if (mPassphrase.isEmpty()) { -                Notify.create(this, R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) -                        .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment)); -                return false; -            } - -        } else { -            // asymmetric encryption checks - -            boolean gotEncryptionKeys = (mEncryptionKeyIds != null -                    && mEncryptionKeyIds.length > 0); - -            if (!gotEncryptionKeys && mSigningKeyId == 0) { -                Notify.create(this, R.string.select_encryption_or_signature_key, Notify.Style.ERROR) -                        .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment)); -                return false; -            } -        } -        return true; -    } +    Fragment mModeFragment; +    EncryptTextFragment mEncryptFragment;      @Override      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState); -        // if called with an intent action, do not init drawer navigation -        if (ACTION_ENCRYPT_TEXT.equals(getIntent().getAction())) { -            // lock drawer -//            deactivateDrawerNavigation(); -            // TODO: back button to key? -        } else { -//            activateDrawerNavigation(savedInstanceState); -        } +        setFullScreenDialogClose(new View.OnClickListener() { +            @Override +            public void onClick(View v) { +                finish(); +            } +        }, false);          // Handle intent actions -        handleActions(getIntent()); -        updateModeFragment(); +        handleActions(getIntent(), savedInstanceState);      }      @Override @@ -299,56 +68,13 @@ public class EncryptTextActivity extends EncryptActivity {          setContentView(R.layout.encrypt_text_activity);      } -    @Override -    public boolean onCreateOptionsMenu(Menu menu) { -        getMenuInflater().inflate(R.menu.encrypt_text_activity, menu); -        return super.onCreateOptionsMenu(menu); -    } - -    private void updateModeFragment() { -        getSupportFragmentManager().beginTransaction() -                .replace(R.id.encrypt_mode, -                        mCurrentMode == MODE_SYMMETRIC -                                ? new EncryptSymmetricFragment() -                                : new EncryptAsymmetricFragment() -                ) -                .commitAllowingStateLoss(); -        getSupportFragmentManager().executePendingTransactions(); -    } - -    @Override -    public boolean onOptionsItemSelected(MenuItem item) { -        if (item.isCheckable()) { -            item.setChecked(!item.isChecked()); -        } -        switch (item.getItemId()) { -            case R.id.check_use_symmetric: { -                mCurrentMode = item.isChecked() ? MODE_SYMMETRIC : MODE_ASYMMETRIC; -                updateModeFragment(); -                break; -            } -            case R.id.check_enable_compression: { -                mUseCompression = item.isChecked(); -                break; -            } -//            case R.id.check_hidden_recipients: { -//                mHiddenRecipients = item.isChecked(); -//                notifyUpdate(); -//                break; -//            } -            default: { -                return super.onOptionsItemSelected(item); -            } -        } -        return true; -    }      /**       * Handles all actions with this intent       *       * @param intent       */ -    private void handleActions(Intent intent) { +    private void handleActions(Intent intent, Bundle savedInstanceState) {          String action = intent.getAction();          Bundle extras = intent.getExtras();          String type = intent.getType(); @@ -379,19 +105,61 @@ public class EncryptTextActivity extends EncryptActivity {          }          String textData = extras.getString(EXTRA_TEXT); +        if (ACTION_ENCRYPT_TEXT.equals(action) && textData == null) { +            Log.e(Constants.TAG, "Include the extra 'text' in your Intent!"); +            return; +        }          // preselect keys given by intent -        mSigningKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID); -        mEncryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS); +        long mSigningKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID); +        long[] mEncryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS); -        /** -         * Main Actions -         */ -        if (ACTION_ENCRYPT_TEXT.equals(action) && textData != null) { -            mMessage = textData; -        } else if (ACTION_ENCRYPT_TEXT.equals(action)) { -            Log.e(Constants.TAG, "Include the extra 'text' in your Intent!"); + +        if (savedInstanceState == null) { +            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + +            mModeFragment = EncryptModeAsymmetricFragment.newInstance(mSigningKeyId, mEncryptionKeyIds); +            transaction.replace(R.id.encrypt_mode_container, mModeFragment, "mode"); + +            mEncryptFragment = EncryptTextFragment.newInstance(textData); +            transaction.replace(R.id.encrypt_text_container, mEncryptFragment, "text"); + +            transaction.commit(); + +            getSupportFragmentManager().executePendingTransactions();          }      } +    @Override +    public void onModeChanged(boolean symmetric) { +        // switch fragments +        getSupportFragmentManager().beginTransaction() +                .replace(R.id.encrypt_mode_container, +                        symmetric +                                ? EncryptModeSymmetricFragment.newInstance() +                                : EncryptModeAsymmetricFragment.newInstance(0, null) +                ) +                .commitAllowingStateLoss(); +        getSupportFragmentManager().executePendingTransactions(); +    } + +    @Override +    public void onSignatureKeyIdChanged(long signatureKeyId) { +        mEncryptFragment.setSigningKeyId(signatureKeyId); +    } + +    @Override +    public void onEncryptionKeyIdsChanged(long[] encryptionKeyIds) { +        mEncryptFragment.setEncryptionKeyIds(encryptionKeyIds); +    } + +    @Override +    public void onEncryptionUserIdsChanged(String[] encryptionUserIds) { +        mEncryptFragment.setEncryptionUserIds(encryptionUserIds); +    } + +    @Override +    public void onPassphraseChanged(Passphrase passphrase) { +        mEncryptFragment.setPassphrase(passphrase); +    }  } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index 5d9994c5c..c71edcd22 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -1,5 +1,5 @@  /* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>   *   * This program is free software: you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -18,32 +18,102 @@  package org.sufficientlysecure.keychain.ui;  import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Intent;  import android.os.Bundle; -import android.support.v4.app.Fragment; +import android.os.Message; +import android.os.Messenger;  import android.text.Editable;  import android.text.TextWatcher;  import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater;  import android.view.MenuItem;  import android.view.View;  import android.view.ViewGroup;  import android.widget.TextView; +import org.spongycastle.bcpg.CompressionAlgorithmTags; +import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; +import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; +import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.PgpConstants; +import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; +import org.sufficientlysecure.keychain.util.ShareHelper; + +import java.util.HashSet; +import java.util.Set; + +public class EncryptTextFragment extends CryptoOperationFragment { + +    public interface IMode { +        public void onModeChanged(boolean symmetric); +    } -public class EncryptTextFragment extends Fragment {      public static final String ARG_TEXT = "text"; +    private IMode mModeInterface; + +    private boolean mSymmetricMode = true; +    private boolean mShareAfterEncrypt = false; +    private boolean mUseCompression = true; +    private boolean mHiddenRecipients = false; + +    private long mEncryptionKeyIds[] = null; +    private String mEncryptionUserIds[] = null; +    // TODO Constants.key.none? What's wrong with a null value? +    private long mSigningKeyId = Constants.key.none; +    private Passphrase mPassphrase = new Passphrase(); +    private String mMessage = ""; +      private TextView mText; -    private EncryptActivityInterface mEncryptInterface; +    public void setEncryptionKeyIds(long[] encryptionKeyIds) { +        mEncryptionKeyIds = encryptionKeyIds; +    } + +    public void setEncryptionUserIds(String[] encryptionUserIds) { +        mEncryptionUserIds = encryptionUserIds; +    } + +    public void setSigningKeyId(long signingKeyId) { +        mSigningKeyId = signingKeyId; +    } + +    public void setPassphrase(Passphrase passphrase) { +        mPassphrase = passphrase; +    } + +    /** +     * Creates new instance of this fragment +     */ +    public static EncryptTextFragment newInstance(String text) { +        EncryptTextFragment frag = new EncryptTextFragment(); + +        Bundle args = new Bundle(); +        args.putString(ARG_TEXT, text); +        frag.setArguments(args); + +        return frag; +    }      @Override      public void onAttach(Activity activity) {          super.onAttach(activity);          try { -            mEncryptInterface = (EncryptActivityInterface) activity; +            mModeInterface = (IMode) activity;          } catch (ClassCastException e) { -            throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface"); +            throw new ClassCastException(activity.toString() + " must implement IMode");          }      } @@ -54,6 +124,9 @@ public class EncryptTextFragment extends Fragment {      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {          View view = inflater.inflate(R.layout.encrypt_text_fragment, container, false); +        if (mMessage != null) { +            mText.setText(mMessage); +        }          mText = (TextView) view.findViewById(R.id.encrypt_text_text);          mText.addTextChangedListener(new TextWatcher() {              @Override @@ -68,7 +141,7 @@ public class EncryptTextFragment extends Fragment {              @Override              public void afterTextChanged(Editable s) { -                mEncryptInterface.setMessage(s.toString()); +                mMessage = s.toString();              }          }); @@ -78,29 +151,43 @@ public class EncryptTextFragment extends Fragment {      @Override      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState); +        mMessage = getArguments().getString(ARG_TEXT);          setHasOptionsMenu(true);      }      @Override -    public void onActivityCreated(Bundle savedInstanceState) { -        super.onActivityCreated(savedInstanceState); - -        String text = mEncryptInterface.getMessage(); -        if (text != null) { -            mText.setText(text); -        } +    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { +        super.onCreateOptionsMenu(menu, inflater); +        inflater.inflate(R.menu.encrypt_text_activity, menu);      }      @Override      public boolean onOptionsItemSelected(MenuItem item) { +        if (item.isCheckable()) { +            item.setChecked(!item.isChecked()); +        }          switch (item.getItemId()) { +            case R.id.check_use_symmetric: { +                mSymmetricMode = item.isChecked(); +                mModeInterface.onModeChanged(mSymmetricMode); +                break; +            } +            case R.id.check_enable_compression: { +                mUseCompression = item.isChecked(); +                break; +            } +//            case R.id.check_hidden_recipients: { +//                mHiddenRecipients = item.isChecked(); +//                notifyUpdate(); +//                break; +//            }              case R.id.encrypt_copy: { -                mEncryptInterface.startEncrypt(false); +                startEncrypt(false);                  break;              }              case R.id.encrypt_share: { -                mEncryptInterface.startEncrypt(true); +                startEncrypt(true);                  break;              }              default: { @@ -109,4 +196,222 @@ public class EncryptTextFragment extends Fragment {          }          return true;      } + + +    protected void onEncryptSuccess(SignEncryptResult result) { +        if (mShareAfterEncrypt) { +            // Share encrypted message/file +            startActivity(sendWithChooserExcludingEncrypt(result.getResultBytes())); +        } else { +            // Copy to clipboard +            copyToClipboard(result.getResultBytes()); +            result.createNotify(getActivity()).show(); +            // Notify.create(EncryptTextActivity.this, +            // R.string.encrypt_sign_clipboard_successful, Notify.Style.OK) +            // .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment)); +        } +    } + +    protected SignEncryptParcel createEncryptBundle() { +        // fill values for this action +        SignEncryptParcel data = new SignEncryptParcel(); + +        data.setBytes(mMessage.getBytes()); +        data.setCleartextSignature(true); + +        if (mUseCompression) { +            data.setCompressionId(PgpConstants.sPreferredCompressionAlgorithms.get(0)); +        } else { +            data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED); +        } +        data.setHiddenRecipients(mHiddenRecipients); +        data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); +        data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); + +        // Always use armor for messages +        data.setEnableAsciiArmorOutput(true); + +        if (mSymmetricMode) { +            Log.d(Constants.TAG, "Symmetric encryption enabled!"); +            Passphrase passphrase = mPassphrase; +            if (passphrase.isEmpty()) { +                passphrase = null; +            } +            data.setSymmetricPassphrase(passphrase); +        } else { +            data.setEncryptionMasterKeyIds(mEncryptionKeyIds); +            data.setSignatureMasterKeyId(mSigningKeyId); +//            data.setSignaturePassphrase(mSigningKeyPassphrase); +        } +        return data; +    } + +    private void copyToClipboard(byte[] resultBytes) { +        ClipboardReflection.copyToClipboard(getActivity(), new String(resultBytes)); +    } + +    /** +     * Create Intent Chooser but exclude OK's EncryptActivity. +     */ +    private Intent sendWithChooserExcludingEncrypt(byte[] resultBytes) { +        Intent prototype = createSendIntent(resultBytes); +        String title = getString(R.string.title_share_message); + +        // we don't want to encrypt the encrypted, no inception ;) +        String[] blacklist = new String[]{ +                Constants.PACKAGE_NAME + ".ui.EncryptTextActivity", +                "org.thialfihar.android.apg.ui.EncryptActivity" +        }; + +        return new ShareHelper(getActivity()).createChooserExcluding(prototype, title, blacklist); +    } + +    private Intent createSendIntent(byte[] resultBytes) { +        Intent sendIntent; +        sendIntent = new Intent(Intent.ACTION_SEND); +        sendIntent.setType(Constants.ENCRYPTED_TEXT_MIME); +        sendIntent.putExtra(Intent.EXTRA_TEXT, new String(resultBytes)); + +        if (!mSymmetricMode && mEncryptionUserIds != null) { +            Set<String> users = new HashSet<>(); +            for (String user : mEncryptionUserIds) { +                KeyRing.UserId userId = KeyRing.splitUserId(user); +                if (userId.email != null) { +                    users.add(userId.email); +                } +            } +            // pass trough email addresses as extra for email applications +            sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()])); +        } +        return sendIntent; +    } + +    protected boolean inputIsValid() { +        if (mMessage == null) { +            Notify.create(getActivity(), R.string.error_message, Notify.Style.ERROR) +                    .show(this); +            return false; +        } + +        if (mSymmetricMode) { +            // symmetric encryption checks + +            if (mPassphrase == null) { +                Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR) +                        .show(this); +                return false; +            } +            if (mPassphrase.isEmpty()) { +                Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) +                        .show(this); +                return false; +            } + +        } else { +            // asymmetric encryption checks + +            boolean gotEncryptionKeys = (mEncryptionKeyIds != null +                    && mEncryptionKeyIds.length > 0); + +            if (!gotEncryptionKeys && mSigningKeyId == 0) { +                Notify.create(getActivity(), R.string.select_encryption_or_signature_key, Notify.Style.ERROR) +                        .show(this); +                return false; +            } +        } +        return true; +    } + + +    public void startEncrypt(boolean share) { +        mShareAfterEncrypt = share; +        startEncrypt(); +    } + +    public void startEncrypt() { +        cryptoOperation(null); +    } + +    @Override +    protected void cryptoOperation(CryptoInputParcel cryptoInput) { +        if (!inputIsValid()) { +            // Notify was created by inputIsValid. +            return; +        } + +        // Send all information needed to service to edit key in other thread +        Intent intent = new Intent(getActivity(), KeychainIntentService.class); +        intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); + +        final SignEncryptParcel input = createEncryptBundle(); +        if (cryptoInput != null) { +            input.setCryptoInput(cryptoInput); +        } + +        Bundle data = new Bundle(); +        data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); +        intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + +        // Message is received after encrypting is done in KeychainIntentService +        ServiceProgressHandler serviceHandler = new ServiceProgressHandler( +                getActivity(), +                getString(R.string.progress_encrypting), +                ProgressDialog.STYLE_HORIZONTAL, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) { +            public void handleMessage(Message message) { +                // handle messages by standard KeychainIntentServiceHandler first +                super.handleMessage(message); + +                // handle pending messages +                if (handlePendingMessage(message)) { +                    return; +                } + +                if (message.arg1 == MessageStatus.OKAY.ordinal()) { +                    SignEncryptResult result = +                            message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT); + +                    PgpSignEncryptResult pgpResult = result.getPending(); + +//                    if (pgpResult != null && pgpResult.isPending()) { +//                        if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == +//                                PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { +//                            startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); +//                        } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == +//                                PgpSignEncryptResult.RESULT_PENDING_NFC) { +// +//                            RequiredInputParcel parcel = RequiredInputParcel.createNfcSignOperation( +//                                    pgpResult.getNfcHash(), +//                                    pgpResult.getNfcAlgo(), +//                                    input.getSignatureTime()); +//                            startNfcSign(pgpResult.getNfcKeyId(), parcel); +// +//                        } else { +//                            throw new RuntimeException("Unhandled pending result!"); +//                        } +//                        return; +//                    } + +                    if (result.success()) { +                        onEncryptSuccess(result); +                    } else { +                        result.createNotify(getActivity()).show(); +                    } + +                    // no matter the result, reset parameters +//                    mSigningKeyPassphrase = null; +                } +            } +        }; +        // Create a new Messenger for the communication back +        Messenger messenger = new Messenger(serviceHandler); +        intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + +        // show progress dialog +        serviceHandler.showProgressDialog(getActivity()); + +        // start service with intent +        getActivity().startService(intent); +    } +  } diff --git a/OpenKeychain/src/main/res/layout/encrypt_text_activity.xml b/OpenKeychain/src/main/res/layout/encrypt_text_activity.xml index dcf5bd041..a5082010e 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_text_activity.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_text_activity.xml @@ -23,14 +23,13 @@          <include layout="@layout/notify_area" />          <FrameLayout -            android:id="@+id/encrypt_mode" +            android:id="@+id/encrypt_mode_container"              android:layout_width="match_parent"              android:layout_height="wrap_content"              android:orientation="vertical" /> -        <fragment -            android:id="@+id/encrypt_text_fragment" -            android:name="org.sufficientlysecure.keychain.ui.EncryptTextFragment" +        <FrameLayout +            android:id="@+id/encrypt_text_container"              android:layout_width="match_parent"              android:layout_height="match_parent" /> | 
