diff options
author | Dominik Schürmann <dominik@dominikschuermann.de> | 2015-07-06 11:27:57 +0200 |
---|---|---|
committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2015-07-06 11:27:57 +0200 |
commit | 801566bdb11d5edac45680037ada16b51922ba18 (patch) | |
tree | 3b52980b4af3ec90c624f07292c27c9bbd6692be /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui | |
parent | baf059843ef51c57e47cd74fa695485b93482669 (diff) | |
parent | 7648602fc876df3ec5827f3bba1ebbb8ae92eaae (diff) | |
download | open-keychain-801566bdb11d5edac45680037ada16b51922ba18.tar.gz open-keychain-801566bdb11d5edac45680037ada16b51922ba18.tar.bz2 open-keychain-801566bdb11d5edac45680037ada16b51922ba18.zip |
Merge branch 'master' of github.com:open-keychain/open-keychain
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui')
32 files changed, 1083 insertions, 164 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index 891c2268c..ab631c6fe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -54,6 +54,7 @@ import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; import java.util.ArrayList; @@ -311,6 +312,11 @@ public class CertifyKeyFragment CertifyActionsParcel actionsParcel = new CertifyActionsParcel(selectedKeyId); actionsParcel.mCertifyActions.addAll(certifyActions); + if (mUploadKeyCheckbox.isChecked()) { + actionsParcel.keyServerUri = Preferences.getPreferences(getActivity()) + .getPreferredKeyserver(); + } + // cached for next cryptoOperation loop cacheActionsParcel(actionsParcel); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java index 7192b7335..51c1bd079 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -23,6 +23,7 @@ import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -385,14 +386,18 @@ public class CreateKeyFinalFragment extends Fragment { } public void handleResult(ExportResult result) { - // TODO: ExportOperation UPLOAD_KEYSERVER needs logs! - // TODO: then merge logs here! - //saveKeyResult.getLog().add(result, 0); + Activity activity = getActivity(); + if (activity == null) { + return; + } + + saveKeyResult.getLog().add(result, 0); Intent data = new Intent(); data.putExtra(OperationResult.EXTRA_RESULT, saveKeyResult); - getActivity().setResult(Activity.RESULT_OK, data); - getActivity().finish(); + activity.setResult(Activity.RESULT_OK, data); + activity.finish(); + } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java index c64f05687..9e3dce28f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java @@ -41,7 +41,9 @@ import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.NfcListenerFragment; import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; public class CreateYubiKeyImportFragment @@ -131,7 +133,18 @@ public class CreateYubiKeyImportFragment view.findViewById(R.id.button_search).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - refreshSearch(); + final Preferences.ProxyPrefs proxyPrefs = Preferences.getPreferences(getActivity()).getProxyPrefs(); + Runnable ignoreTor = new Runnable() { + @Override + public void run() { + refreshSearch(new ParcelableProxy(null, -1, null)); + } + }; + + if (OrbotHelper.putOrbotInRequiredState(R.string.orbot_ignore_tor, ignoreTor, proxyPrefs, + getActivity())) { + refreshSearch(proxyPrefs.parcelableProxy); + } } }); @@ -170,9 +183,10 @@ public class CreateYubiKeyImportFragment } } - public void refreshSearch() { + public void refreshSearch(ParcelableProxy parcelableProxy) { + // TODO: PHILIP verify proxy implementation in YubiKey parts mListFragment.loadNew(new ImportKeysListFragment.CloudLoaderState("0x" + mNfcFingerprint, - Preferences.getPreferences(getActivity()).getCloudSearchPrefs())); + Preferences.getPreferences(getActivity()).getCloudSearchPrefs()), parcelableProxy); } public void importKey() { @@ -210,7 +224,20 @@ public class CreateYubiKeyImportFragment public void onNfcPostExecute() throws IOException { setData(); - refreshSearch(); + + Preferences.ProxyPrefs proxyPrefs = Preferences.getPreferences(getActivity()).getProxyPrefs(); + Runnable ignoreTor = new Runnable() { + @Override + public void run() { + refreshSearch(new ParcelableProxy(null, -1, null)); + } + }; + + if (OrbotHelper.putOrbotInRequiredState(R.string.orbot_ignore_tor, ignoreTor, proxyPrefs, + getActivity())) { + refreshSearch(proxyPrefs.parcelableProxy); + } + } @Override 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 4eb8cd5e8..afd6b337e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -19,15 +19,11 @@ package org.sufficientlysecure.keychain.ui; import java.util.ArrayList; -import android.app.Activity; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; import android.support.v4.app.Fragment; -import android.os.Parcelable; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; @@ -52,13 +48,14 @@ import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; -import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.Style; +import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; public abstract class DecryptFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java index 96767463e..db2841488 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java @@ -304,7 +304,7 @@ public class DecryptListFragment } final Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setType(type); + intent.setDataAndType(outputUri, type); final List<ResolveInfo> matches = context.getPackageManager().queryIntentActivities(intent, 0); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java index 7b3af48cc..dc06e9115 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java @@ -17,6 +17,10 @@ package org.sufficientlysecure.keychain.ui; +import android.app.Activity; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; @@ -29,9 +33,9 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.ShareHelper; public class DisplayTextFragment extends DecryptFragment { @@ -80,8 +84,19 @@ public class DisplayTextFragment extends DecryptFragment { } private void copyToClipboard(String text) { - ClipboardReflection.copyToClipboard(getActivity(), text); - Notify.create(getActivity(), R.string.text_copied_to_clipboard, Notify.Style.OK).show(); + Activity activity = getActivity(); + if (activity == null) { + return; + } + + ClipboardManager clipMan = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE); + if (clipMan == null) { + Notify.create(activity, R.string.error_clipboard_copy, Style.ERROR).show(); + return; + } + + clipMan.setPrimaryClip(ClipData.newPlainText(Constants.CLIPBOARD_LABEL, text)); + Notify.create(activity, R.string.text_copied_to_clipboard, Style.OK).show(); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java index 779b22535..fc72a6c9f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java @@ -124,8 +124,7 @@ public class EncryptDecryptOverviewFragment extends Fragment { super.onResume(); // get text from clipboard - final CharSequence clipboardText = - ClipboardReflection.getClipboardText(getActivity()); + final CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity()); // if it's null, nothing to do here /o/ if (clipboardText == null) { 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 215af5885..b382e31d0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -35,6 +35,7 @@ import android.graphics.Point; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.support.v4.app.FragmentActivity; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -388,6 +389,12 @@ public class EncryptFilesFragment @Override public void onCryptoOperationSuccess(final SignEncryptResult result) { + FragmentActivity activity = getActivity(); + if (activity == null) { + // it's gone, there's nothing we can do here + return; + } + if (mDeleteAfterEncrypt) { // TODO make behavior coherent here DeleteFileDialogFragment deleteFileDialog = @@ -400,13 +407,18 @@ public class EncryptFilesFragment // Share encrypted message/file startActivity(sendWithChooserExcludingEncrypt()); } else { + Activity activity = getActivity(); + if (activity == null) { + // it's gone, there's nothing we can do here + return; + } // Save encrypted file - result.createNotify(getActivity()).show(); + result.createNotify(activity).show(); } } }); - deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog"); + deleteFileDialog.show(activity.getSupportFragmentManager(), "deleteDialog"); } else { switch (mAfterEncryptAction) { @@ -417,25 +429,24 @@ public class EncryptFilesFragment break; case COPY: - Activity activity = getActivity(); - if (activity == null) { - // it's gone, there's nothing we can do here - return; - } ClipboardManager clipMan = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE); + if (clipMan == null) { + Notify.create(activity, R.string.error_clipboard_copy, Style.ERROR).show(); + break; + } ClipData clip = new ClipData(getString(R.string.label_clip_title), // make available as application/pgp-encrypted new String[] { "text/plain" }, new ClipData.Item(mOutputUris.get(0)) ); clipMan.setPrimaryClip(clip); - result.createNotify(getActivity()).show(); + result.createNotify(activity).show(); break; case SAVE: // Encrypted file was saved already, just show notification - result.createNotify(getActivity()).show(); + result.createNotify(activity).show(); break; } } 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 886c52651..8d3738fbd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -18,6 +18,9 @@ package org.sufficientlysecure.keychain.ui; import android.app.Activity; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.text.Editable; @@ -33,7 +36,6 @@ 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.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.PgpConstants; @@ -265,8 +267,21 @@ public class EncryptTextFragment return data; } - private void copyToClipboard(byte[] resultBytes) { - ClipboardReflection.copyToClipboard(getActivity(), new String(resultBytes)); + private void copyToClipboard(SignEncryptResult result) { + Activity activity = getActivity(); + if (activity == null) { + return; + } + + ClipboardManager clipMan = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE); + if (clipMan == null) { + Notify.create(activity, R.string.error_clipboard_copy, Style.ERROR).show(); + return; + } + + ClipData clip = ClipData.newPlainText(Constants.CLIPBOARD_LABEL, new String(result.getResultBytes())); + clipMan.setPrimaryClip(clip); + result.createNotify(activity).show(); } /** @@ -323,11 +338,7 @@ public class EncryptTextFragment 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)); + copyToClipboard(result); } } 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 bc83b05b0..2e8e6f6bd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -42,6 +42,8 @@ import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ParcelableFileCache; import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; +import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; import java.io.IOException; import java.util.ArrayList; @@ -87,11 +89,14 @@ public class ImportKeysActivity extends BaseNfcActivity private ArrayList<ParcelableKeyRing> mKeyList; private CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult> mOperationHelper; + private Preferences.ProxyPrefs mProxyPrefs; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mProxyPrefs = Preferences.getPreferences(this).getProxyPrefs(); + mImportButton = findViewById(R.id.import_import); mImportButton.setOnClickListener(new OnClickListener() { @Override @@ -224,7 +229,7 @@ public class ImportKeysActivity extends BaseNfcActivity Notify.Style.WARN).show(mTopFragment); // we just set the keyserver startCloudFragment(savedInstanceState, null, false, keyserver); - // it's not necessary to set the keyserver for ImportKeysListFragment since + // we don't set the keyserver for ImportKeysListFragment since // it'll be taken care of by ImportKeysCloudFragment when the user clicks // the search button startListFragment(savedInstanceState, null, null, null, null); @@ -316,7 +321,8 @@ public class ImportKeysActivity extends BaseNfcActivity * specified in user preferences */ - private void startCloudFragment(Bundle savedInstanceState, String query, boolean disableQueryEdit, String keyserver) { + private void startCloudFragment(Bundle savedInstanceState, String query, boolean disableQueryEdit, String + keyserver) { // However, if we're being restored from a previous state, // then we don't need to do anything and should return or else // we could end up with overlapping fragments. @@ -346,8 +352,24 @@ public class ImportKeysActivity extends BaseNfcActivity } } - public void loadCallback(ImportKeysListFragment.LoaderState loaderState) { - mListFragment.loadNew(loaderState); + public void loadCallback(final ImportKeysListFragment.LoaderState loaderState) { + if (loaderState instanceof ImportKeysListFragment.CloudLoaderState) { + // do the tor check + // this handle will set tor to be ignored whenever a message is received + Runnable ignoreTor = new Runnable() { + @Override + public void run() { + // disables Tor until Activity is recreated + mProxyPrefs = new Preferences.ProxyPrefs(false, false, null, -1, null); + mListFragment.loadNew(loaderState, mProxyPrefs.parcelableProxy); + } + }; + if (OrbotHelper.putOrbotInRequiredState(R.string.orbot_ignore_tor, ignoreTor, mProxyPrefs, this)) { + mListFragment.loadNew(loaderState, mProxyPrefs.parcelableProxy); + } + } else if (loaderState instanceof ImportKeysListFragment.BytesLoaderState) { // must always be true + mListFragment.loadNew(loaderState, mProxyPrefs.parcelableProxy); + } } private void handleMessage(Message message) { 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 bf7e41045..55ccc3975 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -41,6 +41,7 @@ import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; +import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.Preferences; import java.io.ByteArrayInputStream; @@ -64,6 +65,7 @@ public class ImportKeysListFragment extends ListFragment implements private ImportKeysAdapter mAdapter; private LoaderState mLoaderState; + private ParcelableProxy mProxy; private static final int LOADER_ID_BYTES = 0; private static final int LOADER_ID_CLOUD = 1; @@ -126,6 +128,7 @@ public class ImportKeysListFragment extends ListFragment implements /** * Creates an interactive ImportKeyListFragment which reads keyrings from bytes, or file specified * by dataUri, or searches a keyserver for serverQuery, if parameter is not null, in that order + * Will immediately load data if non-null bytes/dataUri/serverQuery * * @param bytes byte data containing list of keyrings to be imported * @param dataUri file from which keyrings are to be imported @@ -141,7 +144,7 @@ public class ImportKeysListFragment extends ListFragment implements /** * Visually consists of a list of keyrings with checkboxes to specify which are to be imported - * Can immediately load keyrings specified by any of its parameters + * Will immediately load data if non-null bytes/dataUri/serverQuery is supplied * * @param bytes byte data containing list of keyrings to be imported * @param dataUri file from which keyrings are to be imported @@ -258,7 +261,9 @@ public class ImportKeysListFragment extends ListFragment implements mAdapter.notifyDataSetChanged(); } - public void loadNew(LoaderState loaderState) { + public void loadNew(LoaderState loaderState, ParcelableProxy proxy) { + mProxy = proxy; + mLoaderState = loaderState; restartLoaders(); @@ -301,7 +306,7 @@ public class ImportKeysListFragment extends ListFragment implements } case LOADER_ID_CLOUD: { CloudLoaderState ls = (CloudLoaderState) mLoaderState; - return new ImportKeysListCloudLoader(getActivity(), ls.mServerQuery, ls.mCloudPrefs); + return new ImportKeysListCloudLoader(getActivity(), ls.mServerQuery, ls.mCloudPrefs, mProxy); } default: diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java index da713d0d8..f45f1b350 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java @@ -44,7 +44,9 @@ import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.util.IntentIntegratorSupportV4; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; import java.util.ArrayList; import java.util.Locale; @@ -157,8 +159,7 @@ public class ImportKeysProxyActivity extends FragmentActivity returnResult(intent); return; } - - String fingerprint = uri.getEncodedSchemeSpecificPart().toLowerCase(Locale.ENGLISH); + final String fingerprint = uri.getEncodedSchemeSpecificPart().toLowerCase(Locale.ENGLISH); if (!fingerprint.matches("[a-fA-F0-9]{40}")) { SingletonResult result = new SingletonResult( SingletonResult.RESULT_ERROR, LogType.MSG_WRONG_QR_CODE_FP); @@ -273,7 +274,8 @@ public class ImportKeysProxyActivity extends FragmentActivity // only one message sent during the beam NdefMessage msg = (NdefMessage) rawMsgs[0]; // record 0 contains the MIME type, record 1 is the AAR, if present - byte[] receivedKeyringBytes = msg.getRecords()[0].getPayload(); + final byte[] receivedKeyringBytes = msg.getRecords()[0].getPayload(); + importKeys(receivedKeyringBytes); } 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 e038cf948..c5bfdbedf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -52,6 +52,9 @@ import android.widget.TextView; import com.getbase.floatingactionbutton.FloatingActionButton; import com.getbase.floatingactionbutton.FloatingActionsMenu; +import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; +import se.emilsjolander.stickylistheaders.StickyListHeadersListView; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; @@ -71,19 +74,16 @@ import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter; import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.ExportHelper; import org.sufficientlysecure.keychain.util.FabContainer; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; -import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; -import se.emilsjolander.stickylistheaders.StickyListHeadersListView; - /** * Public key list with sticky list headers. It does _not_ extend ListFragment because it uses * StickyListHeaders library which does not extend upon ListView. @@ -478,10 +478,6 @@ public class KeyListFragment extends LoaderFragment updateAllKeys(); return true; - case R.id.menu_key_list_debug_cons: - consolidate(); - return true; - case R.id.menu_key_list_debug_read: try { KeychainDatabase.debugBackup(getActivity(), true); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index ec6fd1bbe..51ed2b012 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -128,6 +128,11 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac getSupportFragmentManager().addOnBackStackChangedListener(this); + // all further initialization steps are saved as instance state + if (savedInstanceState != null) { + return; + } + Intent data = getIntent(); // If we got an EXTRA_RESULT in the intent, show the notification if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { @@ -135,20 +140,18 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac result.createNotify(this).show(); } - if (savedInstanceState == null) { - // always initialize keys fragment to the bottom of the backstack - onKeysSelected(); - - if (data != null && data.hasExtra(EXTRA_INIT_FRAG)) { - // initialize FragmentLayout with KeyListFragment at first - switch (data.getIntExtra(EXTRA_INIT_FRAG, -1)) { - case ID_ENCRYPT_DECRYPT: - onEnDecryptSelected(); - break; - case ID_APPS: - onAppsSelected(); - break; - } + // always initialize keys fragment to the bottom of the backstack + onKeysSelected(); + + if (data != null && data.hasExtra(EXTRA_INIT_FRAG)) { + // initialize FragmentLayout with KeyListFragment at first + switch (data.getIntExtra(EXTRA_INIT_FRAG, -1)) { + case ID_ENCRYPT_DECRYPT: + onEnDecryptSelected(); + break; + case ID_APPS: + onAppsSelected(); + break; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java new file mode 100644 index 000000000..587044659 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.util.ParcelableProxy; +import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; + +/** + * Simply encapsulates a dialog. If orbot is not installed, it shows an install dialog, else a + * dialog to enable orbot. + */ +public class OrbotRequiredDialogActivity extends FragmentActivity { + + // to provide any previous crypto input into which proxy preference is merged + public static final String EXTRA_CRYPTO_INPUT = "extra_crypto_input"; + + public static final String RESULT_CRYPTO_INPUT = "result_crypto_input"; + + private CryptoInputParcel mCryptoInputParcel; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mCryptoInputParcel = getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT); + if (mCryptoInputParcel == null) { + mCryptoInputParcel = new CryptoInputParcel(); + } + showDialog(); + } + + /** + * Displays an install or start orbot dialog depending on orbot's presence and state + */ + public void showDialog() { + DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { + public void run() { + Runnable ignoreTor = new Runnable() { + @Override + public void run() { + Intent intent = new Intent(); + mCryptoInputParcel.addParcelableProxy(ParcelableProxy.getForNoProxy()); + intent.putExtra(RESULT_CRYPTO_INPUT, mCryptoInputParcel); + setResult(RESULT_OK, intent); + finish(); + } + }; + + Runnable dialogDismissed = new Runnable() { + @Override + public void run() { + finish(); + } + }; + + if (OrbotHelper.putOrbotInRequiredState(R.string.orbot_ignore_tor, ignoreTor, dialogDismissed, + Preferences.getPreferences(OrbotRequiredDialogActivity.this) + .getProxyPrefs(), + OrbotRequiredDialogActivity.this)) { + // no action required after all + Intent intent = new Intent(); + intent.putExtra(RESULT_CRYPTO_INPUT, mCryptoInputParcel); + setResult(RESULT_OK, intent); + } + } + }); + } +}
\ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java index 2e838535d..ed96156fe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java @@ -43,7 +43,9 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -207,7 +209,7 @@ public class PassphraseWizardActivity extends FragmentActivity { // transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit(); } } catch (IOException | FormatException e) { - e.printStackTrace(); + Log.e(Constants.TAG, "Failed to write on NFC tag", e); } } else if (readNFC && AUTHENTICATION.equals(selectedAction)) { @@ -232,7 +234,7 @@ public class PassphraseWizardActivity extends FragmentActivity { } } } catch (IOException | FormatException e) { - e.printStackTrace(); + Log.e(Constants.TAG, "Failed to read NFC tag", e); } } } @@ -263,7 +265,7 @@ public class PassphraseWizardActivity extends FragmentActivity { try { password = readText(ndefRecord); } catch (UnsupportedEncodingException e) { - e.printStackTrace(); + Log.e(Constants.TAG, "Failed to read password from tag", e); } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java index 6fc0aaac6..f72a552d5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java @@ -18,14 +18,21 @@ package org.sufficientlysecure.keychain.ui; +import android.annotation.TargetApi; +import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.os.Build; import android.os.Bundle; import android.preference.CheckBoxPreference; +import android.preference.EditTextPreference; +import android.preference.ListPreference; import android.preference.Preference; +import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; import android.support.v7.widget.Toolbar; +import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; @@ -33,9 +40,11 @@ import android.widget.LinearLayout; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.AppCompatPreferenceActivity; +import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; import java.util.List; @@ -43,6 +52,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity { public static final String ACTION_PREFS_CLOUD = "org.sufficientlysecure.keychain.ui.PREFS_CLOUD"; public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV"; + public static final String ACTION_PREFS_PROXY = "org.sufficientlysecure.keychain.ui.PREFS_PROXY"; public static final int REQUEST_CODE_KEYSERVER_PREF = 0x00007005; @@ -209,9 +219,205 @@ public class SettingsActivity extends AppCompatPreferenceActivity { } } + public static class ProxyPrefsFragment extends PreferenceFragment { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + new Initializer(this).initialize(); + + } + + public static class Initializer { + private CheckBoxPreference mUseTor; + private CheckBoxPreference mUseNormalProxy; + private EditTextPreference mProxyHost; + private EditTextPreference mProxyPort; + private ListPreference mProxyType; + private PreferenceActivity mActivity; + private PreferenceFragment mFragment; + + public Initializer(PreferenceFragment fragment) { + mFragment = fragment; + } + + public Initializer(PreferenceActivity activity) { + mActivity = activity; + } + + public Preference automaticallyFindPreference(String key) { + if (mFragment != null) { + return mFragment.findPreference(key); + } else { + return mActivity.findPreference(key); + } + } + + public void initialize() { + // makes android's preference framework write to our file instead of default + // This allows us to use the "persistent" attribute to simplify code + if (mFragment != null) { + Preferences.setPreferenceManagerFileAndMode(mFragment.getPreferenceManager()); + // Load the preferences from an XML resource + mFragment.addPreferencesFromResource(R.xml.proxy_prefs); + } else { + Preferences.setPreferenceManagerFileAndMode(mActivity.getPreferenceManager()); + // Load the preferences from an XML resource + mActivity.addPreferencesFromResource(R.xml.proxy_prefs); + } + + mUseTor = (CheckBoxPreference) automaticallyFindPreference(Constants.Pref.USE_TOR_PROXY); + mUseNormalProxy = (CheckBoxPreference) automaticallyFindPreference(Constants.Pref.USE_NORMAL_PROXY); + mProxyHost = (EditTextPreference) automaticallyFindPreference(Constants.Pref.PROXY_HOST); + mProxyPort = (EditTextPreference) automaticallyFindPreference(Constants.Pref.PROXY_PORT); + mProxyType = (ListPreference) automaticallyFindPreference(Constants.Pref.PROXY_TYPE); + initializeUseTorPref(); + initializeUseNormalProxyPref(); + initializeEditTextPreferences(); + initializeProxyTypePreference(); + + if (mUseTor.isChecked()) disableNormalProxyPrefs(); + else if (mUseNormalProxy.isChecked()) disableUseTorPrefs(); + } + + private void initializeUseTorPref() { + mUseTor.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + Activity activity = mFragment != null ? mFragment.getActivity() : mActivity; + if ((Boolean) newValue) { + boolean installed = OrbotHelper.isOrbotInstalled(activity); + if (!installed) { + Log.d(Constants.TAG, "Prompting to install Tor"); + OrbotHelper.getPreferenceInstallDialogFragment().show(activity.getFragmentManager(), + "installDialog"); + // don't let the user check the box until he's installed orbot + return false; + } else { + disableNormalProxyPrefs(); + // let the enable tor box be checked + return true; + } + } else { + // we're unchecking Tor, so enable other proxy + enableNormalProxyPrefs(); + return true; + } + } + }); + } + + private void initializeUseNormalProxyPref() { + mUseNormalProxy.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if ((Boolean) newValue) { + disableUseTorPrefs(); + } else { + enableUseTorPrefs(); + } + return true; + } + }); + } + + private void initializeEditTextPreferences() { + mProxyHost.setSummary(mProxyHost.getText()); + mProxyPort.setSummary(mProxyPort.getText()); + + mProxyHost.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + Activity activity = mFragment != null ? mFragment.getActivity() : mActivity; + if (TextUtils.isEmpty((String) newValue)) { + Notify.create( + activity, + R.string.pref_proxy_host_err_invalid, + Notify.Style.ERROR + ).show(); + return false; + } else { + mProxyHost.setSummary((CharSequence) newValue); + return true; + } + } + }); + + mProxyPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + Activity activity = mFragment != null ? mFragment.getActivity() : mActivity; + try { + int port = Integer.parseInt((String) newValue); + if (port < 0 || port > 65535) { + Notify.create( + activity, + R.string.pref_proxy_port_err_invalid, + Notify.Style.ERROR + ).show(); + return false; + } + // no issues, save port + mProxyPort.setSummary("" + port); + return true; + } catch (NumberFormatException e) { + Notify.create( + activity, + R.string.pref_proxy_port_err_invalid, + Notify.Style.ERROR + ).show(); + return false; + } + } + }); + } + + private void initializeProxyTypePreference() { + mProxyType.setSummary(mProxyType.getEntry()); + + mProxyType.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + CharSequence entry = mProxyType.getEntries()[mProxyType.findIndexOfValue((String) newValue)]; + mProxyType.setSummary(entry); + return true; + } + }); + } + + private void disableNormalProxyPrefs() { + mUseNormalProxy.setChecked(false); + mUseNormalProxy.setEnabled(false); + mProxyHost.setEnabled(false); + mProxyPort.setEnabled(false); + mProxyType.setEnabled(false); + } + + private void enableNormalProxyPrefs() { + mUseNormalProxy.setEnabled(true); + mProxyHost.setEnabled(true); + mProxyPort.setEnabled(true); + mProxyType.setEnabled(true); + } + + private void disableUseTorPrefs() { + mUseTor.setChecked(false); + mUseTor.setEnabled(false); + } + + private void enableUseTorPrefs() { + mUseTor.setEnabled(true); + } + } + + } + + @TargetApi(Build.VERSION_CODES.KITKAT) protected boolean isValidFragment(String fragmentName) { return AdvancedPrefsFragment.class.getName().equals(fragmentName) || CloudSearchPrefsFragment.class.getName().equals(fragmentName) + || ProxyPrefsFragment.class.getName().equals(fragmentName) || super.isValidFragment(fragmentName); } @@ -270,7 +476,8 @@ public class SettingsActivity extends AppCompatPreferenceActivity { String[] servers = sPreferences.getKeyServers(); String serverSummary = context.getResources().getQuantityString( R.plurals.n_keyservers, servers.length, servers.length); - return serverSummary + "; " + context.getString(R.string.label_preferred) + ": " + sPreferences.getPreferredKeyserver(); + return serverSummary + "; " + context.getString(R.string.label_preferred) + ": " + sPreferences + .getPreferredKeyserver(); } private static void initializeUseDefaultYubiKeyPin(final CheckBoxPreference mUseDefaultYubiKeyPin) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java index 8b49f3b96..703a85b0f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -26,7 +26,6 @@ import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Spinner; -import android.widget.Toast; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -38,6 +37,7 @@ import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; /** * Sends the selected public key to a keyserver @@ -132,8 +132,7 @@ public class UploadKeyActivity extends BaseActivity @Override public void onCryptoOperationSuccess(ExportResult result) { - Toast.makeText(UploadKeyActivity.this, R.string.msg_crt_upload_success, - Toast.LENGTH_SHORT).show(); + result.createNotify(this).show(); } @Override @@ -143,7 +142,7 @@ public class UploadKeyActivity extends BaseActivity @Override public void onCryptoOperationError(ExportResult result) { - // TODO: Implement proper log for key upload then show error + result.createNotify(this).show(); } @Override 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 27832b665..ce8935bce 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -84,7 +84,9 @@ import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.util.ExportHelper; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.NfcHelper; +import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; import java.io.IOException; import java.util.ArrayList; @@ -464,11 +466,11 @@ public class ViewKeyActivity extends BaseNfcActivity implements HashMap<String, Object> data = providerHelper.getGenericData( baseUri, - new String[] {KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET}, - new int[] {ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER}); + new String[]{KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET}, + new int[]{ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER}); exportHelper.showExportKeysDialog( - new long[] {(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)}, + new long[]{(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)}, Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) != 0) ); } catch (ProviderHelper.NotFoundException e) { @@ -492,7 +494,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements // Create a new Messenger for the communication back Messenger messenger = new Messenger(returnHandler); DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, - new long[] {mMasterKeyId}); + new long[]{mMasterKeyId}); deleteKeyDialog.show(getSupportFragmentManager(), "deleteKeyDialog"); } @@ -636,7 +638,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements long keyId = new ProviderHelper(this) .getCachedPublicKeyRing(dataUri) .extractOrGetMasterKeyId(); - long[] encryptionKeyIds = new long[] {keyId}; + long[] encryptionKeyIds = new long[]{keyId}; Intent intent; if (text) { intent = new Intent(this, EncryptTextActivity.class); @@ -742,7 +744,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements // These are the rows that we will retrieve. - static final String[] PROJECTION = new String[] { + static final String[] PROJECTION = new String[]{ KeychainContract.KeyRings._ID, KeychainContract.KeyRings.MASTER_KEY_ID, KeychainContract.KeyRings.USER_ID, @@ -830,7 +832,8 @@ public class ViewKeyActivity extends BaseNfcActivity implements AsyncTask<Long, Void, Bitmap> photoTask = new AsyncTask<Long, Void, Bitmap>() { protected Bitmap doInBackground(Long... mMasterKeyId) { - return ContactHelper.loadPhotoByMasterKeyId(getContentResolver(), mMasterKeyId[0], true); + return ContactHelper.loadPhotoByMasterKeyId(getContentResolver(), + mMasterKeyId[0], true); } protected void onPostExecute(Bitmap photo) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java index b44e6dc78..f46b30137 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java @@ -25,6 +25,9 @@ import java.io.OutputStreamWriter; import android.app.Activity; import android.app.ActivityOptions; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; @@ -49,7 +52,6 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract; @@ -58,6 +60,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.NfcHelper; @@ -197,7 +200,15 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements } if (toClipboard) { - ClipboardReflection.copyToClipboard(activity, content); + ClipboardManager clipMan = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE); + if (clipMan == null) { + Notify.create(activity, R.string.error_clipboard_copy, Style.ERROR); + return; + } + + ClipData clip = ClipData.newPlainText(Constants.CLIPBOARD_LABEL, content); + clipMan.setPrimaryClip(clip); + Notify.create(activity, fingerprintOnly ? R.string.fingerprint_copied_to_clipboard : R.string.key_copied_to_clipboard, Notify.Style.OK).show(); return; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java index 6052eec16..40cbba5b3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java @@ -51,6 +51,9 @@ import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ParcelableProxy; +import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; import java.util.ArrayList; import java.util.Hashtable; @@ -197,8 +200,22 @@ public class ViewKeyTrustFragment extends LoaderFragment implements mStartSearch.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - mStartSearch.setEnabled(false); - new DescribeKey().execute(fingerprint); + final Preferences.ProxyPrefs proxyPrefs = Preferences.getPreferences(getActivity()) + .getProxyPrefs(); + + Runnable ignoreTor = new Runnable() { + @Override + public void run() { + mStartSearch.setEnabled(false); + new DescribeKey(proxyPrefs.parcelableProxy).execute(fingerprint); + } + }; + + if (OrbotHelper.putOrbotInRequiredState(R.string.orbot_ignore_tor, ignoreTor, proxyPrefs, + getActivity())) { + mStartSearch.setEnabled(false); + new DescribeKey(proxyPrefs.parcelableProxy).execute(fingerprint); + } } }); } @@ -229,6 +246,11 @@ public class ViewKeyTrustFragment extends LoaderFragment implements // look for evidence from keybase in the background, make tabular version of result // private class DescribeKey extends AsyncTask<String, Void, ResultPage> { + ParcelableProxy mParcelableProxy; + + public DescribeKey(ParcelableProxy parcelableProxy) { + mParcelableProxy = parcelableProxy; + } @Override protected ResultPage doInBackground(String... args) { @@ -237,7 +259,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements final ArrayList<CharSequence> proofList = new ArrayList<CharSequence>(); final Hashtable<Integer, ArrayList<Proof>> proofs = new Hashtable<Integer, ArrayList<Proof>>(); try { - User keybaseUser = User.findByFingerprint(fingerprint); + User keybaseUser = User.findByFingerprint(fingerprint, mParcelableProxy.getProxy()); for (Proof proof : keybaseUser.getProofs()) { Integer proofType = proof.getType(); appendIfOK(proofs, proofType, proof); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java index f8c3b59ea..c2158650b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java @@ -210,7 +210,7 @@ public class ViewKeyYubiKeyFragment } @Override - protected void onCryptoOperationResult(PromoteKeyResult result) { + public void onCryptoOperationSuccess(PromoteKeyResult result) { result.createNotify(getActivity()).show(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java index af919f3b6..c7f69207c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java @@ -27,6 +27,7 @@ import org.sufficientlysecure.keychain.keyimport.Keyserver; import org.sufficientlysecure.keychain.operations.results.GetKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.Preferences; import java.util.ArrayList; @@ -38,15 +39,18 @@ public class ImportKeysListCloudLoader Preferences.CloudSearchPrefs mCloudPrefs; String mServerQuery; + private ParcelableProxy mParcelableProxy; private ArrayList<ImportKeysListEntry> mEntryList = new ArrayList<>(); private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper; - public ImportKeysListCloudLoader(Context context, String serverQuery, Preferences.CloudSearchPrefs cloudPrefs) { + public ImportKeysListCloudLoader(Context context, String serverQuery, Preferences.CloudSearchPrefs cloudPrefs, + ParcelableProxy proxy) { super(context); mContext = context; mServerQuery = serverQuery; mCloudPrefs = cloudPrefs; + mParcelableProxy = proxy; } @Override @@ -96,8 +100,11 @@ public class ImportKeysListCloudLoader */ private void queryServer(boolean enforceFingerprint) { try { - ArrayList<ImportKeysListEntry> searchResult - = CloudSearch.search(mServerQuery, mCloudPrefs); + ArrayList<ImportKeysListEntry> searchResult = CloudSearch.search( + mServerQuery, + mCloudPrefs, + mParcelableProxy.getProxy() + ); mEntryList.clear(); // add result to data diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java index 17e4e6ede..95bc4adcb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java @@ -31,8 +31,12 @@ public abstract class CachingCryptoOperationFragment <T extends Parcelable, S ex } @Override - protected void onCryptoOperationResult(S result) { - super.onCryptoOperationResult(result); + public void onCryptoOperationSuccess(S result) { + mCachedActionsParcel = null; + } + + @Override + public void onCryptoOperationError(S result) { mCachedActionsParcel = null; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java index 115f52d56..2ab0d5fac 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java @@ -20,56 +20,88 @@ package org.sufficientlysecure.keychain.ui.base; import android.content.Intent; import android.os.Parcelable; +import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.service.KeychainService; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; -/** - * All fragments executing crypto operations need to extend this class. +/** This is a base class for fragments which implement a cryptoOperation. + * + * Subclasses of this class can call the cryptoOperation method to execute an + * operation in KeychainService which takes a parcelable of type T as its input + * and returns an OperationResult of type S as a result. + * + * The input (of type T) is not given directly to the cryptoOperation method, + * but must be provided by the overriden createOperationInput method to be + * available upon request during execution of the cryptoOperation. + * + * After running cryptoOperation, one of the onCryptoOperation*() methods will + * be called, depending on the success status of the operation. The subclass + * must override at least onCryptoOperationSuccess to proceed after a + * successful operation. + * + * @see KeychainService + * */ public abstract class CryptoOperationFragment<T extends Parcelable, S extends OperationResult> extends Fragment implements CryptoOperationHelper.Callback<T, S> { - private CryptoOperationHelper<T, S> mOperationHelper; + final private CryptoOperationHelper<T, S> mOperationHelper; public CryptoOperationFragment() { mOperationHelper = new CryptoOperationHelper<>(this, this); } - public void setProgressMessageResource(int id) { - mOperationHelper.setProgressMessageResource(id); - } - - @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { mOperationHelper.handleActivityResult(requestCode, resultCode, data); } - @Override - public abstract T createOperationInput(); - + /** Starts execution of the cryptographic operation. + * + * During this process, the createOperationInput() method will be called, + * this input will be handed to KeychainService, where it is executed in + * the appropriate *Operation class. If the result is a PendingInputResult, + * it is handled accordingly. Otherwise, it is returned in one of the + * onCryptoOperation* callbacks. + */ protected void cryptoOperation() { - cryptoOperation(new CryptoInputParcel()); + mOperationHelper.cryptoOperation(); } protected void cryptoOperation(CryptoInputParcel cryptoInput) { - cryptoOperation(cryptoInput, true); + mOperationHelper.cryptoOperation(cryptoInput); } protected void cryptoOperation(CryptoInputParcel cryptoInput, boolean showProgress) { mOperationHelper.cryptoOperation(cryptoInput, showProgress); } + @Override @Nullable + /** Creates input for the crypto operation. Called internally after the + * crypto operation is started by a call to cryptoOperation(). Silently + * cancels operation if this method returns null. */ + public abstract T createOperationInput(); + + /** Returns false, indicating that we did not handle progress ourselves. */ public boolean onCryptoSetProgress(String msg, int progress, int max) { return false; } + public void setProgressMessageResource(int id) { + mOperationHelper.setProgressMessageResource(id); + } + + @Override + /** Called when the cryptoOperation() was successful. No default behavior + * here, this should always be implemented by a subclass! */ + abstract public void onCryptoOperationSuccess(S result); + @Override public void onCryptoOperationError(S result) { - onCryptoOperationResult(result); result.createNotify(getActivity()).show(); } @@ -77,19 +109,4 @@ public abstract class CryptoOperationFragment<T extends Parcelable, S extends Op public void onCryptoOperationCancelled() { } - @Override - public void onCryptoOperationSuccess(S result) { - onCryptoOperationResult(result); - } - - /** - * - * To be overriden by subclasses, if desired. Provides a way to access the method by the - * same name in CryptoOperationHelper, if super.onCryptoOperationSuccess and - * super.onCryptoOperationError are called at the start of the respective functions in the - * subclass overriding them - * @param result - */ - protected void onCryptoOperationResult(S result) { - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java index 240dd0972..8d141ea5d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java @@ -28,8 +28,8 @@ import android.os.Messenger; import android.os.Parcelable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; - import android.support.v4.app.FragmentManager; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.InputPendingResult; @@ -39,6 +39,7 @@ import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.NfcOperationActivity; +import org.sufficientlysecure.keychain.ui.OrbotRequiredDialogActivity; import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.util.Log; @@ -52,16 +53,21 @@ import org.sufficientlysecure.keychain.util.Log; */ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResult> { - public interface Callback <T extends Parcelable, S extends OperationResult> { + public interface Callback<T extends Parcelable, S extends OperationResult> { T createOperationInput(); + void onCryptoOperationSuccess(S result); + void onCryptoOperationCancelled(); + void onCryptoOperationError(S result); + boolean onCryptoSetProgress(String msg, int progress, int max); } public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; public static final int REQUEST_CODE_NFC = 0x00008002; + public static final int REQUEST_CODE_ENABLE_ORBOT = 0x00008004; // keeps track of request code used to start an activity from this CryptoOperationHelper. // this is necessary when multiple CryptoOperationHelpers are used in the same fragment/activity @@ -78,8 +84,6 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu /** * If OperationHelper is being integrated into an activity - * - * @param activity */ public CryptoOperationHelper(FragmentActivity activity, Callback<T, S> callback, int progressMessageString) { mActivity = activity; @@ -90,8 +94,6 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu /** * if OperationHelper is being integrated into a fragment - * - * @param fragment */ public CryptoOperationHelper(Fragment fragment, Callback<T, S> callback, int progressMessageString) { mFragment = fragment; @@ -102,8 +104,6 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu /** * if OperationHelper is being integrated into a fragment with default message for the progress dialog - * - * @param fragment */ public CryptoOperationHelper(Fragment fragment, Callback<T, S> callback) { mFragment = fragment; @@ -116,11 +116,14 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu mProgressMessageResource = id; } - private void initiateInputActivity(RequiredInputParcel requiredInput) { + private void initiateInputActivity(RequiredInputParcel requiredInput, + CryptoInputParcel cryptoInputParcel) { Activity activity = mUseFragment ? mFragment.getActivity() : mActivity; switch (requiredInput.mType) { + // TODO: Verify that all started activities add to cryptoInputParcel if necessary (like OrbotRequiredDialogActivity) + // don't forget to set mRequestedCode! case NFC_MOVE_KEY_TO_CARD: case NFC_DECRYPT: case NFC_SIGN: { @@ -130,7 +133,7 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu if (mUseFragment) { mFragment.startActivityForResult(intent, mRequestedCode); } else { - mActivity.startActivityForResult(intent, mRequestedCode); + activity.startActivityForResult(intent, mRequestedCode); } return; } @@ -143,22 +146,32 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu if (mUseFragment) { mFragment.startActivityForResult(intent, mRequestedCode); } else { - mActivity.startActivityForResult(intent, mRequestedCode); + activity.startActivityForResult(intent, mRequestedCode); } return; } - } - throw new RuntimeException("Unhandled pending result!"); + case ENABLE_ORBOT: { + Intent intent = new Intent(activity, OrbotRequiredDialogActivity.class); + intent.putExtra(OrbotRequiredDialogActivity.EXTRA_CRYPTO_INPUT, cryptoInputParcel); + mRequestedCode = REQUEST_CODE_ENABLE_ORBOT; + if (mUseFragment) { + mFragment.startActivityForResult(intent, mRequestedCode); + } else { + activity.startActivityForResult(intent, mRequestedCode); + } + return; + } + + default: { + throw new RuntimeException("Unhandled pending result!"); + } + } } /** - * Attempts the result of an activity started by this helper. Returns true if requestCode is recognized, - * false otherwise. - * - * @param requestCode - * @param resultCode - * @param data + * Attempts the result of an activity started by this helper. Returns true if requestCode is + * recognized, false otherwise. * @return true if requestCode was recognized, false otherwise */ public boolean handleActivityResult(int requestCode, int resultCode, Intent data) { @@ -196,6 +209,16 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu break; } + case REQUEST_CODE_ENABLE_ORBOT: { + if (resultCode == Activity.RESULT_OK && data != null) { + CryptoInputParcel cryptoInput = + data.getParcelableExtra( + OrbotRequiredDialogActivity.RESULT_CRYPTO_INPUT); + cryptoOperation(cryptoInput); + return true; + } + } + default: { return false; } @@ -225,7 +248,7 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu } - public void cryptoOperation(CryptoInputParcel cryptoInput, boolean showProgress) { + public void cryptoOperation(final CryptoInputParcel cryptoInput, boolean showProgress) { FragmentActivity activity = mUseFragment ? mFragment.getActivity() : mActivity; @@ -257,14 +280,14 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu final OperationResult result = returnData.getParcelable(OperationResult.EXTRA_RESULT); - onHandleResult(result); + onHandleResult(result, cryptoInput); } } @Override protected void onSetProgress(String msg, int progress, int max) { // allow handling of progress in fragment, or delegate upwards - if ( ! mCallback.onCryptoSetProgress(msg, progress, max)) { + if (!mCallback.onCryptoSetProgress(msg, progress, max)) { super.onSetProgress(msg, progress, max); } } @@ -291,15 +314,7 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu cryptoOperation(new CryptoInputParcel()); } - protected void onCryptoOperationResult(S result) { - if (result.success()) { - mCallback.onCryptoOperationSuccess(result); - } else { - mCallback.onCryptoOperationError(result); - } - } - - public void onHandleResult(OperationResult result) { + public void onHandleResult(OperationResult result, CryptoInputParcel oldCryptoInput) { Log.d(Constants.TAG, "Handling result in OperationHelper success: " + result.success()); if (result instanceof InputPendingResult) { @@ -307,7 +322,7 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu if (pendingResult.isPending()) { RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel(); - initiateInputActivity(requiredInput); + initiateInputActivity(requiredInput, oldCryptoInput); return; } } @@ -315,8 +330,13 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu dismissProgress(); try { - // noinspection unchecked, because type erasure :( - onCryptoOperationResult((S) result); + if (result.success()) { + // noinspection unchecked, because type erasure :( + mCallback.onCryptoOperationSuccess((S) result); + } else { + // noinspection unchecked, because type erasure :( + mCallback.onCryptoOperationError((S) result); + } } catch (ClassCastException e) { throw new AssertionError("bad return class (" + result.getClass().getSimpleName() + "), this is a programming error!"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java index 321242b2f..b8d93dc00 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java @@ -48,10 +48,17 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.TlsHelper; +import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; + +import java.net.Proxy; public class AddEditKeyserverDialogFragment extends DialogFragment implements OnEditorActionListener { private static final String ARG_MESSENGER = "arg_messenger"; @@ -205,9 +212,21 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On @Override public void onClick(View v) { // behaviour same for edit and add - String keyserverUrl = mKeyserverEditText.getText().toString(); + final String keyserverUrl = mKeyserverEditText.getText().toString(); if (mVerifyKeyserverCheckBox.isChecked()) { - verifyConnection(keyserverUrl); + final Preferences.ProxyPrefs proxyPrefs = Preferences.getPreferences(getActivity()) + .getProxyPrefs(); + Runnable ignoreTor = new Runnable() { + @Override + public void run() { + verifyConnection(keyserverUrl, null); + } + }; + + if (OrbotHelper.putOrbotInRequiredState(R.string.orbot_ignore_tor, ignoreTor, proxyPrefs, + getActivity())) { + verifyConnection(keyserverUrl, proxyPrefs.parcelableProxy.getProxy()); + } } else { dismiss(); // return unverified keyserver back to activity @@ -249,7 +268,7 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On sendMessageToHandler(MESSAGE_VERIFICATION_FAILED, data); } - public void verifyConnection(String keyserver) { + public void verifyConnection(String keyserver, final Proxy proxy) { new AsyncTask<String, Void, FailureReason>() { ProgressDialog mProgressDialog; @@ -283,10 +302,11 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On } URI newKeyserver = new URI(scheme, schemeSpecificPart, fragment); - Log.d(Constants.TAG, "Converted URL" + newKeyserver); + Log.d("Converted URL", newKeyserver.toString()); - // just see if we can get a connection, then immediately close - TlsHelper.openConnection(newKeyserver.toURL()).getInputStream().close(); + OkHttpClient client = HkpKeyserver.getClient(newKeyserver.toURL(), proxy); + TlsHelper.pinCertificateIfNecessary(client, newKeyserver.toURL()); + client.newCall(new Request.Builder().url(newKeyserver.toURL()).build()).execute(); } catch (TlsHelper.TlsHelperException e) { reason = FailureReason.CONNECTION_FAILED; } catch (MalformedURLException | URISyntaxException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/OrbotStartDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/OrbotStartDialogFragment.java new file mode 100644 index 000000000..dd7d2256a --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/OrbotStartDialogFragment.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2012-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.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.support.v4.app.DialogFragment; +import android.view.ContextThemeWrapper; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; + +/** + * displays a dialog asking the user to enable Tor + */ +public class OrbotStartDialogFragment extends DialogFragment { + private static final String ARG_MESSENGER = "messenger"; + private static final String ARG_TITLE = "title"; + private static final String ARG_MESSAGE = "message"; + private static final String ARG_MIDDLE_BUTTON = "middleButton"; + + public static final int MESSAGE_MIDDLE_BUTTON = 1; + public static final int MESSAGE_DIALOG_DISMISSED = 2; // for either cancel or enable pressed + + public static OrbotStartDialogFragment newInstance(Messenger messenger, int title, int message, int middleButton) { + Bundle args = new Bundle(); + args.putParcelable(ARG_MESSENGER, messenger); + args.putInt(ARG_TITLE, title); + args.putInt(ARG_MESSAGE, message); + args.putInt(ARG_MIDDLE_BUTTON, middleButton); + + OrbotStartDialogFragment fragment = new OrbotStartDialogFragment(); + fragment.setArguments(args); + + return fragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + + final Messenger messenger = getArguments().getParcelable(ARG_MESSENGER); + int title = getArguments().getInt(ARG_TITLE); + final int message = getArguments().getInt(ARG_MESSAGE); + int middleButton = getArguments().getInt(ARG_MIDDLE_BUTTON); + final Activity activity = getActivity(); + + // if the dialog is displayed from the application class, design is missing. + // hack to get holo design (which is not automatically applied due to activity's + // Theme.NoDisplay) + ContextThemeWrapper theme = new ContextThemeWrapper(activity, + R.style.Theme_AppCompat_Light_Dialog); + + CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(theme); + builder.setTitle(title).setMessage(message); + + builder.setNegativeButton(R.string.orbot_start_dialog_cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Message msg = Message.obtain(); + msg.what = MESSAGE_DIALOG_DISMISSED; + try { + messenger.send(msg); + } catch (RemoteException e) { + Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); + } catch (NullPointerException e) { + Log.w(Constants.TAG, "Messenger is null!", e); + } + + } + }); + + builder.setPositiveButton(R.string.orbot_start_dialog_start, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + getActivity().startActivityForResult(OrbotHelper.getOrbotStartIntent(), 1); + + Message msg = Message.obtain(); + msg.what = MESSAGE_DIALOG_DISMISSED; + try { + messenger.send(msg); + } catch (RemoteException e) { + Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); + } catch (NullPointerException e) { + Log.w(Constants.TAG, "Messenger is null!", e); + } + } + }); + + builder.setNeutralButton(middleButton, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Message msg = new Message(); + msg.what = MESSAGE_MIDDLE_BUTTON; + try { + messenger.send(msg); + } catch (RemoteException e) { + Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); + } catch (NullPointerException e) { + Log.w(Constants.TAG, "Messenger is null!", e); + } + } + }); + + return builder.show(); + } +}
\ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PreferenceInstallDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PreferenceInstallDialogFragment.java new file mode 100644 index 000000000..3f8bce28b --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PreferenceInstallDialogFragment.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012-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.dialog; + +import android.app.Dialog; +import android.os.Bundle; +import android.os.Messenger; +import android.app.DialogFragment; + +import org.sufficientlysecure.keychain.ui.util.InstallDialogFragmentHelper; + +public class PreferenceInstallDialogFragment extends DialogFragment { + + public static final int MESSAGE_MIDDLE_CLICKED = 1; + public static final int MESSAGE_DIALOG_DISMISSED = 2; + + /** + * Creates a dialog which prompts the user to install an application. Consists of two default buttons ("Install" + * and "Cancel") and an optional third button. Callbacks are provided only for the middle button, if set. + * + * @param messenger required only for callback from middle button if it has been set + * @param title + * @param message content of dialog + * @param packageToInstall package name of application to install + * @param middleButton if not null, adds a third button to the app with a call back + * @return The dialog to display + */ + public static PreferenceInstallDialogFragment newInstance(Messenger messenger, int title, int message, + String packageToInstall, int middleButton, boolean + useMiddleButton) { + PreferenceInstallDialogFragment frag = new PreferenceInstallDialogFragment(); + Bundle args = new Bundle(); + + InstallDialogFragmentHelper.wrapIntoArgs(messenger, title, message, packageToInstall, middleButton, + useMiddleButton, args); + + frag.setArguments(args); + + return frag; + } + + /** + * To create a DialogFragment with only two buttons + * + * @param title + * @param message + * @param packageToInstall + * @return + */ + public static PreferenceInstallDialogFragment newInstance(int title, int message, + String packageToInstall) { + return newInstance(null, title, message, packageToInstall, -1, false); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return InstallDialogFragmentHelper.getInstallDialogFromArgs(getArguments(), getActivity(), + MESSAGE_MIDDLE_CLICKED, MESSAGE_DIALOG_DISMISSED); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SupportInstallDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SupportInstallDialogFragment.java new file mode 100644 index 000000000..b2b71b364 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SupportInstallDialogFragment.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012-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.dialog; + +import android.app.Dialog; +import android.os.Bundle; +import android.os.Messenger; +import android.support.v4.app.DialogFragment; + +import org.sufficientlysecure.keychain.ui.util.InstallDialogFragmentHelper; + +public class SupportInstallDialogFragment extends DialogFragment { + + public static final int MESSAGE_MIDDLE_CLICKED = 1; + public static final int MESSAGE_DIALOG_DISMISSED = 2; + + /** + * Creates a dialog which prompts the user to install an application. Consists of two default buttons ("Install" + * and "Cancel") and an optional third button. Callbacks are provided only for the middle button, if set. + * + * @param messenger required only for callback from middle button if it has been set + * @param title + * @param message content of dialog + * @param packageToInstall package name of application to install + * @param middleButton if not null, adds a third button to the app with a call back + * @return The dialog to display + */ + public static SupportInstallDialogFragment newInstance(Messenger messenger, int title, int message, + String packageToInstall, int middleButton, boolean + useMiddleButton) { + SupportInstallDialogFragment frag = new SupportInstallDialogFragment(); + Bundle args = new Bundle(); + + InstallDialogFragmentHelper.wrapIntoArgs(messenger, title, message, packageToInstall, middleButton, + useMiddleButton, args); + + frag.setArguments(args); + + return frag; + } + + /** + * To create a DialogFragment with only two buttons + * + * @param title + * @param message + * @param packageToInstall + * @return + */ + public static SupportInstallDialogFragment newInstance(int title, int message, + String packageToInstall) { + return newInstance(null, title, message, packageToInstall, -1, false); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + + return InstallDialogFragmentHelper.getInstallDialogFromArgs(getArguments(), getActivity(), + MESSAGE_MIDDLE_CLICKED, MESSAGE_DIALOG_DISMISSED); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/InstallDialogFragmentHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/InstallDialogFragmentHelper.java new file mode 100644 index 000000000..f21d69c48 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/InstallDialogFragmentHelper.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2012-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.util; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.view.ContextThemeWrapper; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; +import org.sufficientlysecure.keychain.util.Log; + +public class InstallDialogFragmentHelper { + private static final String ARG_MESSENGER = "messenger"; + private static final String ARG_TITLE = "title"; + private static final String ARG_MESSAGE = "message"; + private static final String ARG_MIDDLE_BUTTON = "middleButton"; + private static final String ARG_INSTALL_PATH = "installPath"; + private static final String ARG_USE_MIDDLE_BUTTON = "useMiddleButton"; + + private static final String PLAY_STORE_PATH = "market://search?q=pname:"; + + public static void wrapIntoArgs(Messenger messenger, int title, int message, String packageToInstall, + int middleButton, boolean useMiddleButton, Bundle args) { + args.putParcelable(ARG_MESSENGER, messenger); + + args.putInt(ARG_TITLE, title); + args.putInt(ARG_MESSAGE, message); + args.putInt(ARG_MIDDLE_BUTTON, middleButton); + args.putString(ARG_INSTALL_PATH, PLAY_STORE_PATH + packageToInstall); + args.putBoolean(ARG_USE_MIDDLE_BUTTON, useMiddleButton); + } + + public static AlertDialog getInstallDialogFromArgs(Bundle args, final Activity activity, + final int messengerMiddleButtonClicked, + final int messengerDialogDimissed) { + final Messenger messenger = args.getParcelable(ARG_MESSENGER); + + final int title = args.getInt(ARG_TITLE); + final int message = args.getInt(ARG_MESSAGE); + final int middleButton = args.getInt(ARG_MIDDLE_BUTTON); + final String installPath = args.getString(ARG_INSTALL_PATH); + final boolean useMiddleButton = args.getBoolean(ARG_USE_MIDDLE_BUTTON); + + // if the dialog is displayed from the application class, design is missing. + // hack to get holo design (which is not automatically applied due to activity's + // Theme.NoDisplay) + ContextThemeWrapper theme = new ContextThemeWrapper(activity, + R.style.Theme_AppCompat_Light_Dialog); + CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(theme); + + builder.setTitle(title).setMessage(message); + + builder.setNegativeButton(R.string.orbot_install_dialog_cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Message msg = Message.obtain(); + msg.what = messengerDialogDimissed; + try { + messenger.send(msg); + } catch (RemoteException e) { + Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); + } catch (NullPointerException e) { + Log.w(Constants.TAG, "Messenger is null!", e); + } + } + }); + + builder.setPositiveButton(R.string.orbot_install_dialog_install, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Uri uri = Uri.parse(installPath); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + activity.startActivity(intent); + + Message msg = Message.obtain(); + msg.what = messengerDialogDimissed; + try { + messenger.send(msg); + } catch (RemoteException e) { + Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); + } catch (NullPointerException e) { + Log.w(Constants.TAG, "Messenger is null!", e); + } + } + } + ); + + if (useMiddleButton) { + builder.setNeutralButton(middleButton, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Message msg = Message.obtain(); + msg.what = messengerMiddleButtonClicked; + try { + messenger.send(msg); + } catch (RemoteException e) { + Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); + } catch (NullPointerException e) { + Log.w(Constants.TAG, "Messenger is null!", e); + } + } + } + ); + } + + return builder.show(); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java index 0ec145657..30bdfb92a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java @@ -31,7 +31,9 @@ import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Log; /** * Created by Matt Allen |