From e663dadc32633dc12f846539196276265ccc3534 Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Fri, 18 Apr 2014 12:44:42 -0700 Subject: can search openkeychain, retrieve & install & use keys from there --- .../keychain/service/KeychainIntentService.java | 53 +++++++ .../keychain/ui/ImportKeysActivity.java | 41 ++++- .../keychain/ui/ImportKeysClipboardFragment.java | 2 +- .../keychain/ui/ImportKeysFileFragment.java | 2 +- .../keychain/ui/ImportKeysKeybaseFragment.java | 108 +++++++++++++ .../keychain/ui/ImportKeysListFragment.java | 52 ++++++- .../keychain/ui/ImportKeysQrCodeFragment.java | 4 +- .../keychain/ui/ImportKeysServerFragment.java | 2 +- .../keychain/ui/adapter/ImportKeysListEntry.java | 2 +- .../ui/adapter/ImportKeysListKeybaseLoader.java | 109 +++++++++++++ .../sufficientlysecure/keychain/util/JWalk.java | 56 +++++++ .../keychain/util/KeybaseKeyServer.java | 173 +++++++++++++++++++++ 12 files changed, 592 insertions(+), 12 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysKeybaseFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 5615b59c4..fcd31b2fe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -56,6 +56,8 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.util.HkpKeyServer; import org.sufficientlysecure.keychain.util.InputData; +import org.sufficientlysecure.keychain.util.KeyServer; +import org.sufficientlysecure.keychain.util.KeybaseKeyServer; import org.sufficientlysecure.keychain.util.KeychainServiceListener; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressScaler; @@ -103,6 +105,7 @@ public class KeychainIntentService extends IntentService public static final String ACTION_UPLOAD_KEYRING = Constants.INTENT_PREFIX + "UPLOAD_KEYRING"; public static final String ACTION_DOWNLOAD_AND_IMPORT_KEYS = Constants.INTENT_PREFIX + "QUERY_KEYRING"; + public static final String ACTION_IMPORT_KEYBASE_KEYS = Constants.INTENT_PREFIX + "DOWNLOAD_KEYBASE"; public static final String ACTION_CERTIFY_KEYRING = Constants.INTENT_PREFIX + "SIGN_KEYRING"; @@ -739,6 +742,56 @@ public class KeychainIntentService extends IntentService } catch (Exception e) { sendErrorToHandler(e); } + } else if (ACTION_IMPORT_KEYBASE_KEYS.equals(action)) { + ArrayList entries = data.getParcelableArrayList(DOWNLOAD_KEY_LIST); + + try { + KeybaseKeyServer server = new KeybaseKeyServer(); + for (ImportKeysListEntry entry : entries) { + // the keybase handle is in userId(1) + String username = entry.getUserIds().get(1); + byte[] downloadedKeyBytes = server.get(username).getBytes(); + + // create PGPKeyRing object based on downloaded armored key + PGPKeyRing downloadedKey = null; + BufferedInputStream bufferedInput = + new BufferedInputStream(new ByteArrayInputStream(downloadedKeyBytes)); + if (bufferedInput.available() > 0) { + InputStream in = PGPUtil.getDecoderStream(bufferedInput); + PGPObjectFactory objectFactory = new PGPObjectFactory(in); + + // get first object in block + Object obj; + if ((obj = objectFactory.nextObject()) != null) { + Log.d(Constants.TAG, "Found class: " + obj.getClass()); + + if (obj instanceof PGPKeyRing) { + downloadedKey = (PGPKeyRing) obj; + } else { + throw new PgpGeneralException("Object not recognized as PGPKeyRing!"); + } + } + } + + // save key bytes in entry object for doing the + // actual import afterwards + entry.setBytes(downloadedKey.getEncoded()); + } + + Intent importIntent = new Intent(this, KeychainIntentService.class); + importIntent.setAction(ACTION_IMPORT_KEYRING); + Bundle importData = new Bundle(); + importData.putParcelableArrayList(IMPORT_KEY_LIST, entries); + importIntent.putExtra(EXTRA_DATA, importData); + importIntent.putExtra(EXTRA_MESSENGER, mMessenger); + + // now import it with this service + onHandleIntent(importIntent); + + // result is handled in ACTION_IMPORT_KEYRING + } catch (Exception e) { + sendErrorToHandler(e); + } } else if (ACTION_DOWNLOAD_AND_IMPORT_KEYS.equals(action)) { try { ArrayList entries = data.getParcelableArrayList(DOWNLOAD_KEY_LIST); 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 0fccd668f..650e51069 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -62,6 +62,8 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O + "IMPORT_KEY_FROM_KEYSERVER"; public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN = Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_KEY_SERVER_AND_RETURN"; + public static final String ACTION_IMPORT_KEY_FROM_KEYBASE = Constants.INTENT_PREFIX + + "IMPORT_KEY_FROM_KEYBASE"; // Actions for internal use only: public static final String ACTION_IMPORT_KEY_FROM_FILE = Constants.INTENT_PREFIX @@ -92,13 +94,15 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O ImportKeysFileFragment.class, ImportKeysQrCodeFragment.class, ImportKeysClipboardFragment.class, - ImportKeysNFCFragment.class + ImportKeysNFCFragment.class, + ImportKeysKeybaseFragment.class }; private static final int NAV_SERVER = 0; private static final int NAV_FILE = 1; private static final int NAV_QR_CODE = 2; private static final int NAV_CLIPBOARD = 3; private static final int NAV_NFC = 4; + private static final int NAV_KEYBASE = 5; private int mCurrentNavPosition = -1; @@ -236,6 +240,12 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O // NOTE: this only displays the appropriate fragment, no actions are taken loadNavFragment(NAV_NFC, null); + // no immediate actions! + startListFragment(savedInstanceState, null, null, null); + } else if (ACTION_IMPORT_KEY_FROM_KEYBASE.equals(action)) { + // NOTE: this only displays the appropriate fragment, no actions are taken + loadNavFragment(NAV_KEYBASE, null); + // no immediate actions! startListFragment(savedInstanceState, null, null, null); } else { @@ -340,8 +350,8 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O startListFragment(savedInstanceState, null, null, query); } - public void loadCallback(byte[] importData, Uri dataUri, String serverQuery, String keyServer) { - mListFragment.loadNew(importData, dataUri, serverQuery, keyServer); + public void loadCallback(byte[] importData, Uri dataUri, String serverQuery, String keyServer, String keybaseQuery) { + mListFragment.loadNew(importData, dataUri, serverQuery, keyServer, keybaseQuery); } /** @@ -449,6 +459,31 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O // start service with intent startService(intent); + } else if (mListFragment.getKeybaseQuery() != null) { + // Send all information needed to service to query keys in other thread + Intent intent = new Intent(this, KeychainIntentService.class); + + intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYBASE_KEYS); + + // fill values for this action + Bundle data = new Bundle(); + + // get selected key entries + ArrayList selectedEntries = mListFragment.getSelectedData(); + data.putParcelableArrayList(KeychainIntentService.DOWNLOAD_KEY_LIST, selectedEntries); + + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(saveHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // show progress dialog + saveHandler.showProgressDialog(this); + + // start service with intent + startService(intent); + } else { AppMsg.makeText(this, R.string.error_nothing_import, AppMsg.STYLE_ALERT).show(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java index 412fbddd8..f331358fa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java @@ -71,7 +71,7 @@ public class ImportKeysClipboardFragment extends Fragment { return; } } - mImportActivity.loadCallback(sendText.getBytes(), null, null, null); + mImportActivity.loadCallback(sendText.getBytes(), null, null, null, null); } }); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java index dc5333a8f..51f961aab 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java @@ -85,7 +85,7 @@ public class ImportKeysFileFragment extends Fragment { if (resultCode == Activity.RESULT_OK && data != null) { // load data - mImportActivity.loadCallback(null, data.getData(), null, null); + mImportActivity.loadCallback(null, data.getData(), null, null, null); } break; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysKeybaseFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysKeybaseFragment.java new file mode 100644 index 000000000..7ae57cec3 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysKeybaseFragment.java @@ -0,0 +1,108 @@ +package org.sufficientlysecure.keychain.ui; + +import android.content.Context; +import android.support.v4.app.Fragment; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.TextView; + +import com.beardedhen.androidbootstrap.BootstrapButton; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Log; + +/** + * Import public keys from the Keybase.io directory. First cut: just raw search. + * TODO: make a pick list of the people you’re following on keybase + */ +public class ImportKeysKeybaseFragment extends Fragment { + + private ImportKeysActivity mImportActivity; + private BootstrapButton mSearchButton; + private EditText mQueryEditText; + + public static final String ARG_QUERY = "query"; + public static final String ARG_DISABLE_QUERY_EDIT = "disable_query_edit"; + + /** + * Creates new instance of this fragment + */ + public static ImportKeysKeybaseFragment newInstance() { + ImportKeysKeybaseFragment frag = new ImportKeysKeybaseFragment(); + + Bundle args = new Bundle(); + frag.setArguments(args); + + return frag; + } + + /** + * Inflate the layout for this fragment + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.import_keys_keybase_fragment, container, false); + + mQueryEditText = (EditText) view.findViewById(R.id.import_keybase_query); + + mSearchButton = (BootstrapButton) view.findViewById(R.id.import_keybase_search); + mSearchButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String query = mQueryEditText.getText().toString(); + search(query); + + // close keyboard after pressing search + InputMethodManager imm = + (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(mQueryEditText.getWindowToken(), 0); + } + }); + + mQueryEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_SEARCH) { + String query = mQueryEditText.getText().toString(); + search(query); + + // Don't return true to let the keyboard close itself after pressing search + return false; + } + return false; + } + }); + + return view; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + mImportActivity = (ImportKeysActivity) getActivity(); + + // set displayed values + if (getArguments() != null) { + if (getArguments().containsKey(ARG_QUERY)) { + String query = getArguments().getString(ARG_QUERY); + mQueryEditText.setText(query, TextView.BufferType.EDITABLE); + } + + if (getArguments().getBoolean(ARG_DISABLE_QUERY_EDIT, false)) { + mQueryEditText.setEnabled(false); + } + } + } + + private void search(String query) { + mImportActivity.loadCallback(null, null, null, null, query); + } +} 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 3a6c384e8..0580db080 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -34,6 +34,7 @@ import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; +import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListKeybaseLoader; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader; import org.sufficientlysecure.keychain.util.InputData; @@ -60,9 +61,11 @@ public class ImportKeysListFragment extends ListFragment implements private Uri mDataUri; private String mServerQuery; private String mKeyServer; + private String mKeybaseQuery; private static final int LOADER_ID_BYTES = 0; private static final int LOADER_ID_SERVER_QUERY = 1; + private static final int LOADER_ID_KEYBASE = 2; public byte[] getKeyBytes() { return mKeyBytes; @@ -76,6 +79,10 @@ public class ImportKeysListFragment extends ListFragment implements return mServerQuery; } + public String getKeybaseQuery() { + return mKeybaseQuery; + } + public String getKeyServer() { return mKeyServer; } @@ -148,6 +155,16 @@ public class ImportKeysListFragment extends ListFragment implements // give arguments to onCreateLoader() getLoaderManager().initLoader(LOADER_ID_SERVER_QUERY, null, this); } + + if (mKeybaseQuery != null) { + // Start out with a progress indicator. + setListShown(false); + + // Prepare the loader. Either re-connect with an existing one, + // or start a new one. + // give arguments to onCreateLoader() + getLoaderManager().initLoader(LOADER_ID_KEYBASE, null, this); + } } @Override @@ -157,16 +174,18 @@ public class ImportKeysListFragment extends ListFragment implements // Select checkbox! // Update underlying data and notify adapter of change. The adapter will // update the view automatically. + ImportKeysListEntry entry = mAdapter.getItem(position); entry.setSelected(!entry.isSelected()); mAdapter.notifyDataSetChanged(); } - public void loadNew(byte[] keyBytes, Uri dataUri, String serverQuery, String keyServer) { + public void loadNew(byte[] keyBytes, Uri dataUri, String serverQuery, String keyServer, String keybaseQuery) { mKeyBytes = keyBytes; mDataUri = dataUri; mServerQuery = serverQuery; mKeyServer = keyServer; + mKeybaseQuery = keybaseQuery; if (mKeyBytes != null || mDataUri != null) { // Start out with a progress indicator. @@ -181,11 +200,18 @@ public class ImportKeysListFragment extends ListFragment implements getLoaderManager().restartLoader(LOADER_ID_SERVER_QUERY, null, this); } + + if (mKeybaseQuery != null) { + // Start out with a progress indicator. + setListShown(false); + + getLoaderManager().restartLoader(LOADER_ID_KEYBASE, null, this); + } } @Override public Loader>> - onCreateLoader(int id, Bundle args) { + onCreateLoader(int id, Bundle args) { switch (id) { case LOADER_ID_BYTES: { InputData inputData = getInputData(mKeyBytes, mDataUri); @@ -194,6 +220,9 @@ public class ImportKeysListFragment extends ListFragment implements case LOADER_ID_SERVER_QUERY: { return new ImportKeysListServerLoader(getActivity(), mServerQuery, mKeyServer); } + case LOADER_ID_KEYBASE: { + return new ImportKeysListKeybaseLoader(getActivity(), mKeybaseQuery); + } default: return null; @@ -248,7 +277,7 @@ public class ImportKeysListFragment extends ListFragment implements if (error == null) { AppMsg.makeText( getActivity(), getResources().getQuantityString(R.plurals.keys_found, - mAdapter.getCount(), mAdapter.getCount()), + mAdapter.getCount(), mAdapter.getCount()), AppMsg.STYLE_INFO ).show(); } else if (error instanceof KeyServer.InsufficientQuery) { @@ -263,6 +292,19 @@ public class ImportKeysListFragment extends ListFragment implements } break; + case LOADER_ID_KEYBASE: + + if (error == null) { + AppMsg.makeText( + getActivity(), getResources().getQuantityString(R.plurals.keys_found, + mAdapter.getCount(), mAdapter.getCount()), + AppMsg.STYLE_INFO + ).show(); + } else if (error instanceof KeyServer.QueryException) { + AppMsg.makeText(getActivity(), R.string.error_keyserver_query, + AppMsg.STYLE_ALERT).show(); + } + default: break; } @@ -279,6 +321,10 @@ public class ImportKeysListFragment extends ListFragment implements // Clear the data in the adapter. mAdapter.clear(); break; + case LOADER_ID_KEYBASE: + // Clear the data in the adapter. + mAdapter.clear(); + break; default: break; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java index 65d463456..22b56e1ab 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java @@ -117,7 +117,7 @@ public class ImportKeysQrCodeFragment extends Fragment { // is this a full key encoded as qr code? if (scannedContent.startsWith("-----BEGIN PGP")) { - mImportActivity.loadCallback(scannedContent.getBytes(), null, null, null); + mImportActivity.loadCallback(scannedContent.getBytes(), null, null, null, null); return; } @@ -197,7 +197,7 @@ public class ImportKeysQrCodeFragment extends Fragment { for (String in : mScannedContent) { result += in; } - mImportActivity.loadCallback(result.getBytes(), null, null, null); + mImportActivity.loadCallback(result.getBytes(), null, null, null, null); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java index 82fe2fc4c..9e3d88ff5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java @@ -151,7 +151,7 @@ public class ImportKeysServerFragment extends Fragment { } private void search(String query, String keyServer) { - mImportActivity.loadCallback(null, null, query, keyServer); + mImportActivity.loadCallback(null, null, query, keyServer, null); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java index b06852af4..1610bfeab 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java @@ -203,7 +203,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { * Constructor for later querying from keyserver */ public ImportKeysListEntry() { - // keys from keyserver are always public keys + // keys from keyserver are always public keys; from keybase too secretKey = false; // do not select by default mSelected = false; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java new file mode 100644 index 000000000..73ff9a8f8 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui.adapter; + +import android.content.Context; +import android.support.v4.content.AsyncTaskLoader; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.KeyServer; +import org.sufficientlysecure.keychain.util.KeybaseKeyServer; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.ArrayList; + +public class ImportKeysListKeybaseLoader + extends AsyncTaskLoader>> { + Context mContext; + + String mKeybaseQuery; + + private ArrayList mEntryList = new ArrayList(); + private AsyncTaskResultWrapper> mEntryListWrapper; + + public ImportKeysListKeybaseLoader(Context context, String keybaseQuery) { + super(context); + mContext = context; + mKeybaseQuery = keybaseQuery; + } + + @Override + public AsyncTaskResultWrapper> loadInBackground() { + + mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, null); + + if (mKeybaseQuery == null) { + Log.e(Constants.TAG, "mKeybaseQery is null!"); + return mEntryListWrapper; + } + + queryServer(mKeybaseQuery); + + return mEntryListWrapper; + } + + @Override + protected void onReset() { + super.onReset(); + + // Ensure the loader is stopped + onStopLoading(); + } + + @Override + protected void onStartLoading() { + forceLoad(); + } + + @Override + protected void onStopLoading() { + cancelLoad(); + } + + @Override + public void deliverResult(AsyncTaskResultWrapper> data) { + super.deliverResult(data); + } + + /** + * Query keybase + */ + private void queryServer(String query) { + + KeybaseKeyServer server = new KeybaseKeyServer(); + try { + ArrayList searchResult = server.search(query); + + mEntryList.clear(); + + mEntryList.addAll(searchResult); + mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, null); + } catch (KeyServer.InsufficientQuery e) { + Log.e(Constants.TAG, "InsufficientQuery", e); + mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); + } catch (KeyServer.QueryException e) { + Log.e(Constants.TAG, "QueryException", e); + mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); + } catch (KeyServer.TooManyResponses e) { + Log.e(Constants.TAG, "TooManyResponses", e); + mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); + } + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java new file mode 100644 index 000000000..6f9c4cfa5 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java @@ -0,0 +1,56 @@ +package org.sufficientlysecure.keychain.util; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Minimal hierarchy selector + */ +public class JWalk { + + public static int getInt(JSONObject json, String... path) throws JSONException { + json = walk(json, path); + return json.getInt(path[path.length - 1]); + } + + public static long getLong(JSONObject json, String... path) throws JSONException { + json = walk(json, path); + return json.getLong(path[path.length - 1]); + } + + public static String getString(JSONObject json, String... path) throws JSONException { + json = walk(json, path); + return json.getString(path[path.length - 1]); + } + + public static JSONArray getArray(JSONObject json, String... path) throws JSONException { + json = walk(json, path); + return json.getJSONArray(path[path.length - 1]); + } + + public static JSONObject optObject(JSONObject json, String... path) throws JSONException { + json = walk(json, path); + return json.optJSONObject(path[path.length - 1]); + } + + private static JSONObject walk(JSONObject json, String... path) throws JSONException { + int len = path.length - 1; + int pathIndex = 0; + try { + while (pathIndex < len) { + json = json.getJSONObject(path[pathIndex]); + pathIndex++; + } + } catch (JSONException e) { + // try to give ’em a nice-looking error + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < len; i++) { + sb.append(path[i]).append('.'); + } + sb.append(path[len]); + throw new JSONException("JWalk error at step " + pathIndex + " of " + sb); + } + return json; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java new file mode 100644 index 000000000..4b802c0e1 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2012-2014 Dominik Schürmann + * Copyright (C) 2011-2014 Thialfihar + * Copyright (C) 2011 Senecaso + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.sufficientlysecure.keychain.util; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.GregorianCalendar; +import java.util.TimeZone; +import java.util.WeakHashMap; + +public class KeybaseKeyServer extends KeyServer { + + private WeakHashMap mKeyCache = new WeakHashMap(); + + private static String readAll(InputStream in, String encoding) throws IOException { + ByteArrayOutputStream raw = new ByteArrayOutputStream(); + + byte buffer[] = new byte[1 << 16]; + int n = 0; + while ((n = in.read(buffer)) != -1) { + raw.write(buffer, 0, n); + } + + if (encoding == null) { + encoding = "utf8"; + } + return raw.toString(encoding); + } + + @Override + public ArrayList search(String query) throws QueryException, TooManyResponses, + InsufficientQuery { + ArrayList results = new ArrayList(); + + JSONObject fromQuery = getFromKeybase("_/api/1.0/user/autocomplete.json?q=", query); + try { + + JSONArray matches = JWalk.getArray(fromQuery, "completions"); + for (int i = 0; i < matches.length(); i++) { + JSONObject match = matches.getJSONObject(i); + + // only list them if they have a key + if (JWalk.optObject(match, "components", "key_fingerprint") != null) { + results.add(makeEntry(match)); + } + } + } catch (Exception e) { + throw new QueryException("Unexpected structure in keybase search result: " + e.getMessage()); + } + + return results; + } + + private JSONObject getUser(String keybaseID) throws QueryException { + try { + return getFromKeybase("_/api/1.0/user/lookup.json?username=", keybaseID); + } catch (Exception e) { + String detail = ""; + if (keybaseID != null) { + detail = ". Query was for user '" + keybaseID + "'"; + } + throw new QueryException(e.getMessage() + detail); + } + } + + private ImportKeysListEntry makeEntry(JSONObject match) throws QueryException, JSONException { + + String keybaseID = JWalk.getString(match, "components", "username", "val"); + String key_fingerprint = JWalk.getString(match, "components", "key_fingerprint", "val"); + key_fingerprint = key_fingerprint.replace(" ", "").toUpperCase(); + match = getUser(keybaseID); + + final ImportKeysListEntry entry = new ImportKeysListEntry(); + + entry.setBitStrength(4096); + entry.setAlgorithm("RSA"); + entry.setKeyIdHex("0x" + key_fingerprint); + + final long creationDate = JWalk.getLong(match, "them", "public_keys", "primary", "ctime"); + final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + tmpGreg.setTimeInMillis(creationDate * 1000); + entry.setDate(tmpGreg.getTime()); + entry.setRevoked(false); + mKeyCache.put(keybaseID, JWalk.getString(match,"them", "public_keys", "primary", "bundle")); + String name = JWalk.getString(match, "them", "profile", "full_name"); + ArrayList userIds = new ArrayList(); + userIds.add(name); + userIds.add("keybase.io/" + keybaseID); // TODO: Maybe should be keybaseID@keybase.io ? + entry.setUserIds(userIds); + entry.setPrimaryUserId(name); + return entry; + } + + private JSONObject getFromKeybase(String path, String query) throws QueryException { + try { + String url = "https://keybase.io/" + path + URLEncoder.encode(query, "utf8"); + Log.d(Constants.TAG, "keybase query: " + url); + + URL realUrl = new URL(url); + HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection(); + conn.setConnectTimeout(5000); // TODO: Reasonable values for keybase + conn.setReadTimeout(25000); + conn.connect(); + int response = conn.getResponseCode(); + if (response >= 200 && response < 300) { + String text = readAll(conn.getInputStream(), conn.getContentEncoding()); + try { + JSONObject json = new JSONObject(text); + if (JWalk.getInt(json, "status", "code") != 0) { + throw new QueryException("Keybase autocomplete search failed"); + } + return json; + } catch (JSONException e) { + throw new QueryException("Keybase.io query returned broken JSON"); + } + } else { + String message = readAll(conn.getErrorStream(), conn.getContentEncoding()); + throw new QueryException("Keybase.io query error (status=" + response + + "): " + message); + } + } catch (Exception e) { + throw new QueryException("Keybase.io query error"); + } + } + + @Override + public String get(String id) throws QueryException { + // id is like "keybase/username" + String keybaseID = id.substring(id.indexOf('/') + 1); + String key = mKeyCache.get(keybaseID); + if (key == null) { + try { + JSONObject user = getUser(keybaseID); + key = JWalk.getString(user, "them", "public_keys", "primary", "bundle"); + } catch (Exception e) { + throw new QueryException(e.getMessage()); + } + } + return key; + } + + @Override + public void add(String armoredKey) throws AddKeyException { + throw new AddKeyException(); + } +} \ No newline at end of file -- cgit v1.2.3 From ea1032dbfdbb42f39ef37af510e38b64f9854d5a Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Mon, 28 Apr 2014 10:47:39 -0700 Subject: Clean up debug crud --- .../org/sufficientlysecure/keychain/service/KeychainIntentService.java | 3 --- .../java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index fcd31b2fe..e085b5b72 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -56,7 +56,6 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.util.HkpKeyServer; import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.KeyServer; import org.sufficientlysecure.keychain.util.KeybaseKeyServer; import org.sufficientlysecure.keychain.util.KeychainServiceListener; import org.sufficientlysecure.keychain.util.Log; @@ -763,7 +762,6 @@ public class KeychainIntentService extends IntentService // get first object in block Object obj; if ((obj = objectFactory.nextObject()) != null) { - Log.d(Constants.TAG, "Found class: " + obj.getClass()); if (obj instanceof PGPKeyRing) { downloadedKey = (PGPKeyRing) obj; @@ -820,7 +818,6 @@ public class KeychainIntentService extends IntentService // get first object in block Object obj; if ((obj = objectFactory.nextObject()) != null) { - Log.d(Constants.TAG, "Found class: " + obj.getClass()); if (obj instanceof PGPKeyRing) { downloadedKey = (PGPKeyRing) obj; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java index 4b802c0e1..c5f97f0dd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java @@ -111,8 +111,8 @@ public class KeybaseKeyServer extends KeyServer { mKeyCache.put(keybaseID, JWalk.getString(match,"them", "public_keys", "primary", "bundle")); String name = JWalk.getString(match, "them", "profile", "full_name"); ArrayList userIds = new ArrayList(); + name = "keybase.io/" + keybaseID + " " + name; userIds.add(name); - userIds.add("keybase.io/" + keybaseID); // TODO: Maybe should be keybaseID@keybase.io ? entry.setUserIds(userIds); entry.setPrimaryUserId(name); return entry; -- cgit v1.2.3 From b5fb311c6152af36254a803aabe726ed8b03a447 Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Tue, 29 Apr 2014 15:03:37 -0700 Subject: keybase ID stuff --- .../sufficientlysecure/keychain/util/KeybaseKeyServer.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java index c5f97f0dd..ae4c44e09 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java @@ -99,19 +99,24 @@ public class KeybaseKeyServer extends KeyServer { final ImportKeysListEntry entry = new ImportKeysListEntry(); + // TODO: Fix; have suggested keybase provide this value to avoid search-time crypto calls entry.setBitStrength(4096); entry.setAlgorithm("RSA"); entry.setKeyIdHex("0x" + key_fingerprint); + entry.setRevoked(false); + // ctime final long creationDate = JWalk.getLong(match, "them", "public_keys", "primary", "ctime"); final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC")); tmpGreg.setTimeInMillis(creationDate * 1000); entry.setDate(tmpGreg.getTime()); - entry.setRevoked(false); + + // key bits mKeyCache.put(keybaseID, JWalk.getString(match,"them", "public_keys", "primary", "bundle")); - String name = JWalk.getString(match, "them", "profile", "full_name"); + + // String displayName = JWalk.getString(match, "them", "profile", "full_name"); ArrayList userIds = new ArrayList(); - name = "keybase.io/" + keybaseID + " " + name; + String name = "keybase.io/" + keybaseID + " <" + keybaseID + "@keybase.io>"; userIds.add(name); entry.setUserIds(userIds); entry.setPrimaryUserId(name); -- cgit v1.2.3 From 4c693b45097d08d0c4285dccd5d1679a2e4551d6 Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Wed, 30 Apr 2014 13:46:35 -0700 Subject: Changes should now be in sync with dominik --- .../org/sufficientlysecure/keychain/util/KeybaseKeyServer.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java index ae4c44e09..dee3899a8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java @@ -112,12 +112,15 @@ public class KeybaseKeyServer extends KeyServer { entry.setDate(tmpGreg.getTime()); // key bits + // we have to fetch the user object to construct the search-result list, so we might as + // well (weakly) remember the key, in case they try to import it mKeyCache.put(keybaseID, JWalk.getString(match,"them", "public_keys", "primary", "bundle")); // String displayName = JWalk.getString(match, "them", "profile", "full_name"); ArrayList userIds = new ArrayList(); String name = "keybase.io/" + keybaseID + " <" + keybaseID + "@keybase.io>"; userIds.add(name); + userIds.add(keybaseID); entry.setUserIds(userIds); entry.setPrimaryUserId(name); return entry; @@ -157,12 +160,10 @@ public class KeybaseKeyServer extends KeyServer { @Override public String get(String id) throws QueryException { - // id is like "keybase/username" - String keybaseID = id.substring(id.indexOf('/') + 1); - String key = mKeyCache.get(keybaseID); + String key = mKeyCache.get(id); if (key == null) { try { - JSONObject user = getUser(keybaseID); + JSONObject user = getUser(id); key = JWalk.getString(user, "them", "public_keys", "primary", "bundle"); } catch (Exception e) { throw new QueryException(e.getMessage()); -- cgit v1.2.3 From 18ed8286080c70daabfedcd258bfa20c1099c268 Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Wed, 30 Apr 2014 13:49:48 -0700 Subject: tidy up IntentService --- .../sufficientlysecure/keychain/service/KeychainIntentService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index e085b5b72..eabcfadee 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -748,8 +748,8 @@ public class KeychainIntentService extends IntentService KeybaseKeyServer server = new KeybaseKeyServer(); for (ImportKeysListEntry entry : entries) { // the keybase handle is in userId(1) - String username = entry.getUserIds().get(1); - byte[] downloadedKeyBytes = server.get(username).getBytes(); + String keybaseID = entry.getUserIds().get(1); + byte[] downloadedKeyBytes = server.get(keybaseID).getBytes(); // create PGPKeyRing object based on downloaded armored key PGPKeyRing downloadedKey = null; -- cgit v1.2.3 From 5b0f19fcebd586235be7c895769ccb111c97e78e Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Wed, 30 Apr 2014 13:56:56 -0700 Subject: stupid identation stuff --- .../java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') 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 0580db080..c1aa8a1f2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -211,7 +211,7 @@ public class ImportKeysListFragment extends ListFragment implements @Override public Loader>> - onCreateLoader(int id, Bundle args) { + onCreateLoader(int id, Bundle args) { switch (id) { case LOADER_ID_BYTES: { InputData inputData = getInputData(mKeyBytes, mDataUri); -- cgit v1.2.3 From 9726ac7a964dacc593cdb94a494182f61fd59c5b Mon Sep 17 00:00:00 2001 From: Vadim Lebedev Date: Fri, 2 May 2014 19:05:43 +0200 Subject: Avoid displaying double 0x before keyid in ViewCertActivity --- .../java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java index f740cfc22..645766287 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -124,7 +124,7 @@ public class ViewCertActivity extends ActionBarActivity @Override public void onLoadFinished(Loader loader, Cursor data) { if (data.moveToFirst()) { - String signeeKey = "0x" + PgpKeyHelper.convertKeyIdToHex(data.getLong(INDEX_MASTER_KEY_ID)); + String signeeKey = PgpKeyHelper.convertKeyIdToHex(data.getLong(INDEX_MASTER_KEY_ID)); mSigneeKey.setText(signeeKey); String signeeUid = data.getString(INDEX_USER_ID); @@ -134,7 +134,7 @@ public class ViewCertActivity extends ActionBarActivity mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format(creationDate)); mSignerKeyId = data.getLong(INDEX_KEY_ID_CERTIFIER); - String signerKey = "0x" + PgpKeyHelper.convertKeyIdToHex(mSignerKeyId); + String signerKey = PgpKeyHelper.convertKeyIdToHex(mSignerKeyId); mSignerKey.setText(signerKey); String signerUid = data.getString(INDEX_SIGNER_UID); -- cgit v1.2.3 From 6055b0b0da6ca3f6fdae3b7b1602a38d3a05bb3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 5 May 2014 00:58:22 +0200 Subject: New key view design, using Android flat buttons and Android icons --- .../keychain/ui/CertifyKeyActivity.java | 4 +- .../keychain/ui/ViewKeyActivity.java | 241 ++++++++-------- .../keychain/ui/ViewKeyCertsFragment.java | 18 +- .../keychain/ui/ViewKeyKeysFragment.java | 238 +++++++++++++++ .../keychain/ui/ViewKeyMainFragment.java | 179 ++++-------- .../keychain/ui/ViewKeyShareFragment.java | 313 ++++++++++++++++++++ .../keychain/ui/adapter/ImportKeysAdapter.java | 3 +- .../keychain/ui/adapter/PagerTabStripAdapter.java | 10 +- .../keychain/ui/adapter/ViewKeyUserIdsAdapter.java | 46 ++- .../keychain/util/SlidingTabLayout.java | 318 +++++++++++++++++++++ .../keychain/util/SlidingTabStrip.java | 211 ++++++++++++++ 11 files changed, 1305 insertions(+), 276 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/SlidingTabLayout.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/SlidingTabStrip.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index fbcbbb0c3..2d31e0de8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -147,7 +147,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements } Log.e(Constants.TAG, "uri: " + mDataUri); - mUserIds = (ListView) findViewById(R.id.user_ids); + mUserIds = (ListView) findViewById(R.id.view_key_user_ids); mUserIdsAdapter = new ViewKeyUserIdsAdapter(this, null, 0, true); mUserIds.setAdapter(mUserIdsAdapter); @@ -203,7 +203,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements byte[] fingerprintBlob = data.getBlob(INDEX_FINGERPRINT); String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob); - ((TextView) findViewById(R.id.fingerprint)) + ((TextView) findViewById(R.id.view_key_fingerprint)) .setText(PgpKeyHelper.colorizeFingerprint(fingerprint)); } break; 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 e595c1889..56aaba57b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.ui; import android.annotation.TargetApi; import android.app.Activity; import android.content.Intent; +import android.database.Cursor; import android.net.Uri; import android.nfc.NdefMessage; import android.nfc.NdefRecord; @@ -31,6 +32,9 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; @@ -42,20 +46,19 @@ import com.devspark.appmsg.AppMsg; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.helper.ExportHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter; -import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment; +import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.SlidingTabLayout; import java.io.IOException; import java.util.HashMap; -public class ViewKeyActivity extends ActionBarActivity { +public class ViewKeyActivity extends ActionBarActivity implements + LoaderManager.LoaderCallbacks { ExportHelper mExportHelper; ProviderHelper mProviderHelper; @@ -63,9 +66,15 @@ public class ViewKeyActivity extends ActionBarActivity { protected Uri mDataUri; public static final String EXTRA_SELECTED_TAB = "selectedTab"; + public static final int TAB_MAIN = 0; + public static final int TAB_SHARE = 1; + public static final int TAB_KEYS = 2; + public static final int TAB_CERTS = 3; - ViewPager mViewPager; - TabsAdapter mTabsAdapter; + // view + private ViewPager mViewPager; + private SlidingTabLayout mSlidingTabLayout; + private PagerTabStripAdapter mTabsAdapter; public static final int REQUEST_CODE_LOOKUP_KEY = 0x00007006; @@ -76,6 +85,9 @@ public class ViewKeyActivity extends ActionBarActivity { private byte[] mNfcKeyringBytes; private static final int NFC_SENT = 1; + private static final int LOADER_ID_UNIFIED = 0; + + @Override protected void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); @@ -89,33 +101,67 @@ public class ViewKeyActivity extends ActionBarActivity { actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setIcon(android.R.color.transparent); actionBar.setHomeButtonEnabled(true); - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); setContentView(R.layout.view_key_activity); - mViewPager = (ViewPager) findViewById(R.id.pager); + mViewPager = (ViewPager) findViewById(R.id.view_key_pager); + mSlidingTabLayout = (SlidingTabLayout) findViewById(R.id.view_key_sliding_tab_layout); - mTabsAdapter = new TabsAdapter(this, mViewPager); + mTabsAdapter = new PagerTabStripAdapter(this); + mViewPager.setAdapter(mTabsAdapter); - int selectedTab = 0; + int switchToTab = TAB_MAIN; Intent intent = getIntent(); if (intent.getExtras() != null && intent.getExtras().containsKey(EXTRA_SELECTED_TAB)) { - selectedTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB); + switchToTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB); + } + + Uri dataUri = getIntent().getData(); + if (dataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); + finish(); + return; } - mDataUri = getIntent().getData(); + loadData(dataUri); - initNfc(mDataUri); + initNfc(dataUri); Bundle mainBundle = new Bundle(); - mainBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, mDataUri); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.key_view_tab_main)), - ViewKeyMainFragment.class, mainBundle, (selectedTab == 0)); + mainBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyMainFragment.class, + mainBundle, getString(R.string.key_view_tab_main)); + + Bundle shareBundle = new Bundle(); + shareBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyShareFragment.class, + mainBundle, getString(R.string.key_view_tab_share)); + + Bundle keyDetailsBundle = new Bundle(); + keyDetailsBundle.putParcelable(ViewKeyKeysFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyKeysFragment.class, + keyDetailsBundle, getString(R.string.key_view_tab_keys_details)); Bundle certBundle = new Bundle(); - certBundle.putParcelable(ViewKeyCertsFragment.ARG_DATA_URI, mDataUri); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.key_view_tab_certs)), - ViewKeyCertsFragment.class, certBundle, (selectedTab == 1)); + certBundle.putParcelable(ViewKeyCertsFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyCertsFragment.class, + certBundle, getString(R.string.key_view_tab_certs)); + + // NOTE: must be after adding the tabs! + mSlidingTabLayout.setViewPager(mViewPager); + + // switch to tab selected by extra + mViewPager.setCurrentItem(switchToTab); + } + + private void loadData(Uri dataUri) { + mDataUri = dataUri; + + Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); } @Override @@ -143,24 +189,6 @@ public class ViewKeyActivity extends ActionBarActivity { case R.id.menu_key_view_export_file: exportToFile(mDataUri, mExportHelper, mProviderHelper); return true; - case R.id.menu_key_view_share_default_fingerprint: - shareKey(mDataUri, true, mProviderHelper); - return true; - case R.id.menu_key_view_share_default: - shareKey(mDataUri, false, mProviderHelper); - return true; - case R.id.menu_key_view_share_qr_code_fingerprint: - shareKeyQrCode(mDataUri, true); - return true; - case R.id.menu_key_view_share_qr_code: - shareKeyQrCode(mDataUri, false); - return true; - case R.id.menu_key_view_share_nfc: - shareNfc(); - return true; - case R.id.menu_key_view_share_clipboard: - copyToClipboard(mDataUri, mProviderHelper); - return true; case R.id.menu_key_view_delete: { deleteKey(mDataUri, mExportHelper); return true; @@ -209,84 +237,6 @@ public class ViewKeyActivity extends ActionBarActivity { startActivityForResult(queryIntent, REQUEST_CODE_LOOKUP_KEY); } - private void shareKey(Uri dataUri, boolean fingerprintOnly, ProviderHelper providerHelper) - throws ProviderHelper.NotFoundException { - String content = null; - if (fingerprintOnly) { - byte[] data = (byte[]) providerHelper.getGenericData( - KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri), - KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); - if (data != null) { - String fingerprint = PgpKeyHelper.convertFingerprintToHex(data); - content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; - } else { - AppMsg.makeText(this, "Bad key selected!", - AppMsg.STYLE_ALERT).show(); - return; - } - } else { - // get public keyring as ascii armored string - try { - Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); - content = providerHelper.getKeyRingAsArmoredString(uri); - - // Android will fail with android.os.TransactionTooLargeException if key is too big - // see http://www.lonestarprod.com/?p=34 - if (content.length() >= 86389) { - AppMsg.makeText(this, R.string.key_too_big_for_sharing, - AppMsg.STYLE_ALERT).show(); - return; - } - } catch (IOException e) { - Log.e(Constants.TAG, "error processing key!", e); - AppMsg.makeText(this, R.string.error_invalid_data, AppMsg.STYLE_ALERT).show(); - } catch (ProviderHelper.NotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - AppMsg.makeText(this, R.string.error_key_not_found, AppMsg.STYLE_ALERT).show(); - } - } - - if (content != null) { - // let user choose application - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_TEXT, content); - sendIntent.setType("text/plain"); - startActivity(Intent.createChooser(sendIntent, - getResources().getText(R.string.action_share_key_with))); - } else { - Log.e(Constants.TAG, "content is null!"); - } - } - - private void shareKeyQrCode(Uri dataUri, boolean fingerprintOnly) { - ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(dataUri, - fingerprintOnly); - dialog.show(getSupportFragmentManager(), "shareQrCodeDialog"); - } - - private void copyToClipboard(Uri dataUri, ProviderHelper providerHelper) { - // get public keyring as ascii armored string - try { - Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); - String keyringArmored = providerHelper.getKeyRingAsArmoredString(uri); - - ClipboardReflection.copyToClipboard(this, keyringArmored); - AppMsg.makeText(this, R.string.key_copied_to_clipboard, AppMsg.STYLE_INFO) - .show(); - } catch (IOException e) { - Log.e(Constants.TAG, "error processing key!", e); - AppMsg.makeText(this, R.string.error_key_processing, AppMsg.STYLE_ALERT).show(); - } catch (ProviderHelper.NotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - AppMsg.makeText(this, R.string.error_key_not_found, AppMsg.STYLE_ALERT).show(); - } - } - - private void shareNfc() { - ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); - dialog.show(getSupportFragmentManager(), "shareNfcDialog"); - } - private void deleteKey(Uri dataUri, ExportHelper exportHelper) { // Message is received after key is deleted Handler returnHandler = new Handler() { @@ -409,4 +359,63 @@ public class ViewKeyActivity extends ActionBarActivity { } }; + static final String[] UNIFIED_PROJECTION = new String[]{ + KeychainContract.KeyRings._ID, + KeychainContract.KeyRings.MASTER_KEY_ID, + KeychainContract.KeyRings.USER_ID, + + }; + static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; + static final int INDEX_UNIFIED_USER_ID = 2; + + @Override + public Loader onCreateLoader(int id, Bundle args) { + switch (id) { + case LOADER_ID_UNIFIED: { + Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(mDataUri); + return new CursorLoader(this, baseUri, UNIFIED_PROJECTION, null, null, null); + } + + default: + return null; + } + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + /* TODO better error handling? May cause problems when a key is deleted, + * because the notification triggers faster than the activity closes. + */ + // Avoid NullPointerExceptions... + if (data.getCount() == 0) { + return; + } + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + switch (loader.getId()) { + case LOADER_ID_UNIFIED: { + if (data.moveToFirst()) { + // get name, email, and comment from USER_ID + String[] mainUserId = PgpKeyHelper.splitUserId(data.getString(INDEX_UNIFIED_USER_ID)); + if (mainUserId[0] != null) { + setTitle(mainUserId[0]); + } else { + setTitle(R.string.user_id_no_name); + } + + // get key id from MASTER_KEY_ID + long masterKeyId = data.getLong(INDEX_UNIFIED_MASTER_KEY_ID); + String keyIdStr = PgpKeyHelper.convertKeyIdToHex(masterKeyId); + getSupportActionBar().setSubtitle(keyIdStr); + + break; + } + } + } + } + + @Override + public void onLoaderReset(Loader loader) { + + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java index 3c4135715..e1c2013ea 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java @@ -75,6 +75,9 @@ public class ViewKeyCertsFragment extends Fragment private Uri mDataUri; + // starting with 4 for this fragment + private static final int LOADER_ID = 4; + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.view_key_certs_fragment, container, false); @@ -112,7 +115,7 @@ public class ViewKeyCertsFragment extends Fragment mAdapter = new CertListAdapter(getActivity(), null); mStickyList.setAdapter(mAdapter); - getLoaderManager().initLoader(0, null, this); + getLoaderManager().initLoader(LOADER_ID, null, this); } @Override @@ -208,11 +211,18 @@ public class ViewKeyCertsFragment extends Fragment // set name and stuff, common to both key types TextView wSignerKeyId = (TextView) view.findViewById(R.id.signerKeyId); - TextView wSignerUserId = (TextView) view.findViewById(R.id.signerUserId); + TextView wSignerName = (TextView) view.findViewById(R.id.signerName); TextView wSignStatus = (TextView) view.findViewById(R.id.signStatus); String signerKeyId = PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexSignerKeyId)); - String signerUserId = cursor.getString(mIndexSignerUserId); + String[] userId = PgpKeyHelper.splitUserId(cursor.getString(mIndexSignerUserId)); + if (userId[0] != null) { + wSignerName.setText(userId[0]); + } else { + wSignerName.setText(R.string.user_id_no_name); + } + wSignerKeyId.setText(signerKeyId); + switch (cursor.getInt(mIndexType)) { case PGPSignature.DEFAULT_CERTIFICATION: // 0x10 wSignStatus.setText(R.string.cert_default); @@ -231,8 +241,6 @@ public class ViewKeyCertsFragment extends Fragment break; } - wSignerUserId.setText(signerUserId); - wSignerKeyId.setText(signerKeyId); view.setTag(R.id.tag_mki, cursor.getLong(mIndexMasterKeyId)); view.setTag(R.id.tag_rank, cursor.getLong(mIndexRank)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java new file mode 100644 index 000000000..bb0e4b23a --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.database.Cursor; +import android.graphics.Color; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.text.format.DateFormat; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; +import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.Date; + + +public class ViewKeyKeysFragment extends Fragment implements + LoaderManager.LoaderCallbacks { + + public static final String ARG_DATA_URI = "uri"; + + private LinearLayout mContainer; + private TextView mAlgorithm; + private TextView mKeyId; + private TextView mExpiry; + private TextView mCreation; + private TextView mFingerprint; + private TextView mSecretKey; + + private ListView mKeys; + + private static final int LOADER_ID_UNIFIED = 0; + private static final int LOADER_ID_KEYS = 1; + + private ViewKeyKeysAdapter mKeysAdapter; + + private Uri mDataUri; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.view_key_keys_fragment, container, false); + + mContainer = (LinearLayout) view.findViewById(R.id.container); + mKeyId = (TextView) view.findViewById(R.id.key_id); + mAlgorithm = (TextView) view.findViewById(R.id.algorithm); + mCreation = (TextView) view.findViewById(R.id.creation); + mExpiry = (TextView) view.findViewById(R.id.expiry); + mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint); + mSecretKey = (TextView) view.findViewById(R.id.secret_key); + mKeys = (ListView) view.findViewById(R.id.keys); + + return view; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); + if (dataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); + getActivity().finish(); + return; + } + + loadData(dataUri); + } + + private void loadData(Uri dataUri) { + getActivity().setProgressBarIndeterminateVisibility(true); + mContainer.setVisibility(View.GONE); + + mDataUri = dataUri; + + Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + + mKeysAdapter = new ViewKeyKeysAdapter(getActivity(), null, 0); + mKeys.setAdapter(mKeysAdapter); + + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); + getLoaderManager().initLoader(LOADER_ID_KEYS, null, this); + } + + static final String[] UNIFIED_PROJECTION = new String[] { + KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, + KeyRings.USER_ID, KeyRings.FINGERPRINT, + KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY, + + }; + static final int INDEX_UNIFIED_MKI = 1; + static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; + static final int INDEX_UNIFIED_UID = 3; + static final int INDEX_UNIFIED_FINGERPRINT = 4; + static final int INDEX_UNIFIED_ALGORITHM = 5; + static final int INDEX_UNIFIED_KEY_SIZE = 6; + static final int INDEX_UNIFIED_CREATION = 7; + static final int INDEX_UNIFIED_EXPIRY = 8; + + static final String[] KEYS_PROJECTION = new String[] { + Keys._ID, + Keys.KEY_ID, Keys.RANK, Keys.ALGORITHM, Keys.KEY_SIZE, Keys.HAS_SECRET, + Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT, Keys.CAN_SIGN, Keys.IS_REVOKED, + Keys.CREATION, Keys.EXPIRY, Keys.FINGERPRINT + }; + static final int KEYS_INDEX_CAN_ENCRYPT = 7; + + public Loader onCreateLoader(int id, Bundle args) { + switch (id) { + case LOADER_ID_UNIFIED: { + Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); + } + case LOADER_ID_KEYS: { + Uri baseUri = Keys.buildKeysUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, null); + } + + default: + return null; + } + } + + public void onLoadFinished(Loader loader, Cursor data) { + /* TODO better error handling? May cause problems when a key is deleted, + * because the notification triggers faster than the activity closes. + */ + // Avoid NullPointerExceptions... + if(data.getCount() == 0) { + return; + } + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + switch (loader.getId()) { + case LOADER_ID_UNIFIED: { + if (data.moveToFirst()) { + if (data.getInt(INDEX_UNIFIED_HAS_ANY_SECRET) != 0) { + mSecretKey.setTextColor(getResources().getColor(R.color.emphasis)); + mSecretKey.setText(R.string.secret_key_yes); + } else { + mSecretKey.setTextColor(Color.BLACK); + mSecretKey.setText(getResources().getString(R.string.secret_key_no)); + } + + // get key id from MASTER_KEY_ID + long masterKeyId = data.getLong(INDEX_UNIFIED_MKI); + String keyIdStr = PgpKeyHelper.convertKeyIdToHex(masterKeyId); + mKeyId.setText(keyIdStr); + + // get creation date from CREATION + if (data.isNull(INDEX_UNIFIED_CREATION)) { + mCreation.setText(R.string.none); + } else { + Date creationDate = new Date(data.getLong(INDEX_UNIFIED_CREATION) * 1000); + + mCreation.setText( + DateFormat.getDateFormat(getActivity().getApplicationContext()).format( + creationDate)); + } + + // get expiry date from EXPIRY + if (data.isNull(INDEX_UNIFIED_EXPIRY)) { + mExpiry.setText(R.string.none); + } else { + Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); + + mExpiry.setText( + DateFormat.getDateFormat(getActivity().getApplicationContext()).format( + expiryDate)); + } + + String algorithmStr = PgpKeyHelper.getAlgorithmInfo( + getActivity(), + data.getInt(INDEX_UNIFIED_ALGORITHM), + data.getInt(INDEX_UNIFIED_KEY_SIZE) + ); + mAlgorithm.setText(algorithmStr); + + byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); + String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob); + mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint)); + + break; + } + } + + case LOADER_ID_KEYS: + mKeysAdapter.swapCursor(data); + break; + } + getActivity().setProgressBarIndeterminateVisibility(false); + mContainer.setVisibility(View.VISIBLE); + } + + /** + * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. + * We need to make sure we are no longer using it. + */ + public void onLoaderReset(Loader loader) { + switch (loader.getId()) { + case LOADER_ID_KEYS: + mKeysAdapter.swapCursor(null); + break; + } + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index ef4da3010..43e484ffe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -19,66 +19,46 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.database.Cursor; -import android.graphics.Color; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.ListView; -import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; +import org.sufficientlysecure.keychain.R;import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter; import org.sufficientlysecure.keychain.util.Log; -import java.util.Date; - - public class ViewKeyMainFragment extends Fragment implements LoaderManager.LoaderCallbacks { public static final String ARG_DATA_URI = "uri"; private LinearLayout mContainer; - private TextView mName; - private TextView mEmail; - private TextView mComment; - private TextView mAlgorithm; - private TextView mKeyId; - private TextView mExpiry; - private TextView mCreation; - private TextView mFingerprint; - private TextView mSecretKey; - private BootstrapButton mActionEdit; - private BootstrapButton mActionEncrypt; - private BootstrapButton mActionCertify; + private View mActionEdit; + private View mActionEditDivider; + private View mActionEncrypt; + private View mActionCertify; + private View mActionCertifyDivider; private ListView mUserIds; - private ListView mKeys; private static final int LOADER_ID_UNIFIED = 0; private static final int LOADER_ID_USER_IDS = 1; private static final int LOADER_ID_KEYS = 2; private ViewKeyUserIdsAdapter mUserIdsAdapter; - private ViewKeyKeysAdapter mKeysAdapter; private Uri mDataUri; @@ -87,20 +67,12 @@ public class ViewKeyMainFragment extends Fragment implements View view = inflater.inflate(R.layout.view_key_main_fragment, container, false); mContainer = (LinearLayout) view.findViewById(R.id.container); - mName = (TextView) view.findViewById(R.id.name); - mEmail = (TextView) view.findViewById(R.id.email); - mComment = (TextView) view.findViewById(R.id.comment); - mKeyId = (TextView) view.findViewById(R.id.key_id); - mAlgorithm = (TextView) view.findViewById(R.id.algorithm); - mCreation = (TextView) view.findViewById(R.id.creation); - mExpiry = (TextView) view.findViewById(R.id.expiry); - mFingerprint = (TextView) view.findViewById(R.id.fingerprint); - mSecretKey = (TextView) view.findViewById(R.id.secret_key); - mUserIds = (ListView) view.findViewById(R.id.user_ids); - mKeys = (ListView) view.findViewById(R.id.keys); - mActionEdit = (BootstrapButton) view.findViewById(R.id.action_edit); - mActionEncrypt = (BootstrapButton) view.findViewById(R.id.action_encrypt); - mActionCertify = (BootstrapButton) view.findViewById(R.id.action_certify); + mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); + mActionEdit = view.findViewById(R.id.view_key_action_edit); + mActionEditDivider = view.findViewById(R.id.view_key_action_edit_divider); + mActionEncrypt = view.findViewById(R.id.view_key_action_encrypt); + mActionCertify = view.findViewById(R.id.view_key_action_certify); + mActionCertifyDivider = view.findViewById(R.id.view_key_action_certify_divider); return view; } @@ -120,11 +92,6 @@ public class ViewKeyMainFragment extends Fragment implements } private void loadData(Uri dataUri) { - if (dataUri.equals(mDataUri)) { - Log.d(Constants.TAG, "Same URI, no need to load the data again!"); - return; - } - getActivity().setProgressBarIndeterminateVisibility(true); mContainer.setVisibility(View.GONE); @@ -135,44 +102,46 @@ public class ViewKeyMainFragment extends Fragment implements mActionEncrypt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - encryptToContact(mDataUri); + encrypt(mDataUri); } }); mActionCertify.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { - certifyKey(mDataUri); + certify(mDataUri); + } + }); + mActionEdit.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + editKey(mDataUri); } }); mUserIdsAdapter = new ViewKeyUserIdsAdapter(getActivity(), null, 0); mUserIds.setAdapter(mUserIdsAdapter); - mKeysAdapter = new ViewKeyKeysAdapter(getActivity(), null, 0); - mKeys.setAdapter(mKeysAdapter); - // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. - getActivity().getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); - getActivity().getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); - getActivity().getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this); + getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); + getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); + getLoaderManager().initLoader(LOADER_ID_KEYS, null, this); } - static final String[] UNIFIED_PROJECTION = new String[] { - KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, + static final String[] UNIFIED_PROJECTION = new String[]{ + KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, KeyRings.USER_ID, KeyRings.FINGERPRINT, KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY, }; - static final int INDEX_UNIFIED_MKI = 1; + static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; - static final int INDEX_UNIFIED_UID = 3; + static final int INDEX_UNIFIED_USER_ID = 3; static final int INDEX_UNIFIED_FINGERPRINT = 4; static final int INDEX_UNIFIED_ALGORITHM = 5; static final int INDEX_UNIFIED_KEY_SIZE = 6; static final int INDEX_UNIFIED_CREATION = 7; static final int INDEX_UNIFIED_EXPIRY = 8; - static final String[] KEYS_PROJECTION = new String[] { + static final String[] KEYS_PROJECTION = new String[]{ Keys._ID, Keys.KEY_ID, Keys.RANK, Keys.ALGORITHM, Keys.KEY_SIZE, Keys.HAS_SECRET, Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT, Keys.CAN_SIGN, Keys.IS_REVOKED, @@ -205,7 +174,7 @@ public class ViewKeyMainFragment extends Fragment implements * because the notification triggers faster than the activity closes. */ // Avoid NullPointerExceptions... - if(data.getCount() == 0) { + if (data.getCount() == 0) { return; } // Swap the new cursor in. (The framework will take care of closing the @@ -213,81 +182,24 @@ public class ViewKeyMainFragment extends Fragment implements switch (loader.getId()) { case LOADER_ID_UNIFIED: { if (data.moveToFirst()) { - // get name, email, and comment from USER_ID - String[] mainUserId = PgpKeyHelper.splitUserId(data.getString(INDEX_UNIFIED_UID)); - if (mainUserId[0] != null) { - getActivity().setTitle(mainUserId[0]); - mName.setText(mainUserId[0]); - } else { - getActivity().setTitle(R.string.user_id_no_name); - mName.setText(R.string.user_id_no_name); - } - mEmail.setText(mainUserId[1]); - mComment.setText(mainUserId[2]); - if (data.getInt(INDEX_UNIFIED_HAS_ANY_SECRET) != 0) { - mSecretKey.setTextColor(getResources().getColor(R.color.emphasis)); - mSecretKey.setText(R.string.secret_key_yes); + // certify button + mActionCertify.setVisibility(View.GONE); + mActionCertifyDivider.setVisibility(View.GONE); // edit button mActionEdit.setVisibility(View.VISIBLE); - mActionEdit.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); - editIntent.setData( - KeyRingData.buildSecretKeyRingUri(mDataUri)); - editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY); - startActivityForResult(editIntent, 0); - } - }); + mActionEditDivider.setVisibility(View.VISIBLE); } else { - mSecretKey.setTextColor(Color.BLACK); - mSecretKey.setText(getResources().getString(R.string.secret_key_no)); - // certify button mActionCertify.setVisibility(View.VISIBLE); + mActionCertifyDivider.setVisibility(View.VISIBLE); + // edit button mActionEdit.setVisibility(View.GONE); + mActionEditDivider.setVisibility(View.GONE); } - // get key id from MASTER_KEY_ID - long masterKeyId = data.getLong(INDEX_UNIFIED_MKI); - String keyIdStr = PgpKeyHelper.convertKeyIdToHex(masterKeyId); - mKeyId.setText(keyIdStr); - - // get creation date from CREATION - if (data.isNull(INDEX_UNIFIED_CREATION)) { - mCreation.setText(R.string.none); - } else { - Date creationDate = new Date(data.getLong(INDEX_UNIFIED_CREATION) * 1000); - - mCreation.setText( - DateFormat.getDateFormat(getActivity().getApplicationContext()).format( - creationDate)); - } - - // get expiry date from EXPIRY - if (data.isNull(INDEX_UNIFIED_EXPIRY)) { - mExpiry.setText(R.string.none); - } else { - Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); - - mExpiry.setText( - DateFormat.getDateFormat(getActivity().getApplicationContext()).format( - expiryDate)); - } - - String algorithmStr = PgpKeyHelper.getAlgorithmInfo( - getActivity(), - data.getInt(INDEX_UNIFIED_ALGORITHM), - data.getInt(INDEX_UNIFIED_KEY_SIZE) - ); - mAlgorithm.setText(algorithmStr); - - byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); - String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob); - mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint)); - break; } } @@ -307,11 +219,12 @@ public class ViewKeyMainFragment extends Fragment implements break; } } while (data.moveToNext()); - if (!canEncrypt) { + if (canEncrypt) { + mActionEncrypt.setVisibility(View.VISIBLE); + } else { mActionEncrypt.setVisibility(View.GONE); } - mKeysAdapter.swapCursor(data); break; } getActivity().setProgressBarIndeterminateVisibility(false); @@ -327,16 +240,13 @@ public class ViewKeyMainFragment extends Fragment implements case LOADER_ID_USER_IDS: mUserIdsAdapter.swapCursor(null); break; - case LOADER_ID_KEYS: - mKeysAdapter.swapCursor(null); - break; } } - private void encryptToContact(Uri dataUri) { + private void encrypt(Uri dataUri) { try { long keyId = new ProviderHelper(getActivity()).extractOrGetMasterKeyId(dataUri); - long[] encryptionKeyIds = new long[]{ keyId }; + long[] encryptionKeyIds = new long[]{keyId}; Intent intent = new Intent(getActivity(), EncryptActivity.class); intent.setAction(EncryptActivity.ACTION_ENCRYPT); intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); @@ -347,10 +257,17 @@ public class ViewKeyMainFragment extends Fragment implements } } - private void certifyKey(Uri dataUri) { + private void certify(Uri dataUri) { Intent signIntent = new Intent(getActivity(), CertifyKeyActivity.class); signIntent.setData(dataUri); startActivity(signIntent); } + private void editKey(Uri dataUri) { + Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); + editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri)); + editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY); + startActivityForResult(editIntent, 0); + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java new file mode 100644 index 000000000..aacf30429 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.annotation.TargetApi; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.devspark.appmsg.AppMsg; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.QrCodeUtils; + +import java.io.IOException; + + +public class ViewKeyShareFragment extends Fragment implements + LoaderManager.LoaderCallbacks { + + public static final String ARG_DATA_URI = "uri"; + + private LinearLayout mContainer; + private TextView mFingerprint; + private ImageView mFingerprintQrCode; + private View mFingerprintShareButton; + private View mFingerprintClipboardButton; + private View mKeyShareButton; + private View mKeyClipboardButton; + private View mNfcHelpButton; + private View mNfcPrefsButton; + + ProviderHelper mProviderHelper; + + private static final int QR_CODE_SIZE = 1000; + + private static final int LOADER_ID_UNIFIED = 0; + + private Uri mDataUri; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.view_key_share_fragment, container, false); + + mProviderHelper = new ProviderHelper(ViewKeyShareFragment.this.getActivity()); + + mContainer = (LinearLayout) view.findViewById(R.id.container); + mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint); + mFingerprintQrCode = (ImageView) view.findViewById(R.id.view_key_fingerprint_qr_code_image); + mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share); + mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard); + mKeyShareButton = view.findViewById(R.id.view_key_action_key_share); + mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard); + mNfcHelpButton = view.findViewById(R.id.view_key_action_nfc_help); + mNfcPrefsButton = view.findViewById(R.id.view_key_action_nfc_prefs); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + mNfcPrefsButton.setVisibility(View.VISIBLE); + } else { + mNfcPrefsButton.setVisibility(View.GONE); + } + + mFingerprintQrCode.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showQrCodeDialog(); + } + }); + + mFingerprintShareButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + share(mDataUri, mProviderHelper, true, false); + } + }); + mFingerprintClipboardButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + share(mDataUri, mProviderHelper, true, true); + } + }); + mKeyShareButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + share(mDataUri, mProviderHelper, false, false); + } + }); + mKeyClipboardButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + share(mDataUri, mProviderHelper, false, true); + } + }); + mNfcHelpButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showNfcHelpDialog(); + } + }); + mNfcPrefsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showNfcPrefs(); + } + }); + + return view; + } + + private void share(Uri dataUri, ProviderHelper providerHelper, boolean fingerprintOnly, + boolean toClipboard) { + try { + String content; + if (fingerprintOnly) { + byte[] data = (byte[]) providerHelper.getGenericData( + KeyRings.buildUnifiedKeyRingUri(dataUri), + Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); + String fingerprint = PgpKeyHelper.convertFingerprintToHex(data); + content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; + } else { + // get public keyring as ascii armored string + Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); + content = providerHelper.getKeyRingAsArmoredString(uri); + } + + if (toClipboard) { + ClipboardReflection.copyToClipboard(getActivity(), content); + String message; + if (fingerprintOnly) { + message = getResources().getString(R.string.fingerprint_copied_to_clipboard); + } else { + message = getResources().getString(R.string.key_copied_to_clipboard); + } + AppMsg.makeText(getActivity(), message, AppMsg.STYLE_INFO).show(); + } else { + // Android will fail with android.os.TransactionTooLargeException if key is too big + // see http://www.lonestarprod.com/?p=34 + if (content.length() >= 86389) { + AppMsg.makeText(getActivity(), R.string.key_too_big_for_sharing, + AppMsg.STYLE_ALERT).show(); + return; + } + + // let user choose application + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, content); + sendIntent.setType("text/plain"); + String title; + if (fingerprintOnly) { + title = getResources().getString(R.string.title_share_fingerprint_with); + } else { + title = getResources().getString(R.string.title_share_key_with); + } + startActivity(Intent.createChooser(sendIntent, title)); + } + } catch (IOException e) { + Log.e(Constants.TAG, "error processing key!", e); + AppMsg.makeText(getActivity(), R.string.error_key_processing, AppMsg.STYLE_ALERT).show(); + } catch (ProviderHelper.NotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + AppMsg.makeText(getActivity(), R.string.error_key_not_found, AppMsg.STYLE_ALERT).show(); + } + } + + private void showQrCodeDialog() { + ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(mDataUri, + true); + dialog.show(ViewKeyShareFragment.this.getActivity().getSupportFragmentManager(), "shareQrCodeDialog"); + } + + private void showNfcHelpDialog() { + ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); + dialog.show(getActivity().getSupportFragmentManager(), "shareNfcDialog"); + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + private void showNfcPrefs() { + Intent intentSettings = new Intent( + Settings.ACTION_NFCSHARING_SETTINGS); + startActivity(intentSettings); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); + if (dataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); + getActivity().finish(); + return; + } + + loadData(dataUri); + } + + private void loadData(Uri dataUri) { + getActivity().setProgressBarIndeterminateVisibility(true); + mContainer.setVisibility(View.GONE); + + mDataUri = dataUri; + + Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); + } + + static final String[] UNIFIED_PROJECTION = new String[]{ + KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, + KeyRings.USER_ID, KeyRings.FINGERPRINT, + KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY, + + }; + static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; + static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; + static final int INDEX_UNIFIED_USER_ID = 3; + static final int INDEX_UNIFIED_FINGERPRINT = 4; + static final int INDEX_UNIFIED_ALGORITHM = 5; + static final int INDEX_UNIFIED_KEY_SIZE = 6; + static final int INDEX_UNIFIED_CREATION = 7; + static final int INDEX_UNIFIED_EXPIRY = 8; + + public Loader onCreateLoader(int id, Bundle args) { + switch (id) { + case LOADER_ID_UNIFIED: { + Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); + } + + default: + return null; + } + } + + public void onLoadFinished(Loader loader, Cursor data) { + /* TODO better error handling? May cause problems when a key is deleted, + * because the notification triggers faster than the activity closes. + */ + // Avoid NullPointerExceptions... + if (data.getCount() == 0) { + return; + } + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + switch (loader.getId()) { + case LOADER_ID_UNIFIED: { + if (data.moveToFirst()) { + + byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); + String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob); + mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint)); + + String qrCodeContent = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; + mFingerprintQrCode.setImageBitmap( + QrCodeUtils.getQRCodeBitmap(qrCodeContent, QR_CODE_SIZE) + ); + + break; + } + } + + } + getActivity().setProgressBarIndeterminateVisibility(false); + mContainer.setVisibility(View.VISIBLE); + } + + /** + * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. + * We need to make sure we are no longer using it. + */ + public void onLoaderReset(Loader loader) { + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index f4fa7f3bf..c9070c897 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -28,7 +28,6 @@ import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.LinearLayout; -import android.widget.LinearLayout.LayoutParams; import android.widget.TextView; import org.sufficientlysecure.keychain.R; @@ -106,7 +105,7 @@ public class ImportKeysAdapter extends ArrayAdapter { holder.mainUserId = (TextView) convertView.findViewById(R.id.mainUserId); holder.mainUserIdRest = (TextView) convertView.findViewById(R.id.mainUserIdRest); holder.keyId = (TextView) convertView.findViewById(R.id.keyId); - holder.fingerprint = (TextView) convertView.findViewById(R.id.fingerprint); + holder.fingerprint = (TextView) convertView.findViewById(R.id.view_key_fingerprint); holder.algorithm = (TextView) convertView.findViewById(R.id.algorithm); holder.status = (TextView) convertView.findViewById(R.id.status); holder.userIdsList = (LinearLayout) convertView.findViewById(R.id.user_ids_list); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java index fd864eb09..977740567 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java @@ -17,7 +17,7 @@ package org.sufficientlysecure.keychain.ui.adapter; -import android.content.Context; +import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentPagerAdapter; @@ -26,8 +26,8 @@ import android.support.v7.app.ActionBarActivity; import java.util.ArrayList; public class PagerTabStripAdapter extends FragmentPagerAdapter { - private final Context mContext; - private final ArrayList mTabs = new ArrayList(); + protected final Activity mActivity; + protected final ArrayList mTabs = new ArrayList(); static final class TabInfo { public final Class clss; @@ -43,7 +43,7 @@ public class PagerTabStripAdapter extends FragmentPagerAdapter { public PagerTabStripAdapter(ActionBarActivity activity) { super(activity.getSupportFragmentManager()); - mContext = activity; + mActivity = activity; } public void addTab(Class clss, Bundle args, String title) { @@ -60,7 +60,7 @@ public class PagerTabStripAdapter extends FragmentPagerAdapter { @Override public Fragment getItem(int position) { TabInfo info = mTabs.get(position); - return Fragment.instantiate(mContext, info.clss.getName(), info.args); + return Fragment.instantiate(mActivity, info.clss.getName(), info.args); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java index 52e6dec92..05f8f8860 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java @@ -27,6 +27,7 @@ import android.widget.AdapterView; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import org.sufficientlysecure.keychain.R; @@ -106,40 +107,55 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter implements AdapterView. @Override public void bindView(View view, Context context, Cursor cursor) { - TextView vRank = (TextView) view.findViewById(R.id.rank); - TextView vUserId = (TextView) view.findViewById(R.id.userId); + TextView vName = (TextView) view.findViewById(R.id.userId); TextView vAddress = (TextView) view.findViewById(R.id.address); + TextView vComment = (TextView) view.findViewById(R.id.comment); ImageView vVerified = (ImageView) view.findViewById(R.id.certified); + ImageView vPrimaryUserIdIcon = (ImageView) view.findViewById(R.id.primary_user_id_icon); - if (cursor.getInt(mIsPrimary) > 0) { - vRank.setText("+"); + String[] userId = PgpKeyHelper.splitUserId(cursor.getString(mIndexUserId)); + if (userId[0] != null) { + vName.setText(userId[0]); } else { - vRank.setText(Integer.toString(cursor.getInt(mIndexRank))); + vName.setText(R.string.user_id_no_name); + } + if (userId[1] != null) { + vAddress.setText(userId[1]); + vAddress.setVisibility(View.VISIBLE); + } else { + vAddress.setVisibility(View.GONE); + } + if (userId[2] != null) { + vComment.setText(userId[2]); + vComment.setVisibility(View.VISIBLE); + } else { + vComment.setVisibility(View.GONE); } - String[] userId = PgpKeyHelper.splitUserId(cursor.getString(mIndexUserId)); - if (userId[0] != null) { - vUserId.setText(userId[0]); + // show small star icon for primary user ids + if (cursor.getInt(mIsPrimary) > 0) { + vPrimaryUserIdIcon.setVisibility(View.VISIBLE); } else { - vUserId.setText(R.string.user_id_no_name); + vPrimaryUserIdIcon.setVisibility(View.GONE); } - vAddress.setText(userId[1]); if (cursor.getInt(mIsRevoked) > 0) { - vRank.setText(" "); + // no star icon for revoked user ids! + vPrimaryUserIdIcon.setVisibility(View.GONE); + + // set revocation icon vVerified.setImageResource(R.drawable.key_certify_revoke); // disable and strike through text for revoked user ids - vUserId.setEnabled(false); + vName.setEnabled(false); vAddress.setEnabled(false); - vUserId.setText(OtherHelper.strikeOutText(vUserId.getText())); + vName.setText(OtherHelper.strikeOutText(vName.getText())); vAddress.setText(OtherHelper.strikeOutText(vAddress.getText())); } else { - vUserId.setEnabled(true); + vName.setEnabled(true); vAddress.setEnabled(true); int verified = cursor.getInt(mVerifiedId); - // TODO introduce own resources for this :) switch (verified) { case Certs.VERIFIED_SECRET: vVerified.setImageResource(R.drawable.key_certify_ok_depth0); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/SlidingTabLayout.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/SlidingTabLayout.java new file mode 100644 index 000000000..065034be1 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/SlidingTabLayout.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.sufficientlysecure.keychain.util; + +import android.content.Context; +import android.graphics.Typeface; +import android.os.Build; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.HorizontalScrollView; +import android.widget.TextView; + +/** + * Copied from http://developer.android.com/samples/SlidingTabsColors/index.html + */ + +/** + * To be used with ViewPager to provide a tab indicator component which give constant feedback as to + * the user's scroll progress. + *

+ * To use the component, simply add it to your view hierarchy. Then in your + * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call + * {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for. + *

+ * The colors can be customized in two ways. The first and simplest is to provide an array of colors + * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The + * alternative is via the {@link TabColorizer} interface which provides you complete control over + * which color is used for any individual position. + *

+ * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)}, + * providing the layout ID of your custom layout. + */ +public class SlidingTabLayout extends HorizontalScrollView { + + /** + * Allows complete control over the colors drawn in the tab layout. Set with + * {@link #setCustomTabColorizer(TabColorizer)}. + */ + public interface TabColorizer { + + /** + * @return return the color of the indicator used when {@code position} is selected. + */ + int getIndicatorColor(int position); + + /** + * @return return the color of the divider drawn to the right of {@code position}. + */ + int getDividerColor(int position); + + } + + private static final int TITLE_OFFSET_DIPS = 24; + private static final int TAB_VIEW_PADDING_DIPS = 16; + private static final int TAB_VIEW_TEXT_SIZE_SP = 12; + + private int mTitleOffset; + + private int mTabViewLayoutId; + private int mTabViewTextViewId; + + private ViewPager mViewPager; + private ViewPager.OnPageChangeListener mViewPagerPageChangeListener; + + private final SlidingTabStrip mTabStrip; + + public SlidingTabLayout(Context context) { + this(context, null); + } + + public SlidingTabLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + // Disable the Scroll Bar + setHorizontalScrollBarEnabled(false); + // Make sure that the Tab Strips fills this View + setFillViewport(true); + + mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density); + + mTabStrip = new SlidingTabStrip(context); + addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + } + + /** + * Set the custom {@link TabColorizer} to be used. + *

+ * If you only require simple custmisation then you can use + * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve + * similar effects. + */ + public void setCustomTabColorizer(TabColorizer tabColorizer) { + mTabStrip.setCustomTabColorizer(tabColorizer); + } + + /** + * Sets the colors to be used for indicating the selected tab. These colors are treated as a + * circular array. Providing one color will mean that all tabs are indicated with the same color. + */ + public void setSelectedIndicatorColors(int... colors) { + mTabStrip.setSelectedIndicatorColors(colors); + } + + /** + * Sets the colors to be used for tab dividers. These colors are treated as a circular array. + * Providing one color will mean that all tabs are indicated with the same color. + */ + public void setDividerColors(int... colors) { + mTabStrip.setDividerColors(colors); + } + + /** + * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are + * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so + * that the layout can update it's scroll position correctly. + * + * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener) + */ + public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { + mViewPagerPageChangeListener = listener; + } + + /** + * Set the custom layout to be inflated for the tab views. + * + * @param layoutResId Layout id to be inflated + * @param textViewId id of the {@link TextView} in the inflated view + */ + public void setCustomTabView(int layoutResId, int textViewId) { + mTabViewLayoutId = layoutResId; + mTabViewTextViewId = textViewId; + } + + /** + * Sets the associated view pager. Note that the assumption here is that the pager content + * (number of tabs and tab titles) does not change after this call has been made. + */ + public void setViewPager(ViewPager viewPager) { + mTabStrip.removeAllViews(); + + mViewPager = viewPager; + if (viewPager != null) { + viewPager.setOnPageChangeListener(new InternalViewPagerListener()); + populateTabStrip(); + } + } + + /** + * Create a default view to be used for tabs. This is called if a custom tab view is not set via + * {@link #setCustomTabView(int, int)}. + */ + protected TextView createDefaultTabView(Context context) { + TextView textView = new TextView(context); + textView.setGravity(Gravity.CENTER); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP); + textView.setTypeface(Typeface.DEFAULT_BOLD); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + // If we're running on Honeycomb or newer, then we can use the Theme's + // selectableItemBackground to ensure that the View has a pressed state + TypedValue outValue = new TypedValue(); + getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, + outValue, true); + textView.setBackgroundResource(outValue.resourceId); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + // If we're running on ICS or newer, enable all-caps to match the Action Bar tab style + textView.setAllCaps(true); + } + + int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density); + textView.setPadding(padding, padding, padding, padding); + + return textView; + } + + private void populateTabStrip() { + final PagerAdapter adapter = mViewPager.getAdapter(); + final View.OnClickListener tabClickListener = new TabClickListener(); + + for (int i = 0; i < adapter.getCount(); i++) { + View tabView = null; + TextView tabTitleView = null; + + if (mTabViewLayoutId != 0) { + // If there is a custom tab view layout id set, try and inflate it + tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip, + false); + tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId); + } + + if (tabView == null) { + tabView = createDefaultTabView(getContext()); + } + + if (tabTitleView == null && TextView.class.isInstance(tabView)) { + tabTitleView = (TextView) tabView; + } + + tabTitleView.setText(adapter.getPageTitle(i)); + tabView.setOnClickListener(tabClickListener); + + mTabStrip.addView(tabView); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + if (mViewPager != null) { + scrollToTab(mViewPager.getCurrentItem(), 0); + } + } + + private void scrollToTab(int tabIndex, int positionOffset) { + final int tabStripChildCount = mTabStrip.getChildCount(); + if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) { + return; + } + + View selectedChild = mTabStrip.getChildAt(tabIndex); + if (selectedChild != null) { + int targetScrollX = selectedChild.getLeft() + positionOffset; + + if (tabIndex > 0 || positionOffset > 0) { + // If we're not at the first child and are mid-scroll, make sure we obey the offset + targetScrollX -= mTitleOffset; + } + + scrollTo(targetScrollX, 0); + } + } + + private class InternalViewPagerListener implements ViewPager.OnPageChangeListener { + private int mScrollState; + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + int tabStripChildCount = mTabStrip.getChildCount(); + if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) { + return; + } + + mTabStrip.onViewPagerPageChanged(position, positionOffset); + + View selectedTitle = mTabStrip.getChildAt(position); + int extraOffset = (selectedTitle != null) + ? (int) (positionOffset * selectedTitle.getWidth()) + : 0; + scrollToTab(position, extraOffset); + + if (mViewPagerPageChangeListener != null) { + mViewPagerPageChangeListener.onPageScrolled(position, positionOffset, + positionOffsetPixels); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + mScrollState = state; + + if (mViewPagerPageChangeListener != null) { + mViewPagerPageChangeListener.onPageScrollStateChanged(state); + } + } + + @Override + public void onPageSelected(int position) { + if (mScrollState == ViewPager.SCROLL_STATE_IDLE) { + mTabStrip.onViewPagerPageChanged(position, 0f); + scrollToTab(position, 0); + } + + if (mViewPagerPageChangeListener != null) { + mViewPagerPageChangeListener.onPageSelected(position); + } + } + + } + + private class TabClickListener implements View.OnClickListener { + @Override + public void onClick(View v) { + for (int i = 0; i < mTabStrip.getChildCount(); i++) { + if (v == mTabStrip.getChildAt(i)) { + mViewPager.setCurrentItem(i); + return; + } + } + } + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/SlidingTabStrip.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/SlidingTabStrip.java new file mode 100644 index 000000000..4b8c7e75d --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/SlidingTabStrip.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.sufficientlysecure.keychain.util; + +import android.R; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; +import android.widget.LinearLayout; + +/** + * Copied from http://developer.android.com/samples/SlidingTabsColors/index.html + */ +class SlidingTabStrip extends LinearLayout { + + private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2; + private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26; + private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8; + private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5; + + private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1; + private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20; + private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f; + + private final int mBottomBorderThickness; + private final Paint mBottomBorderPaint; + + private final int mSelectedIndicatorThickness; + private final Paint mSelectedIndicatorPaint; + + private final int mDefaultBottomBorderColor; + + private final Paint mDividerPaint; + private final float mDividerHeight; + + private int mSelectedPosition; + private float mSelectionOffset; + + private SlidingTabLayout.TabColorizer mCustomTabColorizer; + private final SimpleTabColorizer mDefaultTabColorizer; + + SlidingTabStrip(Context context) { + this(context, null); + } + + SlidingTabStrip(Context context, AttributeSet attrs) { + super(context, attrs); + setWillNotDraw(false); + + final float density = getResources().getDisplayMetrics().density; + + TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true); + final int themeForegroundColor = outValue.data; + + mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor, + DEFAULT_BOTTOM_BORDER_COLOR_ALPHA); + + mDefaultTabColorizer = new SimpleTabColorizer(); + mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR); + mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor, + DEFAULT_DIVIDER_COLOR_ALPHA)); + + mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density); + mBottomBorderPaint = new Paint(); + mBottomBorderPaint.setColor(mDefaultBottomBorderColor); + + mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density); + mSelectedIndicatorPaint = new Paint(); + + mDividerHeight = DEFAULT_DIVIDER_HEIGHT; + mDividerPaint = new Paint(); + mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density)); + } + + void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) { + mCustomTabColorizer = customTabColorizer; + invalidate(); + } + + void setSelectedIndicatorColors(int... colors) { + // Make sure that the custom colorizer is removed + mCustomTabColorizer = null; + mDefaultTabColorizer.setIndicatorColors(colors); + invalidate(); + } + + void setDividerColors(int... colors) { + // Make sure that the custom colorizer is removed + mCustomTabColorizer = null; + mDefaultTabColorizer.setDividerColors(colors); + invalidate(); + } + + void onViewPagerPageChanged(int position, float positionOffset) { + mSelectedPosition = position; + mSelectionOffset = positionOffset; + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + final int height = getHeight(); + final int childCount = getChildCount(); + final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height); + final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null + ? mCustomTabColorizer + : mDefaultTabColorizer; + + // Thick colored underline below the current selection + if (childCount > 0) { + View selectedTitle = getChildAt(mSelectedPosition); + int left = selectedTitle.getLeft(); + int right = selectedTitle.getRight(); + int color = tabColorizer.getIndicatorColor(mSelectedPosition); + + if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) { + int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1); + if (color != nextColor) { + color = blendColors(nextColor, color, mSelectionOffset); + } + + // Draw the selection partway between the tabs + View nextTitle = getChildAt(mSelectedPosition + 1); + left = (int) (mSelectionOffset * nextTitle.getLeft() + + (1.0f - mSelectionOffset) * left); + right = (int) (mSelectionOffset * nextTitle.getRight() + + (1.0f - mSelectionOffset) * right); + } + + mSelectedIndicatorPaint.setColor(color); + + canvas.drawRect(left, height - mSelectedIndicatorThickness, right, + height, mSelectedIndicatorPaint); + } + + // Thin underline along the entire bottom edge + canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint); + + // Vertical separators between the titles + int separatorTop = (height - dividerHeightPx) / 2; + for (int i = 0; i < childCount - 1; i++) { + View child = getChildAt(i); + mDividerPaint.setColor(tabColorizer.getDividerColor(i)); + canvas.drawLine(child.getRight(), separatorTop, child.getRight(), + separatorTop + dividerHeightPx, mDividerPaint); + } + } + + /** + * Set the alpha value of the {@code color} to be the given {@code alpha} value. + */ + private static int setColorAlpha(int color, byte alpha) { + return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color)); + } + + /** + * Blend {@code color1} and {@code color2} using the given ratio. + * + * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend, + * 0.0 will return {@code color2}. + */ + private static int blendColors(int color1, int color2, float ratio) { + final float inverseRation = 1f - ratio; + float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation); + float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation); + float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation); + return Color.rgb((int) r, (int) g, (int) b); + } + + private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer { + private int[] mIndicatorColors; + private int[] mDividerColors; + + @Override + public final int getIndicatorColor(int position) { + return mIndicatorColors[position % mIndicatorColors.length]; + } + + @Override + public final int getDividerColor(int position) { + return mDividerColors[position % mDividerColors.length]; + } + + void setIndicatorColors(int... colors) { + mIndicatorColors = colors; + } + + void setDividerColors(int... colors) { + mDividerColors = colors; + } + } +} \ No newline at end of file -- cgit v1.2.3 From 90b4db07925ec4741fedfa75eed4ed6acc533696 Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Sun, 4 May 2014 17:16:58 -0700 Subject: Per pull-request comments. --- .../keychain/ui/ImportKeysKeybaseFragment.java | 22 +++++++++++++++++----- .../ui/adapter/ImportKeysListKeybaseLoader.java | 3 --- .../ui/adapter/ImportKeysListServerLoader.java | 3 --- .../keychain/util/HkpKeyServer.java | 16 ---------------- .../sufficientlysecure/keychain/util/JWalk.java | 17 +++++++++++++++++ .../keychain/util/KeyServer.java | 18 ++++++++++++++++++ .../keychain/util/KeybaseKeyServer.java | 18 ------------------ 7 files changed, 52 insertions(+), 45 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysKeybaseFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysKeybaseFragment.java index 7ae57cec3..a996079c9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysKeybaseFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysKeybaseFragment.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * 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 . + */ + package org.sufficientlysecure.keychain.ui; import android.content.Context; @@ -29,7 +46,6 @@ public class ImportKeysKeybaseFragment extends Fragment { private EditText mQueryEditText; public static final String ARG_QUERY = "query"; - public static final String ARG_DISABLE_QUERY_EDIT = "disable_query_edit"; /** * Creates new instance of this fragment @@ -95,10 +111,6 @@ public class ImportKeysKeybaseFragment extends Fragment { String query = getArguments().getString(ARG_QUERY); mQueryEditText.setText(query, TextView.BufferType.EDITABLE); } - - if (getArguments().getBoolean(ARG_DISABLE_QUERY_EDIT, false)) { - mQueryEditText.setEnabled(false); - } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java index 73ff9a8f8..e66032482 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java @@ -94,13 +94,10 @@ public class ImportKeysListKeybaseLoader mEntryList.addAll(searchResult); mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, null); } catch (KeyServer.InsufficientQuery e) { - Log.e(Constants.TAG, "InsufficientQuery", e); mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); } catch (KeyServer.QueryException e) { - Log.e(Constants.TAG, "QueryException", e); mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); } catch (KeyServer.TooManyResponses e) { - Log.e(Constants.TAG, "TooManyResponses", e); mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java index 838aeefee..65810064c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java @@ -116,13 +116,10 @@ public class ImportKeysListServerLoader } mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, null); } catch (KeyServer.InsufficientQuery e) { - Log.e(Constants.TAG, "InsufficientQuery", e); mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); } catch (KeyServer.QueryException e) { - Log.e(Constants.TAG, "QueryException", e); mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); } catch (KeyServer.TooManyResponses e) { - Log.e(Constants.TAG, "TooManyResponses", e); mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java index cf658b0b6..b81fba05d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java @@ -34,7 +34,6 @@ import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; @@ -167,21 +166,6 @@ public class HkpKeyServer extends KeyServer { mPort = port; } - private static String readAll(InputStream in, String encoding) throws IOException { - ByteArrayOutputStream raw = new ByteArrayOutputStream(); - - byte buffer[] = new byte[1 << 16]; - int n = 0; - while ((n = in.read(buffer)) != -1) { - raw.write(buffer, 0, n); - } - - if (encoding == null) { - encoding = "utf8"; - } - return raw.toString(encoding); - } - private String query(String request) throws QueryException, HttpError { InetAddress ips[]; try { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java index 6f9c4cfa5..7ae1d8fab 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2014 Tim Bray + * + * 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 . + */ + package org.sufficientlysecure.keychain.util; import org.json.JSONArray; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java index 2b97165ac..94c02a773 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java @@ -20,6 +20,9 @@ package org.sufficientlysecure.keychain.util; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.List; public abstract class KeyServer { @@ -49,4 +52,19 @@ public abstract class KeyServer { abstract String get(String keyIdHex) throws QueryException; abstract void add(String armoredKey) throws AddKeyException; + + public static String readAll(InputStream in, String encoding) throws IOException { + ByteArrayOutputStream raw = new ByteArrayOutputStream(); + + byte buffer[] = new byte[1 << 16]; + int n = 0; + while ((n = in.read(buffer)) != -1) { + raw.write(buffer, 0, n); + } + + if (encoding == null) { + encoding = "utf8"; + } + return raw.toString(encoding); + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java index dee3899a8..fb58e9f1d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java @@ -24,9 +24,6 @@ import org.json.JSONObject; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; @@ -39,21 +36,6 @@ public class KeybaseKeyServer extends KeyServer { private WeakHashMap mKeyCache = new WeakHashMap(); - private static String readAll(InputStream in, String encoding) throws IOException { - ByteArrayOutputStream raw = new ByteArrayOutputStream(); - - byte buffer[] = new byte[1 << 16]; - int n = 0; - while ((n = in.read(buffer)) != -1) { - raw.write(buffer, 0, n); - } - - if (encoding == null) { - encoding = "utf8"; - } - return raw.toString(encoding); - } - @Override public ArrayList search(String query) throws QueryException, TooManyResponses, InsufficientQuery { -- cgit v1.2.3 From 158c2466bfa5a7871807386dc96bc6ec3c0a8dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 5 May 2014 10:13:44 +0200 Subject: Fix license header --- .../keychain/util/KeybaseKeyServer.java | 23 +++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java index fb58e9f1d..654fe55f8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java @@ -1,19 +1,18 @@ /* - * Copyright (C) 2012-2014 Dominik Schürmann - * Copyright (C) 2011-2014 Thialfihar - * Copyright (C) 2011 Senecaso + * Copyright (C) 2014 Tim Bray * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 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. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package org.sufficientlysecure.keychain.util; -- cgit v1.2.3 From 0fe08233723e46ec966919cf358a30d6c289375e Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 5 May 2014 22:04:57 +0200 Subject: ui: remove primary subkey info --- .../keychain/ui/ViewKeyKeysFragment.java | 120 ++------------------- 1 file changed, 7 insertions(+), 113 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java index bb0e4b23a..9ab6878d0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java @@ -50,18 +50,8 @@ public class ViewKeyKeysFragment extends Fragment implements public static final String ARG_DATA_URI = "uri"; private LinearLayout mContainer; - private TextView mAlgorithm; - private TextView mKeyId; - private TextView mExpiry; - private TextView mCreation; - private TextView mFingerprint; - private TextView mSecretKey; - private ListView mKeys; - private static final int LOADER_ID_UNIFIED = 0; - private static final int LOADER_ID_KEYS = 1; - private ViewKeyKeysAdapter mKeysAdapter; private Uri mDataUri; @@ -71,12 +61,6 @@ public class ViewKeyKeysFragment extends Fragment implements View view = inflater.inflate(R.layout.view_key_keys_fragment, container, false); mContainer = (LinearLayout) view.findViewById(R.id.container); - mKeyId = (TextView) view.findViewById(R.id.key_id); - mAlgorithm = (TextView) view.findViewById(R.id.algorithm); - mCreation = (TextView) view.findViewById(R.id.creation); - mExpiry = (TextView) view.findViewById(R.id.expiry); - mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint); - mSecretKey = (TextView) view.findViewById(R.id.secret_key); mKeys = (ListView) view.findViewById(R.id.keys); return view; @@ -109,116 +93,30 @@ public class ViewKeyKeysFragment extends Fragment implements // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. - getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); - getLoaderManager().initLoader(LOADER_ID_KEYS, null, this); + getLoaderManager().initLoader(0, null, this); } - static final String[] UNIFIED_PROJECTION = new String[] { - KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, - KeyRings.USER_ID, KeyRings.FINGERPRINT, - KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY, - - }; - static final int INDEX_UNIFIED_MKI = 1; - static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; - static final int INDEX_UNIFIED_UID = 3; - static final int INDEX_UNIFIED_FINGERPRINT = 4; - static final int INDEX_UNIFIED_ALGORITHM = 5; - static final int INDEX_UNIFIED_KEY_SIZE = 6; - static final int INDEX_UNIFIED_CREATION = 7; - static final int INDEX_UNIFIED_EXPIRY = 8; - static final String[] KEYS_PROJECTION = new String[] { Keys._ID, Keys.KEY_ID, Keys.RANK, Keys.ALGORITHM, Keys.KEY_SIZE, Keys.HAS_SECRET, Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT, Keys.CAN_SIGN, Keys.IS_REVOKED, Keys.CREATION, Keys.EXPIRY, Keys.FINGERPRINT }; - static final int KEYS_INDEX_CAN_ENCRYPT = 7; public Loader onCreateLoader(int id, Bundle args) { - switch (id) { - case LOADER_ID_UNIFIED: { - Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); - } - case LOADER_ID_KEYS: { - Uri baseUri = Keys.buildKeysUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, null); - } - - default: - return null; - } + Uri baseUri = Keys.buildKeysUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, null); } public void onLoadFinished(Loader loader, Cursor data) { - /* TODO better error handling? May cause problems when a key is deleted, - * because the notification triggers faster than the activity closes. - */ - // Avoid NullPointerExceptions... + // Avoid NullPointerExceptions, if we get an empty result set. if(data.getCount() == 0) { return; } // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) - switch (loader.getId()) { - case LOADER_ID_UNIFIED: { - if (data.moveToFirst()) { - if (data.getInt(INDEX_UNIFIED_HAS_ANY_SECRET) != 0) { - mSecretKey.setTextColor(getResources().getColor(R.color.emphasis)); - mSecretKey.setText(R.string.secret_key_yes); - } else { - mSecretKey.setTextColor(Color.BLACK); - mSecretKey.setText(getResources().getString(R.string.secret_key_no)); - } - - // get key id from MASTER_KEY_ID - long masterKeyId = data.getLong(INDEX_UNIFIED_MKI); - String keyIdStr = PgpKeyHelper.convertKeyIdToHex(masterKeyId); - mKeyId.setText(keyIdStr); - - // get creation date from CREATION - if (data.isNull(INDEX_UNIFIED_CREATION)) { - mCreation.setText(R.string.none); - } else { - Date creationDate = new Date(data.getLong(INDEX_UNIFIED_CREATION) * 1000); - - mCreation.setText( - DateFormat.getDateFormat(getActivity().getApplicationContext()).format( - creationDate)); - } - - // get expiry date from EXPIRY - if (data.isNull(INDEX_UNIFIED_EXPIRY)) { - mExpiry.setText(R.string.none); - } else { - Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); - - mExpiry.setText( - DateFormat.getDateFormat(getActivity().getApplicationContext()).format( - expiryDate)); - } - - String algorithmStr = PgpKeyHelper.getAlgorithmInfo( - getActivity(), - data.getInt(INDEX_UNIFIED_ALGORITHM), - data.getInt(INDEX_UNIFIED_KEY_SIZE) - ); - mAlgorithm.setText(algorithmStr); - - byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); - String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob); - mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint)); - - break; - } - } - - case LOADER_ID_KEYS: - mKeysAdapter.swapCursor(data); - break; - } + mKeysAdapter.swapCursor(data); + getActivity().setProgressBarIndeterminateVisibility(false); mContainer.setVisibility(View.VISIBLE); } @@ -228,11 +126,7 @@ public class ViewKeyKeysFragment extends Fragment implements * We need to make sure we are no longer using it. */ public void onLoaderReset(Loader loader) { - switch (loader.getId()) { - case LOADER_ID_KEYS: - mKeysAdapter.swapCursor(null); - break; - } + mKeysAdapter.swapCursor(null); } } -- cgit v1.2.3 From 162cb1cb7b6e3908716a6e874b6bcba4b3d825e3 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 5 May 2014 22:06:09 +0200 Subject: ui: subkey view redesign --- .../keychain/ui/adapter/ViewKeyKeysAdapter.java | 44 +++++++--------------- 1 file changed, 13 insertions(+), 31 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java index 9e26e559f..f4942a2a0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java @@ -121,35 +121,17 @@ public class ViewKeyKeysAdapter extends CursorAdapter { keyId.setText(keyIdStr); // may be set with additional "stripped" later on if (hasAnySecret && cursor.getInt(mIndexHasSecret) == 0) { - keyDetails.setText("(" + algorithmStr + ", " + - context.getString(R.string.key_stripped) + ")"); + keyDetails.setText(algorithmStr + ", " + + context.getString(R.string.key_stripped)); } else { - keyDetails.setText("(" + algorithmStr + ")"); + keyDetails.setText(algorithmStr); } - if (cursor.getInt(mIndexRank) == 0) { - masterKeyIcon.setVisibility(View.INVISIBLE); - } else { - masterKeyIcon.setVisibility(View.VISIBLE); - } - - if (cursor.getInt(mIndexCanCertify) != 1) { - certifyIcon.setVisibility(View.GONE); - } else { - certifyIcon.setVisibility(View.VISIBLE); - } - - if (cursor.getInt(mIndexCanEncrypt) != 1) { - encryptIcon.setVisibility(View.GONE); - } else { - encryptIcon.setVisibility(View.VISIBLE); - } - - if (cursor.getInt(mIndexCanSign) != 1) { - signIcon.setVisibility(View.GONE); - } else { - signIcon.setVisibility(View.VISIBLE); - } + // Set icons according to properties + masterKeyIcon.setVisibility(cursor.getInt(mIndexRank) == 0 ? View.VISIBLE : View.INVISIBLE); + certifyIcon.setVisibility(cursor.getInt(mIndexCanCertify) != 0 ? View.VISIBLE : View.GONE); + encryptIcon.setVisibility(cursor.getInt(mIndexCanEncrypt) != 0 ? View.VISIBLE : View.GONE); + signIcon.setVisibility(cursor.getInt(mIndexCanSign) != 0 ? View.VISIBLE : View.GONE); boolean valid = true; if (cursor.getInt(mIndexRevokedKey) > 0) { @@ -168,13 +150,13 @@ public class ViewKeyKeysAdapter extends CursorAdapter { Date expiryDate = new Date(cursor.getLong(mIndexExpiry) * 1000); valid = valid && expiryDate.after(new Date()); - keyExpiry.setText("(" + + keyExpiry.setText( context.getString(R.string.label_expiry) + ": " + - DateFormat.getDateFormat(context).format(expiryDate) + ")"); - - keyExpiry.setVisibility(View.VISIBLE); + DateFormat.getDateFormat(context).format(expiryDate)); } else { - keyExpiry.setVisibility(View.GONE); + keyExpiry.setText( + context.getString(R.string.label_expiry) + ": " + + context.getString(R.string.none)); } // if key is expired or revoked, strike through text -- cgit v1.2.3 From d31ae89824b9a86d0e70f384b5fd5ac212a3e6cd Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 6 May 2014 00:04:37 +0200 Subject: ui: show revocation and expiry status on info tab --- .../keychain/ui/ViewKeyMainFragment.java | 71 ++++++++++++---------- 1 file changed, 40 insertions(+), 31 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index 43e484ffe..46c726ac3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -25,6 +25,7 @@ import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; +import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -40,12 +41,16 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter; import org.sufficientlysecure.keychain.util.Log; +import java.util.Date; + public class ViewKeyMainFragment extends Fragment implements LoaderManager.LoaderCallbacks { public static final String ARG_DATA_URI = "uri"; private LinearLayout mContainer; + private View mStatusRevoked; + private View mStatusExpired; private View mActionEdit; private View mActionEditDivider; private View mActionEncrypt; @@ -56,7 +61,6 @@ public class ViewKeyMainFragment extends Fragment implements private static final int LOADER_ID_UNIFIED = 0; private static final int LOADER_ID_USER_IDS = 1; - private static final int LOADER_ID_KEYS = 2; private ViewKeyUserIdsAdapter mUserIdsAdapter; @@ -68,6 +72,8 @@ public class ViewKeyMainFragment extends Fragment implements mContainer = (LinearLayout) view.findViewById(R.id.container); mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); + mStatusRevoked = view.findViewById(R.id.view_key_revoked); + mStatusExpired = view.findViewById(R.id.view_key_expired); mActionEdit = view.findViewById(R.id.view_key_action_edit); mActionEditDivider = view.findViewById(R.id.view_key_action_edit_divider); mActionEncrypt = view.findViewById(R.id.view_key_action_encrypt); @@ -123,23 +129,25 @@ public class ViewKeyMainFragment extends Fragment implements // or start new ones. getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); - getLoaderManager().initLoader(LOADER_ID_KEYS, null, this); } static final String[] UNIFIED_PROJECTION = new String[]{ - KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, + KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, KeyRings.IS_REVOKED, KeyRings.USER_ID, KeyRings.FINGERPRINT, KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY, + KeyRings.HAS_ENCRYPT }; static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; - static final int INDEX_UNIFIED_USER_ID = 3; - static final int INDEX_UNIFIED_FINGERPRINT = 4; - static final int INDEX_UNIFIED_ALGORITHM = 5; - static final int INDEX_UNIFIED_KEY_SIZE = 6; - static final int INDEX_UNIFIED_CREATION = 7; - static final int INDEX_UNIFIED_EXPIRY = 8; + static final int INDEX_UNIFIED_IS_REVOKED = 3; + static final int INDEX_UNIFIED_USER_ID = 4; + static final int INDEX_UNIFIED_FINGERPRINT = 5; + static final int INDEX_UNIFIED_ALGORITHM = 6; + static final int INDEX_UNIFIED_KEY_SIZE = 7; + static final int INDEX_UNIFIED_CREATION = 8; + static final int INDEX_UNIFIED_EXPIRY = 9; + static final int INDEX_UNIFIED_HAS_ENCRYPT = 10; static final String[] KEYS_PROJECTION = new String[]{ Keys._ID, @@ -159,10 +167,6 @@ public class ViewKeyMainFragment extends Fragment implements Uri baseUri = UserIds.buildUserIdsUri(mDataUri); return new CursorLoader(getActivity(), baseUri, ViewKeyUserIdsAdapter.USER_IDS_PROJECTION, null, null, null); } - case LOADER_ID_KEYS: { - Uri baseUri = Keys.buildKeysUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, null); - } default: return null; @@ -200,6 +204,29 @@ public class ViewKeyMainFragment extends Fragment implements mActionEditDivider.setVisibility(View.GONE); } + // It's easier to reset to defaults beforehand, saves some nasty else clauses + mStatusRevoked.setVisibility(View.GONE); + mStatusExpired.setVisibility(View.GONE); + mActionCertify.setEnabled(true); + mActionEdit.setEnabled(true); + mActionEncrypt.setEnabled(true); + + // If this key is revoked, it cannot be used for anything! + if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) { + mStatusRevoked.setVisibility(View.VISIBLE); + mActionCertify.setEnabled(false); + mActionEdit.setEnabled(false); + mActionEncrypt.setEnabled(false); + } else { + Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); + if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) { + mStatusExpired.setVisibility(View.VISIBLE); + mActionCertify.setEnabled(false); + mActionEncrypt.setEnabled(false); + // mActionEdit is still fine + } + } + break; } } @@ -208,24 +235,6 @@ public class ViewKeyMainFragment extends Fragment implements mUserIdsAdapter.swapCursor(data); break; - case LOADER_ID_KEYS: - // hide encrypt button if no encryption key is available - // TODO: do with subquery! - boolean canEncrypt = false; - data.moveToFirst(); - do { - if (data.getInt(KEYS_INDEX_CAN_ENCRYPT) == 1) { - canEncrypt = true; - break; - } - } while (data.moveToNext()); - if (canEncrypt) { - mActionEncrypt.setVisibility(View.VISIBLE); - } else { - mActionEncrypt.setVisibility(View.GONE); - } - - break; } getActivity().setProgressBarIndeterminateVisibility(false); mContainer.setVisibility(View.VISIBLE); -- cgit v1.2.3 From 8564c4aca15f3dff339063054e137602dff42567 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 6 May 2014 00:39:09 +0200 Subject: ui: use primary icon color for certification status --- .../keychain/ui/adapter/ViewKeyUserIdsAdapter.java | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java index 05f8f8860..64452e8b4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java @@ -111,7 +111,6 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter implements AdapterView. TextView vAddress = (TextView) view.findViewById(R.id.address); TextView vComment = (TextView) view.findViewById(R.id.comment); ImageView vVerified = (ImageView) view.findViewById(R.id.certified); - ImageView vPrimaryUserIdIcon = (ImageView) view.findViewById(R.id.primary_user_id_icon); String[] userId = PgpKeyHelper.splitUserId(cursor.getString(mIndexUserId)); if (userId[0] != null) { @@ -133,17 +132,11 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter implements AdapterView. } // show small star icon for primary user ids - if (cursor.getInt(mIsPrimary) > 0) { - vPrimaryUserIdIcon.setVisibility(View.VISIBLE); - } else { - vPrimaryUserIdIcon.setVisibility(View.GONE); - } + boolean isPrimary = cursor.getInt(mIsPrimary) != 0; if (cursor.getInt(mIsRevoked) > 0) { - // no star icon for revoked user ids! - vPrimaryUserIdIcon.setVisibility(View.GONE); - // set revocation icon + // set revocation icon (can this even be primary?) vVerified.setImageResource(R.drawable.key_certify_revoke); // disable and strike through text for revoked user ids @@ -158,10 +151,14 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter implements AdapterView. int verified = cursor.getInt(mVerifiedId); switch (verified) { case Certs.VERIFIED_SECRET: - vVerified.setImageResource(R.drawable.key_certify_ok_depth0); + vVerified.setImageResource(isPrimary + ? R.drawable.key_certify_primary_ok_depth0 + : R.drawable.key_certify_ok_depth0); break; case Certs.VERIFIED_SELF: - vVerified.setImageResource(R.drawable.key_certify_ok_self); + vVerified.setImageResource(isPrimary + ? R.drawable.key_certify_primary_ok_self + : R.drawable.key_certify_ok_self); break; default: vVerified.setImageResource(R.drawable.key_certify_error); -- cgit v1.2.3 From f91457e07fd3f38ba5cd4d07bb0b708a3a5beb17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 6 May 2014 15:04:09 +0200 Subject: Touch view only once --- .../keychain/ui/ViewKeyMainFragment.java | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index 46c726ac3..ded457eca 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -204,26 +204,28 @@ public class ViewKeyMainFragment extends Fragment implements mActionEditDivider.setVisibility(View.GONE); } - // It's easier to reset to defaults beforehand, saves some nasty else clauses - mStatusRevoked.setVisibility(View.GONE); - mStatusExpired.setVisibility(View.GONE); - mActionCertify.setEnabled(true); - mActionEdit.setEnabled(true); - mActionEncrypt.setEnabled(true); - // If this key is revoked, it cannot be used for anything! if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) { mStatusRevoked.setVisibility(View.VISIBLE); - mActionCertify.setEnabled(false); + mStatusExpired.setVisibility(View.GONE); + mActionEdit.setEnabled(false); + mActionCertify.setEnabled(false); mActionEncrypt.setEnabled(false); } else { + mActionEdit.setEnabled(true); + Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) { + mStatusRevoked.setVisibility(View.GONE); mStatusExpired.setVisibility(View.VISIBLE); mActionCertify.setEnabled(false); mActionEncrypt.setEnabled(false); - // mActionEdit is still fine + } else { + mStatusRevoked.setVisibility(View.GONE); + mStatusExpired.setVisibility(View.GONE); + mActionCertify.setEnabled(true); + mActionEncrypt.setEnabled(true); } } -- cgit v1.2.3 From 0d05ff98cb7ef992a040e7040c4fc534307e51e8 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 6 May 2014 19:18:32 +0200 Subject: ui: use textviews instead of bootstrap buttons in SignEncrypt --- .../keychain/ui/EncryptFileFragment.java | 4 ++-- .../keychain/ui/EncryptMessageFragment.java | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java index b8ac59dac..d150abdeb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java @@ -67,7 +67,7 @@ public class EncryptFileFragment extends Fragment { private CheckBox mDeleteAfter = null; private CheckBox mShareAfter = null; private BootstrapButton mBrowse = null; - private BootstrapButton mEncryptFile; + private View mEncryptFile; private FileDialogFragment mFileDialog; @@ -92,7 +92,7 @@ public class EncryptFileFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.encrypt_file_fragment, container, false); - mEncryptFile = (BootstrapButton) view.findViewById(R.id.action_encrypt_file); + mEncryptFile = view.findViewById(R.id.action_encrypt_file); mEncryptFile.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java index 0a1a3474a..4c35806e5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java @@ -28,9 +28,8 @@ import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.EditText; +import android.widget.TextView; -import com.beardedhen.androidbootstrap.BootstrapButton; import com.devspark.appmsg.AppMsg; import org.sufficientlysecure.keychain.Constants; @@ -46,9 +45,9 @@ import org.sufficientlysecure.keychain.util.Log; public class EncryptMessageFragment extends Fragment { public static final String ARG_TEXT = "text"; - private EditText mMessage = null; - private BootstrapButton mEncryptShare; - private BootstrapButton mEncryptClipboard; + private TextView mMessage = null; + private View mEncryptShare; + private View mEncryptClipboard; private EncryptActivityInterface mEncryptInterface; @@ -70,9 +69,9 @@ public class EncryptMessageFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.encrypt_message_fragment, container, false); - mMessage = (EditText) view.findViewById(R.id.message); - mEncryptClipboard = (BootstrapButton) view.findViewById(R.id.action_encrypt_clipboard); - mEncryptShare = (BootstrapButton) view.findViewById(R.id.action_encrypt_share); + mMessage = (TextView) view.findViewById(R.id.message); + mEncryptClipboard = view.findViewById(R.id.action_encrypt_clipboard); + mEncryptShare = view.findViewById(R.id.action_encrypt_share); mEncryptClipboard.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { -- cgit v1.2.3 From e0985878d732674626eee947a8d27c7a9193495c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 6 May 2014 19:18:32 +0200 Subject: ui: use textview buttons in decrypt verify dialogue --- .../org/sufficientlysecure/keychain/ui/DecryptFileFragment.java | 4 ++-- .../sufficientlysecure/keychain/ui/DecryptMessageFragment.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java index 0f88ee753..d953e2591 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java @@ -54,7 +54,7 @@ public class DecryptFileFragment extends DecryptFragment { private EditText mFilename; private CheckBox mDeleteAfter; private BootstrapButton mBrowse; - private BootstrapButton mDecryptButton; + private View mDecryptButton; private String mInputFilename = null; private String mOutputFilename = null; @@ -71,7 +71,7 @@ public class DecryptFileFragment extends DecryptFragment { mFilename = (EditText) view.findViewById(R.id.decrypt_file_filename); mBrowse = (BootstrapButton) view.findViewById(R.id.decrypt_file_browse); mDeleteAfter = (CheckBox) view.findViewById(R.id.decrypt_file_delete_after_decryption); - mDecryptButton = (BootstrapButton) view.findViewById(R.id.decrypt_file_action_decrypt); + mDecryptButton = view.findViewById(R.id.decrypt_file_action_decrypt); mBrowse.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { FileHelper.openFile(DecryptFileFragment.this, mFilename.getText().toString(), "*/*", diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java index 454ee4415..ddc326acf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java @@ -47,8 +47,8 @@ public class DecryptMessageFragment extends DecryptFragment { // view private EditText mMessage; - private BootstrapButton mDecryptButton; - private BootstrapButton mDecryptFromCLipboardButton; + private View mDecryptButton; + private View mDecryptFromCLipboardButton; // model private String mCiphertext; @@ -61,8 +61,8 @@ public class DecryptMessageFragment extends DecryptFragment { View view = inflater.inflate(R.layout.decrypt_message_fragment, container, false); mMessage = (EditText) view.findViewById(R.id.message); - mDecryptButton = (BootstrapButton) view.findViewById(R.id.action_decrypt); - mDecryptFromCLipboardButton = (BootstrapButton) view.findViewById(R.id.action_decrypt_from_clipboard); + mDecryptButton = view.findViewById(R.id.action_decrypt); + mDecryptFromCLipboardButton = view.findViewById(R.id.action_decrypt_from_clipboard); mDecryptButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { -- cgit v1.2.3 From 797aeaf6e8c7a8df39ee325c39924cf1f1a96778 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 6 May 2014 19:18:32 +0200 Subject: ui: apply purple theme (twi is best color) --- .../main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java | 2 +- .../main/java/org/sufficientlysecure/keychain/util/SlidingTabStrip.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') 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 6bb2209ea..955f8324e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -192,7 +192,7 @@ public class DecryptFragment extends Fragment { mLookupKey.setVisibility(View.GONE); // successful decryption-only - mResultLayout.setBackgroundColor(getResources().getColor(R.color.result_blue)); + mResultLayout.setBackgroundColor(getResources().getColor(R.color.result_purple)); mResultText.setText(R.string.decrypt_result_decrypted); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/SlidingTabStrip.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/SlidingTabStrip.java index 4b8c7e75d..9ce6f943e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/SlidingTabStrip.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/SlidingTabStrip.java @@ -34,7 +34,7 @@ class SlidingTabStrip extends LinearLayout { private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2; private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26; private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8; - private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5; + private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFFAA66CC; private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1; private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20; -- cgit v1.2.3 From ad791fd8f8c19be95beaf5d1dcc1a38faaa1a08e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 6 May 2014 22:29:57 +0200 Subject: Move logic classes for import into own sub-package --- .../keychain/keyimport/HkpKeyServer.java | 338 +++++++++++++++++++++ .../keychain/keyimport/ImportKeysListEntry.java | 268 ++++++++++++++++ .../keychain/keyimport/KeyServer.java | 68 +++++ .../keychain/keyimport/KeybaseKeyServer.java | 161 ++++++++++ .../keychain/pgp/PgpImportExport.java | 13 +- .../keychain/service/KeychainIntentService.java | 9 +- .../keychain/ui/ImportKeysActivity.java | 2 +- .../keychain/ui/ImportKeysListFragment.java | 4 +- .../keychain/ui/adapter/ImportKeysAdapter.java | 1 + .../keychain/ui/adapter/ImportKeysListEntry.java | 269 ---------------- .../ui/adapter/ImportKeysListKeybaseLoader.java | 5 +- .../keychain/ui/adapter/ImportKeysListLoader.java | 1 + .../ui/adapter/ImportKeysListServerLoader.java | 5 +- .../keychain/util/HkpKeyServer.java | 338 --------------------- .../keychain/util/InputData.java | 3 + .../keychain/util/IntentIntegratorSupportV4.java | 2 + .../keychain/util/KeyServer.java | 70 ----- .../keychain/util/KeybaseKeyServer.java | 160 ---------- .../keychain/util/KeychainServiceListener.java | 22 -- .../keychain/util/QrCodeUtils.java | 3 + 20 files changed, 866 insertions(+), 876 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyServer.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeyServer.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyServer.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyServer.java new file mode 100644 index 000000000..85ce6bfcc --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyServer.java @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2012-2014 Dominik Schürmann + * Copyright (C) 2011-2014 Thialfihar + * Copyright (C) 2011 Senecaso + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.sufficientlysecure.keychain.keyimport; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.PgpHelper; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class HkpKeyServer extends KeyServer { + private static class HttpError extends Exception { + private static final long serialVersionUID = 1718783705229428893L; + private int mCode; + private String mData; + + public HttpError(int code, String data) { + super("" + code + ": " + data); + mCode = code; + mData = data; + } + + public int getCode() { + return mCode; + } + + public String getData() { + return mData; + } + } + + private String mHost; + private short mPort; + + /** + * pub:%keyid%:%algo%:%keylen%:%creationdate%:%expirationdate%:%flags% + *

    + *
  • %keyid% = this is either the fingerprint or the key ID of the key. + * Either the 16-digit or 8-digit key IDs are acceptable, but obviously the fingerprint is best. + *
  • + *
  • %algo% = the algorithm number, (i.e. 1==RSA, 17==DSA, etc). + * See RFC-2440
  • + *
  • %keylen% = the key length (i.e. 1024, 2048, 4096, etc.)
  • + *
  • %creationdate% = creation date of the key in standard + * RFC-2440 form (i.e. number of + * seconds since 1/1/1970 UTC time)
  • + *
  • %expirationdate% = expiration date of the key in standard + * RFC-2440 form (i.e. number of + * seconds since 1/1/1970 UTC time)
  • + *
  • %flags% = letter codes to indicate details of the key, if any. Flags may be in any + * order. The meaning of "disabled" is implementation-specific. Note that individual flags may + * be unimplemented, so the absence of a given flag does not necessarily mean the absence of the + * detail. + *
      + *
    • r == revoked
    • + *
    • d == disabled
    • + *
    • e == expired
    • + *
    + *
  • + *
+ * + * @see + * 5.2. Machine Readable Indexes + * in Internet-Draft OpenPGP HTTP Keyserver Protocol Document + */ + public static final Pattern PUB_KEY_LINE = Pattern + .compile("pub:([0-9a-fA-F]+):([0-9]+):([0-9]+):([0-9]+):([0-9]*):([rde]*)[ \n\r]*" // pub line + + "(uid:(.*):([0-9]+):([0-9]*):([rde]*))+", // one or more uid lines + Pattern.CASE_INSENSITIVE); + + /** + * uid:%escaped uid string%:%creationdate%:%expirationdate%:%flags% + *
    + *
  • %escaped uid string% = the user ID string, with HTTP %-escaping for anything that + * isn't 7-bit safe as well as for the ":" character. Any other characters may be escaped, as + * desired.
  • + *
  • %creationdate% = creation date of the key in standard + * RFC-2440 form (i.e. number of + * seconds since 1/1/1970 UTC time)
  • + *
  • %expirationdate% = expiration date of the key in standard + * RFC-2440 form (i.e. number of + * seconds since 1/1/1970 UTC time)
  • + *
  • %flags% = letter codes to indicate details of the key, if any. Flags may be in any + * order. The meaning of "disabled" is implementation-specific. Note that individual flags may + * be unimplemented, so the absence of a given flag does not necessarily mean the absence of + * the detail. + *
      + *
    • r == revoked
    • + *
    • d == disabled
    • + *
    • e == expired
    • + *
    + *
  • + *
+ */ + public static final Pattern UID_LINE = Pattern + .compile("uid:(.*):([0-9]+):([0-9]*):([rde]*)", + Pattern.CASE_INSENSITIVE); + + private static final short PORT_DEFAULT = 11371; + + /** + * @param hostAndPort may be just + * "hostname" (eg. "pool.sks-keyservers.net"), then it will + * connect using {@link #PORT_DEFAULT}. However, port may be specified after colon + * ("hostname:port", eg. "p80.pool.sks-keyservers.net:80"). + */ + public HkpKeyServer(String hostAndPort) { + String host = hostAndPort; + short port = PORT_DEFAULT; + final int colonPosition = hostAndPort.lastIndexOf(':'); + if (colonPosition > 0) { + host = hostAndPort.substring(0, colonPosition); + final String portStr = hostAndPort.substring(colonPosition + 1); + port = Short.decode(portStr); + } + mHost = host; + mPort = port; + } + + public HkpKeyServer(String host, short port) { + mHost = host; + mPort = port; + } + + private String query(String request) throws QueryException, HttpError { + InetAddress ips[]; + try { + ips = InetAddress.getAllByName(mHost); + } catch (UnknownHostException e) { + throw new QueryException(e.toString()); + } + for (int i = 0; i < ips.length; ++i) { + try { + String url = "http://" + ips[i].getHostAddress() + ":" + mPort + request; + Log.d(Constants.TAG, "hkp keyserver query: " + url); + URL realUrl = new URL(url); + HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection(); + conn.setConnectTimeout(5000); + conn.setReadTimeout(25000); + conn.connect(); + int response = conn.getResponseCode(); + if (response >= 200 && response < 300) { + return readAll(conn.getInputStream(), conn.getContentEncoding()); + } else { + String data = readAll(conn.getErrorStream(), conn.getContentEncoding()); + throw new HttpError(response, data); + } + } catch (MalformedURLException e) { + // nothing to do, try next IP + } catch (IOException e) { + // nothing to do, try next IP + } + } + + throw new QueryException("querying server(s) for '" + mHost + "' failed"); + } + + @Override + public ArrayList search(String query) throws QueryException, TooManyResponses, + InsufficientQuery { + ArrayList results = new ArrayList(); + + if (query.length() < 3) { + throw new InsufficientQuery(); + } + + String encodedQuery; + try { + encodedQuery = URLEncoder.encode(query, "utf8"); + } catch (UnsupportedEncodingException e) { + return null; + } + String request = "/pks/lookup?op=index&options=mr&search=" + encodedQuery; + + String data; + try { + data = query(request); + } catch (HttpError e) { + if (e.getCode() == 404) { + return results; + } else { + if (e.getData().toLowerCase(Locale.US).contains("no keys found")) { + return results; + } else if (e.getData().toLowerCase(Locale.US).contains("too many")) { + throw new TooManyResponses(); + } else if (e.getData().toLowerCase(Locale.US).contains("insufficient")) { + throw new InsufficientQuery(); + } + } + throw new QueryException("querying server(s) for '" + mHost + "' failed"); + } + + final Matcher matcher = PUB_KEY_LINE.matcher(data); + while (matcher.find()) { + final ImportKeysListEntry entry = new ImportKeysListEntry(); + + entry.setBitStrength(Integer.parseInt(matcher.group(3))); + + final int algorithmId = Integer.decode(matcher.group(2)); + entry.setAlgorithm(PgpKeyHelper.getAlgorithmInfo(algorithmId)); + + // group 1 contains the full fingerprint (v4) or the long key id if available + // see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr + String fingerprintOrKeyId = matcher.group(1); + if (fingerprintOrKeyId.length() > 16) { + entry.setFingerPrintHex(fingerprintOrKeyId.toLowerCase(Locale.US)); + entry.setKeyIdHex("0x" + fingerprintOrKeyId.substring(fingerprintOrKeyId.length() + - 16, fingerprintOrKeyId.length())); + } else { + // set key id only + entry.setKeyIdHex("0x" + fingerprintOrKeyId); + } + + final long creationDate = Long.parseLong(matcher.group(4)); + final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + tmpGreg.setTimeInMillis(creationDate * 1000); + entry.setDate(tmpGreg.getTime()); + + entry.setRevoked(matcher.group(6).contains("r")); + + ArrayList userIds = new ArrayList(); + final String uidLines = matcher.group(7); + final Matcher uidMatcher = UID_LINE.matcher(uidLines); + while (uidMatcher.find()) { + String tmp = uidMatcher.group(1).trim(); + if (tmp.contains("%")) { + try { + // converts Strings like "Universit%C3%A4t" to a proper encoding form "Universität". + tmp = (URLDecoder.decode(tmp, "UTF8")); + } catch (UnsupportedEncodingException ignored) { + // will never happen, because "UTF8" is supported + } + } + userIds.add(tmp); + } + entry.setUserIds(userIds); + entry.setPrimaryUserId(userIds.get(0)); + + results.add(entry); + } + return results; + } + + @Override + public String get(String keyIdHex) throws QueryException { + HttpClient client = new DefaultHttpClient(); + try { + String query = "http://" + mHost + ":" + mPort + + "/pks/lookup?op=get&options=mr&search=" + keyIdHex; + Log.d(Constants.TAG, "hkp keyserver get: " + query); + HttpGet get = new HttpGet(query); + HttpResponse response = client.execute(get); + if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + throw new QueryException("not found"); + } + + HttpEntity entity = response.getEntity(); + InputStream is = entity.getContent(); + String data = readAll(is, EntityUtils.getContentCharSet(entity)); + Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(data); + if (matcher.find()) { + return matcher.group(1); + } + } catch (IOException e) { + // nothing to do, better luck on the next keyserver + } finally { + client.getConnectionManager().shutdown(); + } + + return null; + } + + @Override + public void add(String armoredKey) throws AddKeyException { + HttpClient client = new DefaultHttpClient(); + try { + String query = "http://" + mHost + ":" + mPort + "/pks/add"; + HttpPost post = new HttpPost(query); + Log.d(Constants.TAG, "hkp keyserver add: " + query); + List nameValuePairs = new ArrayList(2); + nameValuePairs.add(new BasicNameValuePair("keytext", armoredKey)); + post.setEntity(new UrlEncodedFormEntity(nameValuePairs)); + + HttpResponse response = client.execute(post); + if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + throw new AddKeyException(); + } + } catch (IOException e) { + // nothing to do, better luck on the next keyserver + } finally { + client.getConnectionManager().shutdown(); + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java new file mode 100644 index 000000000..1199290e0 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.keyimport; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; + +import org.spongycastle.bcpg.SignatureSubpacketTags; +import org.spongycastle.openpgp.PGPKeyRing; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.util.IterableIterator; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; + +public class ImportKeysListEntry implements Serializable, Parcelable { + private static final long serialVersionUID = -7797972103284992662L; + + public ArrayList userIds; + public long keyId; + public String keyIdHex; + public boolean revoked; + public Date date; // TODO: not displayed + public String fingerPrintHex; + public int bitStrength; + public String algorithm; + public boolean secretKey; + public String mPrimaryUserId; + + private boolean mSelected; + + private byte[] mBytes = new byte[]{}; + + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mPrimaryUserId); + dest.writeStringList(userIds); + dest.writeLong(keyId); + dest.writeByte((byte) (revoked ? 1 : 0)); + dest.writeSerializable(date); + dest.writeString(fingerPrintHex); + dest.writeString(keyIdHex); + dest.writeInt(bitStrength); + dest.writeString(algorithm); + dest.writeByte((byte) (secretKey ? 1 : 0)); + dest.writeByte((byte) (mSelected ? 1 : 0)); + dest.writeInt(mBytes.length); + dest.writeByteArray(mBytes); + } + + public static final Creator CREATOR = new Creator() { + public ImportKeysListEntry createFromParcel(final Parcel source) { + ImportKeysListEntry vr = new ImportKeysListEntry(); + vr.mPrimaryUserId = source.readString(); + vr.userIds = new ArrayList(); + source.readStringList(vr.userIds); + vr.keyId = source.readLong(); + vr.revoked = source.readByte() == 1; + vr.date = (Date) source.readSerializable(); + vr.fingerPrintHex = source.readString(); + vr.keyIdHex = source.readString(); + vr.bitStrength = source.readInt(); + vr.algorithm = source.readString(); + vr.secretKey = source.readByte() == 1; + vr.mSelected = source.readByte() == 1; + vr.mBytes = new byte[source.readInt()]; + source.readByteArray(vr.mBytes); + + return vr; + } + + public ImportKeysListEntry[] newArray(final int size) { + return new ImportKeysListEntry[size]; + } + }; + + public String getKeyIdHex() { + return keyIdHex; + } + + public byte[] getBytes() { + return mBytes; + } + + public void setBytes(byte[] bytes) { + this.mBytes = bytes; + } + + public boolean isSelected() { + return mSelected; + } + + public void setSelected(boolean selected) { + this.mSelected = selected; + } + + public long getKeyId() { + return keyId; + } + + public void setKeyId(long keyId) { + this.keyId = keyId; + } + + public void setKeyIdHex(String keyIdHex) { + this.keyIdHex = keyIdHex; + } + + public boolean isRevoked() { + return revoked; + } + + public void setRevoked(boolean revoked) { + this.revoked = revoked; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public String getFingerPrintHex() { + return fingerPrintHex; + } + + public void setFingerPrintHex(String fingerPrintHex) { + this.fingerPrintHex = fingerPrintHex; + } + + public int getBitStrength() { + return bitStrength; + } + + public void setBitStrength(int bitStrength) { + this.bitStrength = bitStrength; + } + + public String getAlgorithm() { + return algorithm; + } + + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + public boolean isSecretKey() { + return secretKey; + } + + public void setSecretKey(boolean secretKey) { + this.secretKey = secretKey; + } + + public ArrayList getUserIds() { + return userIds; + } + + public void setUserIds(ArrayList userIds) { + this.userIds = userIds; + } + + public String getPrimaryUserId() { + return mPrimaryUserId; + } + + public void setPrimaryUserId(String uid) { + mPrimaryUserId = uid; + } + + /** + * Constructor for later querying from keyserver + */ + public ImportKeysListEntry() { + // keys from keyserver are always public keys; from keybase too + secretKey = false; + // do not select by default + mSelected = false; + userIds = new ArrayList(); + } + + /** + * Constructor based on key object, used for import from NFC, QR Codes, files + */ + @SuppressWarnings("unchecked") + public ImportKeysListEntry(Context context, PGPKeyRing pgpKeyRing) { + // save actual key object into entry, used to import it later + try { + this.mBytes = pgpKeyRing.getEncoded(); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException on pgpKeyRing.getEncoded()", e); + } + + // selected is default + this.mSelected = true; + + if (pgpKeyRing instanceof PGPSecretKeyRing) { + secretKey = true; + } else { + secretKey = false; + } + PGPPublicKey key = pgpKeyRing.getPublicKey(); + + userIds = new ArrayList(); + for (String userId : new IterableIterator(key.getUserIDs())) { + userIds.add(userId); + for (PGPSignature sig : new IterableIterator(key.getSignaturesForID(userId))) { + if (sig.getHashedSubPackets() != null + && sig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.PRIMARY_USER_ID)) { + try { + // make sure it's actually valid + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider( + Constants.BOUNCY_CASTLE_PROVIDER_NAME), key); + if (sig.verifyCertification(userId, key)) { + mPrimaryUserId = userId; + } + } catch (Exception e) { + // nothing bad happens, the key is just not considered the primary key id + } + } + + } + } + // if there was no user id flagged as primary, use the first one + if (mPrimaryUserId == null) { + mPrimaryUserId = userIds.get(0); + } + + this.keyId = key.getKeyID(); + this.keyIdHex = PgpKeyHelper.convertKeyIdToHex(keyId); + + this.revoked = key.isRevoked(); + this.fingerPrintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint()); + this.bitStrength = key.getBitStrength(); + final int algorithm = key.getAlgorithm(); + this.algorithm = PgpKeyHelper.getAlgorithmInfo(context, algorithm); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeyServer.java new file mode 100644 index 000000000..d6ebca5a6 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeyServer.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2012-2014 Dominik Schürmann + * Copyright (C) 2011-2014 Thialfihar + * Copyright (C) 2011 Senecaso + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.sufficientlysecure.keychain.keyimport; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +public abstract class KeyServer { + public static class QueryException extends Exception { + private static final long serialVersionUID = 2703768928624654512L; + + public QueryException(String message) { + super(message); + } + } + + public static class TooManyResponses extends Exception { + private static final long serialVersionUID = 2703768928624654513L; + } + + public static class InsufficientQuery extends Exception { + private static final long serialVersionUID = 2703768928624654514L; + } + + public static class AddKeyException extends Exception { + private static final long serialVersionUID = -507574859137295530L; + } + + abstract List search(String query) throws QueryException, TooManyResponses, + InsufficientQuery; + + abstract String get(String keyIdHex) throws QueryException; + + abstract void add(String armoredKey) throws AddKeyException; + + public static String readAll(InputStream in, String encoding) throws IOException { + ByteArrayOutputStream raw = new ByteArrayOutputStream(); + + byte buffer[] = new byte[1 << 16]; + int n = 0; + while ((n = in.read(buffer)) != -1) { + raw.write(buffer, 0, n); + } + + if (encoding == null) { + encoding = "utf8"; + } + return raw.toString(encoding); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyServer.java new file mode 100644 index 000000000..7ffe123c0 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyServer.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2014 Tim Bray + * + * 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 . + */ + +package org.sufficientlysecure.keychain.keyimport; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.JWalk; +import org.sufficientlysecure.keychain.util.Log; + +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.GregorianCalendar; +import java.util.TimeZone; +import java.util.WeakHashMap; + +public class KeybaseKeyServer extends KeyServer { + + private WeakHashMap mKeyCache = new WeakHashMap(); + + @Override + public ArrayList search(String query) throws QueryException, TooManyResponses, + InsufficientQuery { + ArrayList results = new ArrayList(); + + JSONObject fromQuery = getFromKeybase("_/api/1.0/user/autocomplete.json?q=", query); + try { + + JSONArray matches = JWalk.getArray(fromQuery, "completions"); + for (int i = 0; i < matches.length(); i++) { + JSONObject match = matches.getJSONObject(i); + + // only list them if they have a key + if (JWalk.optObject(match, "components", "key_fingerprint") != null) { + results.add(makeEntry(match)); + } + } + } catch (Exception e) { + throw new QueryException("Unexpected structure in keybase search result: " + e.getMessage()); + } + + return results; + } + + private JSONObject getUser(String keybaseID) throws QueryException { + try { + return getFromKeybase("_/api/1.0/user/lookup.json?username=", keybaseID); + } catch (Exception e) { + String detail = ""; + if (keybaseID != null) { + detail = ". Query was for user '" + keybaseID + "'"; + } + throw new QueryException(e.getMessage() + detail); + } + } + + private ImportKeysListEntry makeEntry(JSONObject match) throws QueryException, JSONException { + + String keybaseID = JWalk.getString(match, "components", "username", "val"); + String key_fingerprint = JWalk.getString(match, "components", "key_fingerprint", "val"); + key_fingerprint = key_fingerprint.replace(" ", "").toUpperCase(); + match = getUser(keybaseID); + + final ImportKeysListEntry entry = new ImportKeysListEntry(); + + // TODO: Fix; have suggested keybase provide this value to avoid search-time crypto calls + entry.setBitStrength(4096); + entry.setAlgorithm("RSA"); + entry.setKeyIdHex("0x" + key_fingerprint); + entry.setRevoked(false); + + // ctime + final long creationDate = JWalk.getLong(match, "them", "public_keys", "primary", "ctime"); + final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + tmpGreg.setTimeInMillis(creationDate * 1000); + entry.setDate(tmpGreg.getTime()); + + // key bits + // we have to fetch the user object to construct the search-result list, so we might as + // well (weakly) remember the key, in case they try to import it + mKeyCache.put(keybaseID, JWalk.getString(match,"them", "public_keys", "primary", "bundle")); + + // String displayName = JWalk.getString(match, "them", "profile", "full_name"); + ArrayList userIds = new ArrayList(); + String name = "keybase.io/" + keybaseID + " <" + keybaseID + "@keybase.io>"; + userIds.add(name); + userIds.add(keybaseID); + entry.setUserIds(userIds); + entry.setPrimaryUserId(name); + return entry; + } + + private JSONObject getFromKeybase(String path, String query) throws QueryException { + try { + String url = "https://keybase.io/" + path + URLEncoder.encode(query, "utf8"); + Log.d(Constants.TAG, "keybase query: " + url); + + URL realUrl = new URL(url); + HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection(); + conn.setConnectTimeout(5000); // TODO: Reasonable values for keybase + conn.setReadTimeout(25000); + conn.connect(); + int response = conn.getResponseCode(); + if (response >= 200 && response < 300) { + String text = readAll(conn.getInputStream(), conn.getContentEncoding()); + try { + JSONObject json = new JSONObject(text); + if (JWalk.getInt(json, "status", "code") != 0) { + throw new QueryException("Keybase autocomplete search failed"); + } + return json; + } catch (JSONException e) { + throw new QueryException("Keybase.io query returned broken JSON"); + } + } else { + String message = readAll(conn.getErrorStream(), conn.getContentEncoding()); + throw new QueryException("Keybase.io query error (status=" + response + + "): " + message); + } + } catch (Exception e) { + throw new QueryException("Keybase.io query error"); + } + } + + @Override + public String get(String id) throws QueryException { + String key = mKeyCache.get(id); + if (key == null) { + try { + JSONObject user = getUser(id); + key = JWalk.getString(user, "them", "public_keys", "primary", "bundle"); + } catch (Exception e) { + throw new QueryException(e.getMessage()); + } + } + return key; + } + + @Override + public void add(String armoredKey) throws AddKeyException { + throw new AddKeyException(); + } +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java index bfbcd582e..ca9edf7ae 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -32,15 +32,13 @@ import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; -import org.sufficientlysecure.keychain.util.HkpKeyServer; +import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; +import org.sufficientlysecure.keychain.keyimport.HkpKeyServer; import org.sufficientlysecure.keychain.util.IterableIterator; -import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException; -import org.sufficientlysecure.keychain.util.KeychainServiceListener; +import org.sufficientlysecure.keychain.keyimport.KeyServer.AddKeyException; import org.sufficientlysecure.keychain.util.Log; import java.io.ByteArrayOutputStream; @@ -51,6 +49,11 @@ import java.util.List; public class PgpImportExport { + // TODO: is this really used? + public interface KeychainServiceListener { + boolean hasServiceStopped(); + } + private Context mContext; private Progressable mProgressable; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index eabcfadee..d2e9533a7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -53,11 +53,10 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; -import org.sufficientlysecure.keychain.util.HkpKeyServer; +import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; +import org.sufficientlysecure.keychain.keyimport.HkpKeyServer; import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.KeybaseKeyServer; -import org.sufficientlysecure.keychain.util.KeychainServiceListener; +import org.sufficientlysecure.keychain.keyimport.KeybaseKeyServer; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressScaler; @@ -80,7 +79,7 @@ import java.util.List; * after doing them. */ public class KeychainIntentService extends IntentService - implements Progressable, KeychainServiceListener { + implements Progressable, PgpImportExport.KeychainServiceListener { /* extras that can be given by intent */ public static final String EXTRA_MESSENGER = "messenger"; 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 650e51069..66224dd0b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -47,7 +47,7 @@ import org.sufficientlysecure.keychain.helper.ActionBarHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; +import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.ui.dialog.BadImportKeyDialogFragment; import org.sufficientlysecure.keychain.util.Log; 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 c1aa8a1f2..bf6abcd6f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -33,12 +33,12 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; +import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListKeybaseLoader; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader; import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.KeyServer; +import org.sufficientlysecure.keychain.keyimport.KeyServer; import org.sufficientlysecure.keychain.util.Log; import java.io.ByteArrayInputStream; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index c9070c897..9d323c822 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -31,6 +31,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import java.util.ArrayList; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java deleted file mode 100644 index 1610bfeab..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.content.Context; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.SparseArray; - -import org.spongycastle.bcpg.SignatureSubpacketTags; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.util.IterableIterator; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.IOException; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; - -public class ImportKeysListEntry implements Serializable, Parcelable { - private static final long serialVersionUID = -7797972103284992662L; - - public ArrayList userIds; - public long keyId; - public String keyIdHex; - public boolean revoked; - public Date date; // TODO: not displayed - public String fingerPrintHex; - public int bitStrength; - public String algorithm; - public boolean secretKey; - public String mPrimaryUserId; - - private boolean mSelected; - - private byte[] mBytes = new byte[]{}; - - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mPrimaryUserId); - dest.writeStringList(userIds); - dest.writeLong(keyId); - dest.writeByte((byte) (revoked ? 1 : 0)); - dest.writeSerializable(date); - dest.writeString(fingerPrintHex); - dest.writeString(keyIdHex); - dest.writeInt(bitStrength); - dest.writeString(algorithm); - dest.writeByte((byte) (secretKey ? 1 : 0)); - dest.writeByte((byte) (mSelected ? 1 : 0)); - dest.writeInt(mBytes.length); - dest.writeByteArray(mBytes); - } - - public static final Creator CREATOR = new Creator() { - public ImportKeysListEntry createFromParcel(final Parcel source) { - ImportKeysListEntry vr = new ImportKeysListEntry(); - vr.mPrimaryUserId = source.readString(); - vr.userIds = new ArrayList(); - source.readStringList(vr.userIds); - vr.keyId = source.readLong(); - vr.revoked = source.readByte() == 1; - vr.date = (Date) source.readSerializable(); - vr.fingerPrintHex = source.readString(); - vr.keyIdHex = source.readString(); - vr.bitStrength = source.readInt(); - vr.algorithm = source.readString(); - vr.secretKey = source.readByte() == 1; - vr.mSelected = source.readByte() == 1; - vr.mBytes = new byte[source.readInt()]; - source.readByteArray(vr.mBytes); - - return vr; - } - - public ImportKeysListEntry[] newArray(final int size) { - return new ImportKeysListEntry[size]; - } - }; - - public String getKeyIdHex() { - return keyIdHex; - } - - public byte[] getBytes() { - return mBytes; - } - - public void setBytes(byte[] bytes) { - this.mBytes = bytes; - } - - public boolean isSelected() { - return mSelected; - } - - public void setSelected(boolean selected) { - this.mSelected = selected; - } - - public long getKeyId() { - return keyId; - } - - public void setKeyId(long keyId) { - this.keyId = keyId; - } - - public void setKeyIdHex(String keyIdHex) { - this.keyIdHex = keyIdHex; - } - - public boolean isRevoked() { - return revoked; - } - - public void setRevoked(boolean revoked) { - this.revoked = revoked; - } - - public Date getDate() { - return date; - } - - public void setDate(Date date) { - this.date = date; - } - - public String getFingerPrintHex() { - return fingerPrintHex; - } - - public void setFingerPrintHex(String fingerPrintHex) { - this.fingerPrintHex = fingerPrintHex; - } - - public int getBitStrength() { - return bitStrength; - } - - public void setBitStrength(int bitStrength) { - this.bitStrength = bitStrength; - } - - public String getAlgorithm() { - return algorithm; - } - - public void setAlgorithm(String algorithm) { - this.algorithm = algorithm; - } - - public boolean isSecretKey() { - return secretKey; - } - - public void setSecretKey(boolean secretKey) { - this.secretKey = secretKey; - } - - public ArrayList getUserIds() { - return userIds; - } - - public void setUserIds(ArrayList userIds) { - this.userIds = userIds; - } - - public String getPrimaryUserId() { - return mPrimaryUserId; - } - - public void setPrimaryUserId(String uid) { - mPrimaryUserId = uid; - } - - /** - * Constructor for later querying from keyserver - */ - public ImportKeysListEntry() { - // keys from keyserver are always public keys; from keybase too - secretKey = false; - // do not select by default - mSelected = false; - userIds = new ArrayList(); - } - - /** - * Constructor based on key object, used for import from NFC, QR Codes, files - */ - @SuppressWarnings("unchecked") - public ImportKeysListEntry(Context context, PGPKeyRing pgpKeyRing) { - // save actual key object into entry, used to import it later - try { - this.mBytes = pgpKeyRing.getEncoded(); - } catch (IOException e) { - Log.e(Constants.TAG, "IOException on pgpKeyRing.getEncoded()", e); - } - - // selected is default - this.mSelected = true; - - if (pgpKeyRing instanceof PGPSecretKeyRing) { - secretKey = true; - } else { - secretKey = false; - } - PGPPublicKey key = pgpKeyRing.getPublicKey(); - - userIds = new ArrayList(); - for (String userId : new IterableIterator(key.getUserIDs())) { - userIds.add(userId); - for (PGPSignature sig : new IterableIterator(key.getSignaturesForID(userId))) { - if (sig.getHashedSubPackets() != null - && sig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.PRIMARY_USER_ID)) { - try { - // make sure it's actually valid - sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME), key); - if (sig.verifyCertification(userId, key)) { - mPrimaryUserId = userId; - } - } catch (Exception e) { - // nothing bad happens, the key is just not considered the primary key id - } - } - - } - } - // if there was no user id flagged as primary, use the first one - if (mPrimaryUserId == null) { - mPrimaryUserId = userIds.get(0); - } - - this.keyId = key.getKeyID(); - this.keyIdHex = PgpKeyHelper.convertKeyIdToHex(keyId); - - this.revoked = key.isRevoked(); - this.fingerPrintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint()); - this.bitStrength = key.getBitStrength(); - final int algorithm = key.getAlgorithm(); - this.algorithm = PgpKeyHelper.getAlgorithmInfo(context, algorithm); - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java index e66032482..420880522 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java @@ -21,8 +21,9 @@ import android.content.Context; import android.support.v4.content.AsyncTaskLoader; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.KeyServer; -import org.sufficientlysecure.keychain.util.KeybaseKeyServer; +import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; +import org.sufficientlysecure.keychain.keyimport.KeyServer; +import org.sufficientlysecure.keychain.keyimport.KeybaseKeyServer; import org.sufficientlysecure.keychain.util.Log; import java.util.ArrayList; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java index 3fd5d5daf..b6c829677 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -24,6 +24,7 @@ import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPUtil; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.PositionAwareInputStream; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java index 65810064c..4175592d6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java @@ -21,8 +21,9 @@ import android.content.Context; import android.support.v4.content.AsyncTaskLoader; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.HkpKeyServer; -import org.sufficientlysecure.keychain.util.KeyServer; +import org.sufficientlysecure.keychain.keyimport.HkpKeyServer; +import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; +import org.sufficientlysecure.keychain.keyimport.KeyServer; import org.sufficientlysecure.keychain.util.Log; import java.util.ArrayList; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java deleted file mode 100644 index b81fba05d..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann - * Copyright (C) 2011-2014 Thialfihar - * Copyright (C) 2011 Senecaso - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.util; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.Locale; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class HkpKeyServer extends KeyServer { - private static class HttpError extends Exception { - private static final long serialVersionUID = 1718783705229428893L; - private int mCode; - private String mData; - - public HttpError(int code, String data) { - super("" + code + ": " + data); - mCode = code; - mData = data; - } - - public int getCode() { - return mCode; - } - - public String getData() { - return mData; - } - } - - private String mHost; - private short mPort; - - /** - * pub:%keyid%:%algo%:%keylen%:%creationdate%:%expirationdate%:%flags% - *
    - *
  • %keyid% = this is either the fingerprint or the key ID of the key. - * Either the 16-digit or 8-digit key IDs are acceptable, but obviously the fingerprint is best. - *
  • - *
  • %algo% = the algorithm number, (i.e. 1==RSA, 17==DSA, etc). - * See RFC-2440
  • - *
  • %keylen% = the key length (i.e. 1024, 2048, 4096, etc.)
  • - *
  • %creationdate% = creation date of the key in standard - * RFC-2440 form (i.e. number of - * seconds since 1/1/1970 UTC time)
  • - *
  • %expirationdate% = expiration date of the key in standard - * RFC-2440 form (i.e. number of - * seconds since 1/1/1970 UTC time)
  • - *
  • %flags% = letter codes to indicate details of the key, if any. Flags may be in any - * order. The meaning of "disabled" is implementation-specific. Note that individual flags may - * be unimplemented, so the absence of a given flag does not necessarily mean the absence of the - * detail. - *
      - *
    • r == revoked
    • - *
    • d == disabled
    • - *
    • e == expired
    • - *
    - *
  • - *
- * - * @see - * 5.2. Machine Readable Indexes - * in Internet-Draft OpenPGP HTTP Keyserver Protocol Document - */ - public static final Pattern PUB_KEY_LINE = Pattern - .compile("pub:([0-9a-fA-F]+):([0-9]+):([0-9]+):([0-9]+):([0-9]*):([rde]*)[ \n\r]*" // pub line - + "(uid:(.*):([0-9]+):([0-9]*):([rde]*))+", // one or more uid lines - Pattern.CASE_INSENSITIVE); - - /** - * uid:%escaped uid string%:%creationdate%:%expirationdate%:%flags% - *
    - *
  • %escaped uid string% = the user ID string, with HTTP %-escaping for anything that - * isn't 7-bit safe as well as for the ":" character. Any other characters may be escaped, as - * desired.
  • - *
  • %creationdate% = creation date of the key in standard - * RFC-2440 form (i.e. number of - * seconds since 1/1/1970 UTC time)
  • - *
  • %expirationdate% = expiration date of the key in standard - * RFC-2440 form (i.e. number of - * seconds since 1/1/1970 UTC time)
  • - *
  • %flags% = letter codes to indicate details of the key, if any. Flags may be in any - * order. The meaning of "disabled" is implementation-specific. Note that individual flags may - * be unimplemented, so the absence of a given flag does not necessarily mean the absence of - * the detail. - *
      - *
    • r == revoked
    • - *
    • d == disabled
    • - *
    • e == expired
    • - *
    - *
  • - *
- */ - public static final Pattern UID_LINE = Pattern - .compile("uid:(.*):([0-9]+):([0-9]*):([rde]*)", - Pattern.CASE_INSENSITIVE); - - private static final short PORT_DEFAULT = 11371; - - /** - * @param hostAndPort may be just - * "hostname" (eg. "pool.sks-keyservers.net"), then it will - * connect using {@link #PORT_DEFAULT}. However, port may be specified after colon - * ("hostname:port", eg. "p80.pool.sks-keyservers.net:80"). - */ - public HkpKeyServer(String hostAndPort) { - String host = hostAndPort; - short port = PORT_DEFAULT; - final int colonPosition = hostAndPort.lastIndexOf(':'); - if (colonPosition > 0) { - host = hostAndPort.substring(0, colonPosition); - final String portStr = hostAndPort.substring(colonPosition + 1); - port = Short.decode(portStr); - } - mHost = host; - mPort = port; - } - - public HkpKeyServer(String host, short port) { - mHost = host; - mPort = port; - } - - private String query(String request) throws QueryException, HttpError { - InetAddress ips[]; - try { - ips = InetAddress.getAllByName(mHost); - } catch (UnknownHostException e) { - throw new QueryException(e.toString()); - } - for (int i = 0; i < ips.length; ++i) { - try { - String url = "http://" + ips[i].getHostAddress() + ":" + mPort + request; - Log.d(Constants.TAG, "hkp keyserver query: " + url); - URL realUrl = new URL(url); - HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection(); - conn.setConnectTimeout(5000); - conn.setReadTimeout(25000); - conn.connect(); - int response = conn.getResponseCode(); - if (response >= 200 && response < 300) { - return readAll(conn.getInputStream(), conn.getContentEncoding()); - } else { - String data = readAll(conn.getErrorStream(), conn.getContentEncoding()); - throw new HttpError(response, data); - } - } catch (MalformedURLException e) { - // nothing to do, try next IP - } catch (IOException e) { - // nothing to do, try next IP - } - } - - throw new QueryException("querying server(s) for '" + mHost + "' failed"); - } - - @Override - public ArrayList search(String query) throws QueryException, TooManyResponses, - InsufficientQuery { - ArrayList results = new ArrayList(); - - if (query.length() < 3) { - throw new InsufficientQuery(); - } - - String encodedQuery; - try { - encodedQuery = URLEncoder.encode(query, "utf8"); - } catch (UnsupportedEncodingException e) { - return null; - } - String request = "/pks/lookup?op=index&options=mr&search=" + encodedQuery; - - String data; - try { - data = query(request); - } catch (HttpError e) { - if (e.getCode() == 404) { - return results; - } else { - if (e.getData().toLowerCase(Locale.US).contains("no keys found")) { - return results; - } else if (e.getData().toLowerCase(Locale.US).contains("too many")) { - throw new TooManyResponses(); - } else if (e.getData().toLowerCase(Locale.US).contains("insufficient")) { - throw new InsufficientQuery(); - } - } - throw new QueryException("querying server(s) for '" + mHost + "' failed"); - } - - final Matcher matcher = PUB_KEY_LINE.matcher(data); - while (matcher.find()) { - final ImportKeysListEntry entry = new ImportKeysListEntry(); - - entry.setBitStrength(Integer.parseInt(matcher.group(3))); - - final int algorithmId = Integer.decode(matcher.group(2)); - entry.setAlgorithm(PgpKeyHelper.getAlgorithmInfo(algorithmId)); - - // group 1 contains the full fingerprint (v4) or the long key id if available - // see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr - String fingerprintOrKeyId = matcher.group(1); - if (fingerprintOrKeyId.length() > 16) { - entry.setFingerPrintHex(fingerprintOrKeyId.toLowerCase(Locale.US)); - entry.setKeyIdHex("0x" + fingerprintOrKeyId.substring(fingerprintOrKeyId.length() - - 16, fingerprintOrKeyId.length())); - } else { - // set key id only - entry.setKeyIdHex("0x" + fingerprintOrKeyId); - } - - final long creationDate = Long.parseLong(matcher.group(4)); - final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - tmpGreg.setTimeInMillis(creationDate * 1000); - entry.setDate(tmpGreg.getTime()); - - entry.setRevoked(matcher.group(6).contains("r")); - - ArrayList userIds = new ArrayList(); - final String uidLines = matcher.group(7); - final Matcher uidMatcher = UID_LINE.matcher(uidLines); - while (uidMatcher.find()) { - String tmp = uidMatcher.group(1).trim(); - if (tmp.contains("%")) { - try { - // converts Strings like "Universit%C3%A4t" to a proper encoding form "Universität". - tmp = (URLDecoder.decode(tmp, "UTF8")); - } catch (UnsupportedEncodingException ignored) { - // will never happen, because "UTF8" is supported - } - } - userIds.add(tmp); - } - entry.setUserIds(userIds); - entry.setPrimaryUserId(userIds.get(0)); - - results.add(entry); - } - return results; - } - - @Override - public String get(String keyIdHex) throws QueryException { - HttpClient client = new DefaultHttpClient(); - try { - String query = "http://" + mHost + ":" + mPort + - "/pks/lookup?op=get&options=mr&search=" + keyIdHex; - Log.d(Constants.TAG, "hkp keyserver get: " + query); - HttpGet get = new HttpGet(query); - HttpResponse response = client.execute(get); - if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - throw new QueryException("not found"); - } - - HttpEntity entity = response.getEntity(); - InputStream is = entity.getContent(); - String data = readAll(is, EntityUtils.getContentCharSet(entity)); - Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(data); - if (matcher.find()) { - return matcher.group(1); - } - } catch (IOException e) { - // nothing to do, better luck on the next keyserver - } finally { - client.getConnectionManager().shutdown(); - } - - return null; - } - - @Override - public void add(String armoredKey) throws AddKeyException { - HttpClient client = new DefaultHttpClient(); - try { - String query = "http://" + mHost + ":" + mPort + "/pks/add"; - HttpPost post = new HttpPost(query); - Log.d(Constants.TAG, "hkp keyserver add: " + query); - List nameValuePairs = new ArrayList(2); - nameValuePairs.add(new BasicNameValuePair("keytext", armoredKey)); - post.setEntity(new UrlEncodedFormEntity(nameValuePairs)); - - HttpResponse response = client.execute(post); - if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - throw new AddKeyException(); - } - } catch (IOException e) { - // nothing to do, better luck on the next keyserver - } finally { - client.getConnectionManager().shutdown(); - } - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/InputData.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/InputData.java index 5793d7438..f89ffd139 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/InputData.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/InputData.java @@ -19,6 +19,9 @@ package org.sufficientlysecure.keychain.util; import java.io.InputStream; +/** + * Wrapper to include size besides an InputStream + */ public class InputData { private PositionAwareInputStream mInputStream; private long mSize; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/IntentIntegratorSupportV4.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/IntentIntegratorSupportV4.java index ad1aab146..68b402124 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/IntentIntegratorSupportV4.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/IntentIntegratorSupportV4.java @@ -22,6 +22,8 @@ import android.support.v4.app.Fragment; import com.google.zxing.integration.android.IntentIntegrator; /** + * Copied from older Barcode Scanner Integration library + * * IntentIntegrator for the V4 Android compatibility package. * * @author Lachezar Dobrev diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java deleted file mode 100644 index 94c02a773..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann - * Copyright (C) 2011-2014 Thialfihar - * Copyright (C) 2011 Senecaso - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.util; - -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; - -public abstract class KeyServer { - public static class QueryException extends Exception { - private static final long serialVersionUID = 2703768928624654512L; - - public QueryException(String message) { - super(message); - } - } - - public static class TooManyResponses extends Exception { - private static final long serialVersionUID = 2703768928624654513L; - } - - public static class InsufficientQuery extends Exception { - private static final long serialVersionUID = 2703768928624654514L; - } - - public static class AddKeyException extends Exception { - private static final long serialVersionUID = -507574859137295530L; - } - - abstract List search(String query) throws QueryException, TooManyResponses, - InsufficientQuery; - - abstract String get(String keyIdHex) throws QueryException; - - abstract void add(String armoredKey) throws AddKeyException; - - public static String readAll(InputStream in, String encoding) throws IOException { - ByteArrayOutputStream raw = new ByteArrayOutputStream(); - - byte buffer[] = new byte[1 << 16]; - int n = 0; - while ((n = in.read(buffer)) != -1) { - raw.write(buffer, 0, n); - } - - if (encoding == null) { - encoding = "utf8"; - } - return raw.toString(encoding); - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java deleted file mode 100644 index 654fe55f8..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeybaseKeyServer.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2014 Tim Bray - * - * 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 . - */ - -package org.sufficientlysecure.keychain.util; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; - -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.GregorianCalendar; -import java.util.TimeZone; -import java.util.WeakHashMap; - -public class KeybaseKeyServer extends KeyServer { - - private WeakHashMap mKeyCache = new WeakHashMap(); - - @Override - public ArrayList search(String query) throws QueryException, TooManyResponses, - InsufficientQuery { - ArrayList results = new ArrayList(); - - JSONObject fromQuery = getFromKeybase("_/api/1.0/user/autocomplete.json?q=", query); - try { - - JSONArray matches = JWalk.getArray(fromQuery, "completions"); - for (int i = 0; i < matches.length(); i++) { - JSONObject match = matches.getJSONObject(i); - - // only list them if they have a key - if (JWalk.optObject(match, "components", "key_fingerprint") != null) { - results.add(makeEntry(match)); - } - } - } catch (Exception e) { - throw new QueryException("Unexpected structure in keybase search result: " + e.getMessage()); - } - - return results; - } - - private JSONObject getUser(String keybaseID) throws QueryException { - try { - return getFromKeybase("_/api/1.0/user/lookup.json?username=", keybaseID); - } catch (Exception e) { - String detail = ""; - if (keybaseID != null) { - detail = ". Query was for user '" + keybaseID + "'"; - } - throw new QueryException(e.getMessage() + detail); - } - } - - private ImportKeysListEntry makeEntry(JSONObject match) throws QueryException, JSONException { - - String keybaseID = JWalk.getString(match, "components", "username", "val"); - String key_fingerprint = JWalk.getString(match, "components", "key_fingerprint", "val"); - key_fingerprint = key_fingerprint.replace(" ", "").toUpperCase(); - match = getUser(keybaseID); - - final ImportKeysListEntry entry = new ImportKeysListEntry(); - - // TODO: Fix; have suggested keybase provide this value to avoid search-time crypto calls - entry.setBitStrength(4096); - entry.setAlgorithm("RSA"); - entry.setKeyIdHex("0x" + key_fingerprint); - entry.setRevoked(false); - - // ctime - final long creationDate = JWalk.getLong(match, "them", "public_keys", "primary", "ctime"); - final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - tmpGreg.setTimeInMillis(creationDate * 1000); - entry.setDate(tmpGreg.getTime()); - - // key bits - // we have to fetch the user object to construct the search-result list, so we might as - // well (weakly) remember the key, in case they try to import it - mKeyCache.put(keybaseID, JWalk.getString(match,"them", "public_keys", "primary", "bundle")); - - // String displayName = JWalk.getString(match, "them", "profile", "full_name"); - ArrayList userIds = new ArrayList(); - String name = "keybase.io/" + keybaseID + " <" + keybaseID + "@keybase.io>"; - userIds.add(name); - userIds.add(keybaseID); - entry.setUserIds(userIds); - entry.setPrimaryUserId(name); - return entry; - } - - private JSONObject getFromKeybase(String path, String query) throws QueryException { - try { - String url = "https://keybase.io/" + path + URLEncoder.encode(query, "utf8"); - Log.d(Constants.TAG, "keybase query: " + url); - - URL realUrl = new URL(url); - HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection(); - conn.setConnectTimeout(5000); // TODO: Reasonable values for keybase - conn.setReadTimeout(25000); - conn.connect(); - int response = conn.getResponseCode(); - if (response >= 200 && response < 300) { - String text = readAll(conn.getInputStream(), conn.getContentEncoding()); - try { - JSONObject json = new JSONObject(text); - if (JWalk.getInt(json, "status", "code") != 0) { - throw new QueryException("Keybase autocomplete search failed"); - } - return json; - } catch (JSONException e) { - throw new QueryException("Keybase.io query returned broken JSON"); - } - } else { - String message = readAll(conn.getErrorStream(), conn.getContentEncoding()); - throw new QueryException("Keybase.io query error (status=" + response + - "): " + message); - } - } catch (Exception e) { - throw new QueryException("Keybase.io query error"); - } - } - - @Override - public String get(String id) throws QueryException { - String key = mKeyCache.get(id); - if (key == null) { - try { - JSONObject user = getUser(id); - key = JWalk.getString(user, "them", "public_keys", "primary", "bundle"); - } catch (Exception e) { - throw new QueryException(e.getMessage()); - } - } - return key; - } - - @Override - public void add(String armoredKey) throws AddKeyException { - throw new AddKeyException(); - } -} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java deleted file mode 100644 index b205bd556..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.util; - -public interface KeychainServiceListener { - boolean hasServiceStopped(); -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/QrCodeUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/QrCodeUtils.java index cd9e56394..28e567d76 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/QrCodeUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/QrCodeUtils.java @@ -32,6 +32,9 @@ import org.sufficientlysecure.keychain.Constants; import java.util.Hashtable; +/** + * Copied from Bitcoin Wallet + */ public class QrCodeUtils { public static final QRCodeWriter QR_CODE_WRITER = new QRCodeWriter(); -- cgit v1.2.3 From 274326f78065cf9f713504e6dbe213248b02ed5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 6 May 2014 22:48:47 +0200 Subject: Always use section style instead of custom class --- .../keychain/ui/widget/UnderlineTextView.java | 69 ---------------------- 1 file changed, 69 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java deleted file mode 100644 index 937a48e48..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2013 Eric Frohnhoefer - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui.widget; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.widget.TextView; - -/** - * Copied from StickyListHeaders lib example - * - * @author Eric Frohnhoefer - */ -public class UnderlineTextView extends TextView { - private final Paint mPaint = new Paint(); - private int mUnderlineHeight = 0; - - public UnderlineTextView(Context context) { - this(context, null); - } - - public UnderlineTextView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public UnderlineTextView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - init(context, attrs); - } - - private void init(Context context, AttributeSet attrs) { - Resources r = getResources(); - mUnderlineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, - r.getDisplayMetrics()); - } - - @Override - public void setPadding(int left, int top, int right, int bottom) { - super.setPadding(left, top, right, bottom + mUnderlineHeight); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - // Draw the underline the same color as the text - mPaint.setColor(getTextColors().getDefaultColor()); - canvas.drawRect(0, getHeight() - mUnderlineHeight, getWidth(), getHeight(), mPaint); - } -} -- cgit v1.2.3 From 1c2919f07fb9739bbc57ce27bb5b4a6ca2d6be20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 6 May 2014 22:52:50 +0200 Subject: edit button with image --- .../java/org/sufficientlysecure/keychain/ui/KeyListFragment.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') 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 82f65a962..f196e3445 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -50,6 +50,7 @@ import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; import android.widget.Button; import android.widget.FrameLayout; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; @@ -475,7 +476,7 @@ public class KeyListFragment extends Fragment TextView mMainUserIdRest; View mStatusDivider; FrameLayout mStatusLayout; - Button mButton; + ImageButton mButton; TextView mRevoked; ImageView mVerified; } @@ -488,7 +489,7 @@ public class KeyListFragment extends Fragment holder.mMainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); holder.mStatusDivider = (View) view.findViewById(R.id.status_divider); holder.mStatusLayout = (FrameLayout) view.findViewById(R.id.status_layout); - holder.mButton = (Button) view.findViewById(R.id.edit); + holder.mButton = (ImageButton) view.findViewById(R.id.edit); holder.mRevoked = (TextView) view.findViewById(R.id.revoked); holder.mVerified = (ImageView) view.findViewById(R.id.verified); view.setTag(holder); -- cgit v1.2.3 From e97cdbd9ad06b66c67f7778eafce1970590aa654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 6 May 2014 23:16:08 +0200 Subject: Clarify language --- .../java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index 2d31e0de8..1c851de0a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -131,7 +131,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements public void onClick(View v) { if (mPubKeyId != 0) { if (mMasterKeyId == 0) { - mSelectKeyFragment.setError(getString(R.string.select_key_to_sign)); + mSelectKeyFragment.setError(getString(R.string.select_key_to_certify)); } else { initiateSigning(); } -- cgit v1.2.3 From 96125b1976b1cddec946d1ef8e28c4868a63e354 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 7 May 2014 01:39:28 +0200 Subject: ui: purplize edge overscroll glow effect --- .../keychain/KeychainApplication.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index 866888bb2..f911318a0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -18,6 +18,9 @@ package org.sufficientlysecure.keychain; import android.app.Application; +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; import android.os.Environment; import org.spongycastle.jce.provider.BouncyCastleProvider; @@ -70,5 +73,22 @@ public class KeychainApplication extends Application { // that the directory doesn't exist at this point } } + + brandGlowEffect(getApplicationContext(), + getApplicationContext().getResources().getColor(R.color.emphasis)); + } + + static void brandGlowEffect(Context context, int brandColor) { + // terrible hack to brand the edge overscroll glow effect + // https://gist.github.com/menny/7878762#file-brandgloweffect_full-java + + //glow + int glowDrawableId = context.getResources().getIdentifier("overscroll_glow", "drawable", "android"); + Drawable androidGlow = context.getResources().getDrawable(glowDrawableId); + androidGlow.setColorFilter(brandColor, PorterDuff.Mode.SRC_IN); + //edge + int edgeDrawableId = context.getResources().getIdentifier("overscroll_edge", "drawable", "android"); + Drawable androidEdge = context.getResources().getDrawable(edgeDrawableId); + androidEdge.setColorFilter(brandColor, PorterDuff.Mode.SRC_IN); } } -- cgit v1.2.3 From 6aafb314125f016e2215f7d33baf600b5768d72c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 7 May 2014 02:14:47 +0200 Subject: ui: move revocation/expiry notes above tab slider --- .../keychain/ui/ViewKeyActivity.java | 26 +++++++++++++++ .../keychain/ui/ViewKeyMainFragment.java | 38 ++++------------------ 2 files changed, 32 insertions(+), 32 deletions(-) (limited to 'OpenKeychain/src/main/java') 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 56aaba57b..a7ac2587a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -40,6 +40,7 @@ import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; +import android.view.View; import android.view.Window; import com.devspark.appmsg.AppMsg; @@ -55,6 +56,7 @@ import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.SlidingTabLayout; import java.io.IOException; +import java.util.Date; import java.util.HashMap; public class ViewKeyActivity extends ActionBarActivity implements @@ -75,6 +77,8 @@ public class ViewKeyActivity extends ActionBarActivity implements private ViewPager mViewPager; private SlidingTabLayout mSlidingTabLayout; private PagerTabStripAdapter mTabsAdapter; + private View mStatusRevoked; + private View mStatusExpired; public static final int REQUEST_CODE_LOOKUP_KEY = 0x00007006; @@ -104,6 +108,9 @@ public class ViewKeyActivity extends ActionBarActivity implements setContentView(R.layout.view_key_activity); + mStatusRevoked = findViewById(R.id.view_key_revoked); + mStatusExpired = findViewById(R.id.view_key_expired); + mViewPager = (ViewPager) findViewById(R.id.view_key_pager); mSlidingTabLayout = (SlidingTabLayout) findViewById(R.id.view_key_sliding_tab_layout); @@ -363,10 +370,14 @@ public class ViewKeyActivity extends ActionBarActivity implements KeychainContract.KeyRings._ID, KeychainContract.KeyRings.MASTER_KEY_ID, KeychainContract.KeyRings.USER_ID, + KeychainContract.KeyRings.IS_REVOKED, + KeychainContract.KeyRings.EXPIRY, }; static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; static final int INDEX_UNIFIED_USER_ID = 2; + static final int INDEX_UNIFIED_IS_REVOKED = 3; + static final int INDEX_UNIFIED_EXPIRY = 4; @Override public Loader onCreateLoader(int id, Bundle args) { @@ -408,6 +419,21 @@ public class ViewKeyActivity extends ActionBarActivity implements String keyIdStr = PgpKeyHelper.convertKeyIdToHex(masterKeyId); getSupportActionBar().setSubtitle(keyIdStr); + // If this key is revoked, it cannot be used for anything! + if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) { + mStatusRevoked.setVisibility(View.VISIBLE); + mStatusExpired.setVisibility(View.GONE); + } else { + mStatusRevoked.setVisibility(View.GONE); + + Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); + if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) { + mStatusExpired.setVisibility(View.VISIBLE); + } else { + mStatusExpired.setVisibility(View.GONE); + } + } + break; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index ded457eca..389455a9a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -49,8 +49,6 @@ public class ViewKeyMainFragment extends Fragment implements public static final String ARG_DATA_URI = "uri"; private LinearLayout mContainer; - private View mStatusRevoked; - private View mStatusExpired; private View mActionEdit; private View mActionEditDivider; private View mActionEncrypt; @@ -72,8 +70,6 @@ public class ViewKeyMainFragment extends Fragment implements mContainer = (LinearLayout) view.findViewById(R.id.container); mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); - mStatusRevoked = view.findViewById(R.id.view_key_revoked); - mStatusExpired = view.findViewById(R.id.view_key_expired); mActionEdit = view.findViewById(R.id.view_key_action_edit); mActionEditDivider = view.findViewById(R.id.view_key_action_edit_divider); mActionEncrypt = view.findViewById(R.id.view_key_action_encrypt); @@ -132,30 +128,14 @@ public class ViewKeyMainFragment extends Fragment implements } static final String[] UNIFIED_PROJECTION = new String[]{ - KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, KeyRings.IS_REVOKED, - KeyRings.USER_ID, KeyRings.FINGERPRINT, - KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY, - KeyRings.HAS_ENCRYPT - + KeyRings._ID, KeyRings.MASTER_KEY_ID, + KeyRings.HAS_ANY_SECRET, KeyRings.IS_REVOKED, KeyRings.EXPIRY, KeyRings.HAS_ENCRYPT }; static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; static final int INDEX_UNIFIED_IS_REVOKED = 3; - static final int INDEX_UNIFIED_USER_ID = 4; - static final int INDEX_UNIFIED_FINGERPRINT = 5; - static final int INDEX_UNIFIED_ALGORITHM = 6; - static final int INDEX_UNIFIED_KEY_SIZE = 7; - static final int INDEX_UNIFIED_CREATION = 8; - static final int INDEX_UNIFIED_EXPIRY = 9; - static final int INDEX_UNIFIED_HAS_ENCRYPT = 10; - - static final String[] KEYS_PROJECTION = new String[]{ - Keys._ID, - Keys.KEY_ID, Keys.RANK, Keys.ALGORITHM, Keys.KEY_SIZE, Keys.HAS_SECRET, - Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT, Keys.CAN_SIGN, Keys.IS_REVOKED, - Keys.CREATION, Keys.EXPIRY, Keys.FINGERPRINT - }; - static final int KEYS_INDEX_CAN_ENCRYPT = 7; + static final int INDEX_UNIFIED_EXPIRY = 4; + static final int INDEX_UNIFIED_HAS_ENCRYPT = 5; public Loader onCreateLoader(int id, Bundle args) { switch (id) { @@ -165,7 +145,8 @@ public class ViewKeyMainFragment extends Fragment implements } case LOADER_ID_USER_IDS: { Uri baseUri = UserIds.buildUserIdsUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, ViewKeyUserIdsAdapter.USER_IDS_PROJECTION, null, null, null); + return new CursorLoader(getActivity(), baseUri, + ViewKeyUserIdsAdapter.USER_IDS_PROJECTION, null, null, null); } default: @@ -206,9 +187,6 @@ public class ViewKeyMainFragment extends Fragment implements // If this key is revoked, it cannot be used for anything! if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) { - mStatusRevoked.setVisibility(View.VISIBLE); - mStatusExpired.setVisibility(View.GONE); - mActionEdit.setEnabled(false); mActionCertify.setEnabled(false); mActionEncrypt.setEnabled(false); @@ -217,13 +195,9 @@ public class ViewKeyMainFragment extends Fragment implements Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) { - mStatusRevoked.setVisibility(View.GONE); - mStatusExpired.setVisibility(View.VISIBLE); mActionCertify.setEnabled(false); mActionEncrypt.setEnabled(false); } else { - mStatusRevoked.setVisibility(View.GONE); - mStatusExpired.setVisibility(View.GONE); mActionCertify.setEnabled(true); mActionEncrypt.setEnabled(true); } -- cgit v1.2.3 From 0bb11be749cd2af71fc905d930ac1d9e3b9b22be Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 7 May 2014 02:15:09 +0200 Subject: ui: slight edit icon cosmetics in keylist --- .../main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'OpenKeychain/src/main/java') 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 a7ac2587a..957a2db07 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -77,6 +77,7 @@ public class ViewKeyActivity extends ActionBarActivity implements private ViewPager mViewPager; private SlidingTabLayout mSlidingTabLayout; private PagerTabStripAdapter mTabsAdapter; + private View mStatusDivider; private View mStatusRevoked; private View mStatusExpired; @@ -421,6 +422,7 @@ public class ViewKeyActivity extends ActionBarActivity implements // If this key is revoked, it cannot be used for anything! if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) { + mStatusDivider.setVisibility(View.VISIBLE); mStatusRevoked.setVisibility(View.VISIBLE); mStatusExpired.setVisibility(View.GONE); } else { @@ -428,8 +430,10 @@ public class ViewKeyActivity extends ActionBarActivity implements Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) { + mStatusDivider.setVisibility(View.VISIBLE); mStatusExpired.setVisibility(View.VISIBLE); } else { + mStatusDivider.setVisibility(View.GONE); mStatusExpired.setVisibility(View.GONE); } } -- cgit v1.2.3 From 873b1be75dc7296ce60b6f11cd63e6707080db49 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 7 May 2014 02:27:51 +0200 Subject: display AppMsg warning when no encryption subkey is available --- .../sufficientlysecure/keychain/ui/ViewKeyMainFragment.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index 389455a9a..b30c9aaec 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -32,6 +32,8 @@ import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.ListView; +import com.devspark.appmsg.AppMsg; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R;import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; @@ -60,6 +62,9 @@ public class ViewKeyMainFragment extends Fragment implements private static final int LOADER_ID_UNIFIED = 0; private static final int LOADER_ID_USER_IDS = 1; + // conservative attitude + private boolean mHasEncrypt = true; + private ViewKeyUserIdsAdapter mUserIdsAdapter; private Uri mDataUri; @@ -203,6 +208,8 @@ public class ViewKeyMainFragment extends Fragment implements } } + mHasEncrypt = data.getInt(INDEX_UNIFIED_HAS_ENCRYPT) != 0; + break; } } @@ -229,6 +236,11 @@ public class ViewKeyMainFragment extends Fragment implements } private void encrypt(Uri dataUri) { + // If there is no encryption key, don't bother. + if (!mHasEncrypt) { + AppMsg.makeText(getActivity(), R.string.error_no_encrypt_subkey, AppMsg.STYLE_ALERT).show(); + return; + } try { long keyId = new ProviderHelper(getActivity()).extractOrGetMasterKeyId(dataUri); long[] encryptionKeyIds = new long[]{keyId}; -- cgit v1.2.3 From 65274f6c1678c55d321e513c3db45974c68470e4 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 7 May 2014 03:07:24 +0200 Subject: ui: purplize searchtext in keylist --- .../main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'OpenKeychain/src/main/java') 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 f196e3445..5464a9b96 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -381,6 +381,9 @@ public class KeyListFragment extends Fragment // Execute this when searching mSearchView.setOnQueryTextListener(this); + View searchPlate = mSearchView.findViewById(android.support.v7.appcompat.R.id.search_plate); + searchPlate.setBackgroundResource(R.drawable.keychaintheme_searchview_holo_light); + // Erase search result without focus MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() { @Override -- cgit v1.2.3 From 992d37819cbac9f7ba001bd91f0b5b700fd51f61 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 7 May 2014 03:18:41 +0200 Subject: small fix for 6aafb3, forgot to commit this line --- .../main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java | 1 + 1 file changed, 1 insertion(+) (limited to 'OpenKeychain/src/main/java') 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 957a2db07..ef01dfc38 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -109,6 +109,7 @@ public class ViewKeyActivity extends ActionBarActivity implements setContentView(R.layout.view_key_activity); + mStatusDivider = findViewById(R.id.status_divider); mStatusRevoked = findViewById(R.id.view_key_revoked); mStatusExpired = findViewById(R.id.view_key_expired); -- cgit v1.2.3 From 12f1162a1ee6ac407080db3b9de2c8bf7fd83314 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 7 May 2014 03:48:03 +0200 Subject: ui: use SlidingTabLayout in help activity --- .../keychain/ui/HelpActivity.java | 50 +++++++++++++--------- 1 file changed, 30 insertions(+), 20 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java index e81bc1563..cf7446a58 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java @@ -24,7 +24,9 @@ import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter; +import org.sufficientlysecure.keychain.util.SlidingTabLayout; public class HelpActivity extends ActionBarActivity { public static final String EXTRA_SELECTED_TAB = "selected_tab"; @@ -37,25 +39,27 @@ public class HelpActivity extends ActionBarActivity { public static final int TAB_ABOUT = 5; ViewPager mViewPager; - TabsAdapter mTabsAdapter; + private PagerTabStripAdapter mTabsAdapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.help_activity); - - mViewPager = (ViewPager) findViewById(R.id.pager); - final ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayShowTitleEnabled(true); actionBar.setDisplayHomeAsUpEnabled(false); actionBar.setHomeButtonEnabled(false); - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); - mTabsAdapter = new TabsAdapter(this, mViewPager); + setContentView(R.layout.help_activity); + + mViewPager = (ViewPager) findViewById(R.id.pager); + SlidingTabLayout slidingTabLayout = + (SlidingTabLayout) findViewById(R.id.sliding_tab_layout); + + mTabsAdapter = new PagerTabStripAdapter(this); + mViewPager.setAdapter(mTabsAdapter); - int selectedTab = 0; + int selectedTab = TAB_START; Intent intent = getIntent(); if (intent.getExtras() != null && intent.getExtras().containsKey(EXTRA_SELECTED_TAB)) { selectedTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB); @@ -63,30 +67,36 @@ public class HelpActivity extends ActionBarActivity { Bundle startBundle = new Bundle(); startBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_start); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_start)), - HelpHtmlFragment.class, startBundle, (selectedTab == TAB_START)); + mTabsAdapter.addTab(HelpHtmlFragment.class, startBundle, + getString(R.string.help_tab_start)); Bundle faqBundle = new Bundle(); faqBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_faq); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_faq)), - HelpHtmlFragment.class, faqBundle, (selectedTab == TAB_FAQ)); + mTabsAdapter.addTab(HelpHtmlFragment.class, faqBundle, + getString(R.string.help_tab_faq)); Bundle wotBundle = new Bundle(); wotBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_wot); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_wot)), - HelpHtmlFragment.class, wotBundle, (selectedTab == TAB_WOT)); + mTabsAdapter.addTab(HelpHtmlFragment.class, wotBundle, + getString(R.string.help_tab_wot)); Bundle nfcBundle = new Bundle(); nfcBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_nfc_beam); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_nfc_beam)), - HelpHtmlFragment.class, nfcBundle, (selectedTab == TAB_NFC)); + mTabsAdapter.addTab(HelpHtmlFragment.class, nfcBundle, + getString(R.string.help_tab_nfc_beam)); Bundle changelogBundle = new Bundle(); changelogBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_changelog); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_changelog)), - HelpHtmlFragment.class, changelogBundle, (selectedTab == TAB_CHANGELOG)); + mTabsAdapter.addTab(HelpHtmlFragment.class, changelogBundle, + getString(R.string.help_tab_changelog)); + + mTabsAdapter.addTab(HelpAboutFragment.class, null, + getString(R.string.help_tab_about)); + + // NOTE: must be after adding the tabs! + slidingTabLayout.setViewPager(mViewPager); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_about)), - HelpAboutFragment.class, null, (selectedTab == TAB_ABOUT)); + // switch to tab selected by extra + mViewPager.setCurrentItem(selectedTab); } } -- cgit v1.2.3 From dc382a2ddd40a2797ad3458a50afb5e88ec27b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 7 May 2014 09:05:28 +0200 Subject: Clarify language --- .../main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java | 2 +- .../java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') 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 56aaba57b..7c920294c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -140,7 +140,7 @@ public class ViewKeyActivity extends ActionBarActivity implements Bundle keyDetailsBundle = new Bundle(); keyDetailsBundle.putParcelable(ViewKeyKeysFragment.ARG_DATA_URI, dataUri); mTabsAdapter.addTab(ViewKeyKeysFragment.class, - keyDetailsBundle, getString(R.string.key_view_tab_keys_details)); + keyDetailsBundle, getString(R.string.key_view_tab_keys)); Bundle certBundle = new Bundle(); certBundle.putParcelable(ViewKeyCertsFragment.ARG_DATA_URI, dataUri); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java index aacf30429..fce402136 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java @@ -187,7 +187,7 @@ public class ViewKeyShareFragment extends Fragment implements if (fingerprintOnly) { title = getResources().getString(R.string.title_share_fingerprint_with); } else { - title = getResources().getString(R.string.title_share_key_with); + title = getResources().getString(R.string.title_share_key); } startActivity(Intent.createChooser(sendIntent, title)); } -- cgit v1.2.3 From f4cbd8cabbe9dcd01e430a4f9953f061092cdfe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 7 May 2014 14:17:18 +0200 Subject: Design fixes for certification activity --- .../keychain/ui/ViewCertActivity.java | 87 +++++++++++----------- 1 file changed, 43 insertions(+), 44 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java index 645766287..f78c30820 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -28,7 +28,6 @@ import android.support.v4.content.Loader; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.text.format.DateFormat; -import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.TextView; @@ -76,11 +75,12 @@ public class ViewCertActivity extends ActionBarActivity private Uri mDataUri; - private long mSignerKeyId; + private long mCertifierKeyId; - private TextView mSigneeKey, mSigneeUid, mAlgorithm, mType, mRReason, mCreation; - private TextView mSignerKey, mSignerUid, mStatus; + private TextView mSigneeKey, mSigneeUid, mAlgorithm, mType, mReason, mCreation; + private TextView mCertifierKey, mCertifierUid, mStatus; private View mRowReason; + private View mViewCertifierButton; @Override protected void onCreate(Bundle savedInstanceState) { @@ -96,14 +96,16 @@ public class ViewCertActivity extends ActionBarActivity mSigneeUid = (TextView) findViewById(R.id.signee_uid); mAlgorithm = (TextView) findViewById(R.id.algorithm); mType = (TextView) findViewById(R.id.signature_type); - mRReason = (TextView) findViewById(R.id.reason); + mReason = (TextView) findViewById(R.id.reason); mCreation = (TextView) findViewById(R.id.creation); - mSignerKey = (TextView) findViewById(R.id.signer_key_id); - mSignerUid = (TextView) findViewById(R.id.signer_uid); + mCertifierKey = (TextView) findViewById(R.id.signer_key_id); + mCertifierUid = (TextView) findViewById(R.id.signer_uid); mRowReason = findViewById(R.id.row_reason); + mViewCertifierButton = findViewById(R.id.view_cert_view_cert_key); + mDataUri = getIntent().getData(); if (mDataUri == null) { Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!"); @@ -133,15 +135,15 @@ public class ViewCertActivity extends ActionBarActivity Date creationDate = new Date(data.getLong(INDEX_CREATION) * 1000); mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format(creationDate)); - mSignerKeyId = data.getLong(INDEX_KEY_ID_CERTIFIER); - String signerKey = PgpKeyHelper.convertKeyIdToHex(mSignerKeyId); - mSignerKey.setText(signerKey); + mCertifierKeyId = data.getLong(INDEX_KEY_ID_CERTIFIER); + String certifierKey = PgpKeyHelper.convertKeyIdToHex(mCertifierKeyId); + mCertifierKey.setText(certifierKey); - String signerUid = data.getString(INDEX_SIGNER_UID); - if (signerUid != null) { - mSignerUid.setText(signerUid); + String certifierUid = data.getString(INDEX_SIGNER_UID); + if (certifierUid != null) { + mCertifierUid.setText(certifierUid); } else { - mSignerUid.setText(R.string.unknown_uid); + mCertifierUid.setText(R.string.unknown_uid); } PGPSignature sig = PgpConversionHelper.BytesToPGPSignature(data.getBlob(INDEX_DATA)); @@ -149,10 +151,12 @@ public class ViewCertActivity extends ActionBarActivity ProviderHelper providerHelper = new ProviderHelper(this); PGPKeyRing signeeRing = providerHelper.getPGPKeyRing( KeychainContract.KeyRingData.buildPublicKeyRingUri( - Long.toString(data.getLong(INDEX_MASTER_KEY_ID)))); + Long.toString(data.getLong(INDEX_MASTER_KEY_ID))) + ); PGPKeyRing signerRing = providerHelper.getPGPKeyRing( KeychainContract.KeyRingData.buildPublicKeyRingUri( - Long.toString(sig.getKeyID()))); + Long.toString(sig.getKeyID())) + ); try { sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider( @@ -203,25 +207,39 @@ public class ViewCertActivity extends ActionBarActivity p = new RevocationReason(false, p.getData()); } String reason = ((RevocationReason) p).getRevocationDescription(); - mRReason.setText(reason); + mReason.setText(reason); mRowReason.setVisibility(View.VISIBLE); } break; } } } - } - @Override - public void onLoaderReset(Loader loader) { - } + // can't do this before the data is initialized + mViewCertifierButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent viewIntent = new Intent(ViewCertActivity.this, ViewKeyActivity.class); + try { + ProviderHelper providerHelper = new ProviderHelper(ViewCertActivity.this); + long signerMasterKeyId = providerHelper.getMasterKeyId( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(mCertifierKeyId)) + ); + viewIntent.setData(KeyRings.buildGenericKeyRingUri( + Long.toString(signerMasterKeyId)) + ); + startActivity(viewIntent); + } catch (ProviderHelper.NotFoundException e) { + // TODO notify user of this, maybe offer download? + Log.e(Constants.TAG, "key not found!", e); + } + } + }); + } @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.view_cert, menu); - return true; + public void onLoaderReset(Loader loader) { } @Override @@ -233,25 +251,6 @@ public class ViewCertActivity extends ActionBarActivity NavUtils.navigateUpTo(this, viewIntent); return true; } - case R.id.menu_view_cert_view_signer: - // can't do this before the data is initialized - Intent viewIntent = new Intent(this, ViewKeyActivity.class); - - try { - ProviderHelper providerHelper = new ProviderHelper(this); - long signerMasterKeyId = providerHelper.getMasterKeyId( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(mSignerKeyId)) - ); - viewIntent.setData(KeyRings.buildGenericKeyRingUri( - Long.toString(signerMasterKeyId)) - ); - startActivity(viewIntent); - } catch (ProviderHelper.NotFoundException e) { - // TODO notify user of this, maybe offer download? - Log.e(Constants.TAG, "key not found!", e); - } - - return true; } return super.onOptionsItemSelected(item); } -- cgit v1.2.3 From e14ce09186cde662ec24312a1722692cac25d5c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 7 May 2014 14:33:20 +0200 Subject: Better handling of actionbars back --- .../keychain/helper/ActionBarHelper.java | 19 -------------- .../keychain/ui/CertifyKeyActivity.java | 26 ++++++++++++++----- .../keychain/ui/DecryptActivity.java | 4 --- .../keychain/ui/EncryptActivity.java | 30 ++++++++++++---------- .../keychain/ui/ImportKeysActivity.java | 2 -- .../keychain/ui/UploadKeyActivity.java | 15 +++++++++++ 6 files changed, 50 insertions(+), 46 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java index 72b6d9e1d..46e7936ce 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java @@ -32,25 +32,6 @@ import org.sufficientlysecure.keychain.util.Log; public class ActionBarHelper { - /** - * Set actionbar without home button if called from another app - * - * @param activity - */ - public static void setBackButton(ActionBarActivity activity) { - final ActionBar actionBar = activity.getSupportActionBar(); - Log.d(Constants.TAG, "calling package (only set when using startActivityForResult)=" - + activity.getCallingPackage()); - if (activity.getCallingPackage() != null - && activity.getCallingPackage().equals(Constants.PACKAGE_NAME)) { - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setHomeButtonEnabled(true); - } else { - actionBar.setDisplayHomeAsUpEnabled(false); - actionBar.setHomeButtonEnabled(false); - } - } - /** * Sets custom view on ActionBar for Done/Cancel activities * diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index 1c851de0a..29969ca55 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -26,10 +26,12 @@ import android.os.Handler; import android.os.Message; import android.os.Messenger; import android.support.v4.app.LoaderManager; +import android.support.v4.app.NavUtils; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; +import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; @@ -88,11 +90,6 @@ public class CertifyKeyActivity extends ActionBarActivity implements setContentView(R.layout.certify_key_activity); - final ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(false); - actionBar.setHomeButtonEnabled(false); - mSelectKeyFragment = (SelectSecretKeyLayoutFragment) getSupportFragmentManager() .findFragmentById(R.id.sign_key_select_key_fragment); mSelectKeyFragment.setCallback(this); @@ -101,7 +98,8 @@ public class CertifyKeyActivity extends ActionBarActivity implements mSelectKeyserverSpinner = (Spinner) findViewById(R.id.sign_key_keyserver); ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, Preferences.getPreferences(this) - .getKeyServers()); + .getKeyServers() + ); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mSelectKeyserverSpinner.setAdapter(adapter); @@ -258,7 +256,8 @@ public class CertifyKeyActivity extends ActionBarActivity implements startSigning(); } } - }); + } + ); // bail out; need to wait until the user has entered the passphrase before trying again return; } else { @@ -392,4 +391,17 @@ public class CertifyKeyActivity extends ActionBarActivity implements public void onKeySelected(long secretKeyId) { mMasterKeyId = secretKeyId; } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: { + Intent viewIntent = NavUtils.getParentActivityIntent(this); + viewIntent.setData(KeyRings.buildGenericKeyRingUri(mDataUri)); + NavUtils.navigateUpTo(this, viewIntent); + return true; + } + } + return super.onOptionsItemSelected(item); + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index 1877a43b5..5b21be6e4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -27,7 +27,6 @@ import android.widget.Toast; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; import org.sufficientlysecure.keychain.helper.FileHelper; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; @@ -68,9 +67,6 @@ public class DecryptActivity extends DrawerActivity { setContentView(R.layout.decrypt_activity); - // set actionbar without home button if called from another app - ActionBarHelper.setBackButton(this); - initView(); setupDrawerNavigation(savedInstanceState); 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 6c71c641f..39d4a09bc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -27,7 +27,6 @@ import android.widget.Toast; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; import org.sufficientlysecure.keychain.helper.FileHelper; import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; import org.sufficientlysecure.keychain.util.Log; @@ -145,26 +144,28 @@ public class EncryptActivity extends DrawerActivity implements setContentView(R.layout.encrypt_activity); - // set actionbar without home button if called from another app - ActionBarHelper.setBackButton(this); - initView(); - setupDrawerNavigation(savedInstanceState); + // if called with an intent action, do not init drawer navigation + if (ACTION_ENCRYPT.equals(getIntent().getAction())) { + // TODO: back button to key? + } else { + setupDrawerNavigation(savedInstanceState); + } // Handle intent actions handleActions(getIntent()); mTabsAdapterMode.addTab(EncryptAsymmetricFragment.class, - mAsymmetricFragmentBundle, getString(R.string.label_asymmetric)); + mAsymmetricFragmentBundle, getString(R.string.label_asymmetric)); mTabsAdapterMode.addTab(EncryptSymmetricFragment.class, - mSymmetricFragmentBundle, getString(R.string.label_symmetric)); + mSymmetricFragmentBundle, getString(R.string.label_symmetric)); mViewPagerMode.setCurrentItem(mSwitchToMode); mTabsAdapterContent.addTab(EncryptMessageFragment.class, - mMessageFragmentBundle, getString(R.string.label_message)); + mMessageFragmentBundle, getString(R.string.label_message)); mTabsAdapterContent.addTab(EncryptFileFragment.class, - mFileFragmentBundle, getString(R.string.label_file)); + mFileFragmentBundle, getString(R.string.label_file)); mViewPagerContent.setCurrentItem(mSwitchToContent); } @@ -217,9 +218,9 @@ public class EncryptActivity extends DrawerActivity implements // preselect keys given by intent mAsymmetricFragmentBundle.putLongArray(EncryptAsymmetricFragment.ARG_ENCRYPTION_KEY_IDS, - encryptionKeyIds); + encryptionKeyIds); mAsymmetricFragmentBundle.putLong(EncryptAsymmetricFragment.ARG_SIGNATURE_KEY_ID, - signatureKeyId); + signatureKeyId); mSwitchToMode = PAGER_MODE_ASYMMETRIC; /** @@ -241,9 +242,10 @@ public class EncryptActivity extends DrawerActivity implements } else { Log.e(Constants.TAG, "Direct binary data without actual file in filesystem is not supported " + - "by Intents. Please use the Remote Service API!"); - Toast.makeText(this, R.string.error_only_files_are_supported, Toast.LENGTH_LONG) - .show(); + "by Intents. Please use the Remote Service API!" + ); + Toast.makeText(this, R.string.error_only_files_are_supported, + Toast.LENGTH_LONG).show(); // end activity finish(); } 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 66224dd0b..f71ef6d46 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -43,7 +43,6 @@ import com.devspark.appmsg.AppMsg; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; @@ -125,7 +124,6 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN.equals(getIntent().getAction())) { setTitle(R.string.nav_import); } else { - ActionBarHelper.setBackButton(this); getSupportActionBar().setDisplayShowTitleEnabled(false); // set drop down navigation 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 97a2af645..90783aa8b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -23,7 +23,9 @@ import android.net.Uri; import android.os.Bundle; import android.os.Message; import android.os.Messenger; +import android.support.v4.app.NavUtils; import android.support.v7.app.ActionBarActivity; +import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; @@ -129,4 +131,17 @@ public class UploadKeyActivity extends ActionBarActivity { // start service with intent startService(intent); } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: { + Intent viewIntent = NavUtils.getParentActivityIntent(this); + viewIntent.setData(KeychainContract.KeyRings.buildGenericKeyRingUri(mDataUri)); + NavUtils.navigateUpTo(this, viewIntent); + return true; + } + } + return super.onOptionsItemSelected(item); + } } -- cgit v1.2.3 From 2a33eae9ebad8b24326ad30b262e6062f47be80f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 7 May 2014 14:53:35 +0200 Subject: GET_KEY: also return PendingIntent to key view --- .../sufficientlysecure/keychain/remote/OpenPgpService.java | 11 ++++++++++- .../org/sufficientlysecure/keychain/ui/ViewKeyActivity.java | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index 1e0cfaa8e..5691d2fe2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -42,6 +42,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.ui.ImportKeysActivity; +import org.sufficientlysecure.keychain.ui.ViewKeyActivity; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; @@ -417,7 +418,15 @@ public class OpenPgpService extends RemoteService { Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - // TODO: also return PendingIntent that opens the key view activity + // also return PendingIntent that opens the key view activity + Intent intent = new Intent(getBaseContext(), ViewKeyActivity.class); + intent.setData(KeyRings.buildGenericKeyRingUri(Long.toString(masterKeyId))); + + PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, + intent, + PendingIntent.FLAG_CANCEL_CURRENT); + + result.putExtra(OpenPgpApi.RESULT_INTENT, pi); return result; } catch (ProviderHelper.NotFoundException e) { 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 1955c122d..8c52e6f22 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -67,7 +67,7 @@ public class ViewKeyActivity extends ActionBarActivity implements protected Uri mDataUri; - public static final String EXTRA_SELECTED_TAB = "selectedTab"; + public static final String EXTRA_SELECTED_TAB = "selected_tab"; public static final int TAB_MAIN = 0; public static final int TAB_SHARE = 1; public static final int TAB_KEYS = 2; -- cgit v1.2.3 From b771276611b98e167242dd790416811ff2966a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 7 May 2014 15:03:24 +0200 Subject: Start app menu item for registered apps --- .../keychain/remote/ui/AppSettingsActivity.java | 28 ++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index c6637c058..8df341f9e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -40,6 +40,9 @@ public class AppSettingsActivity extends ActionBarActivity { private AppSettingsFragment mSettingsFragment; private AccountsListFragment mAccountsListFragment; + // model + AppSettings mAppSettings; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -80,22 +83,39 @@ public class AppSettingsActivity extends ActionBarActivity { case R.id.menu_api_settings_revoke: revokeAccess(); return true; + case R.id.menu_api_settings_start: + startApp(); + return true; } return super.onOptionsItemSelected(item); } + private void startApp() { + Intent i; + PackageManager manager = getPackageManager(); + try { + i = manager.getLaunchIntentForPackage(mAppSettings.getPackageName()); + if (i == null) + throw new PackageManager.NameNotFoundException(); + i.addCategory(Intent.CATEGORY_LAUNCHER); + startActivity(i); + } catch (PackageManager.NameNotFoundException e) { + Log.e(Constants.TAG, "startApp", e); + } + } + private void loadData(Bundle savedInstanceState, Uri appUri) { - AppSettings settings = new ProviderHelper(this).getApiAppSettings(appUri); - mSettingsFragment.setAppSettings(settings); + mAppSettings = new ProviderHelper(this).getApiAppSettings(appUri); + mSettingsFragment.setAppSettings(mAppSettings); String appName; PackageManager pm = getPackageManager(); try { - ApplicationInfo ai = pm.getApplicationInfo(settings.getPackageName(), 0); + ApplicationInfo ai = pm.getApplicationInfo(mAppSettings.getPackageName(), 0); appName = (String) pm.getApplicationLabel(ai); } catch (PackageManager.NameNotFoundException e) { // fallback - appName = settings.getPackageName(); + appName = mAppSettings.getPackageName(); } setTitle(appName); -- cgit v1.2.3 From 377edfb31090eaa948852d264614817749febd23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 7 May 2014 15:40:19 +0200 Subject: Remove code for sharing whole key via qr code --- .../keychain/ui/ViewKeyShareFragment.java | 3 +- .../ui/dialog/ShareQrCodeDialogFragment.java | 142 +++------------------ 2 files changed, 16 insertions(+), 129 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java index fce402136..1a76f5eed 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java @@ -201,8 +201,7 @@ public class ViewKeyShareFragment extends Fragment implements } private void showQrCodeDialog() { - ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(mDataUri, - true); + ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(mDataUri); dialog.show(ViewKeyShareFragment.this.getActivity().getSupportFragmentManager(), "shareQrCodeDialog"); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java index fe50c759b..1b998ec8d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java @@ -25,7 +25,6 @@ import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.view.LayoutInflater; import android.view.View; -import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; @@ -34,37 +33,26 @@ import com.devspark.appmsg.AppMsg; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.QrCodeUtils; -import java.io.IOException; -import java.util.ArrayList; - public class ShareQrCodeDialogFragment extends DialogFragment { private static final String ARG_KEY_URI = "uri"; - private static final String ARG_FINGERPRINT_ONLY = "fingerprint_only"; private ImageView mImage; private TextView mText; - private boolean mFingerprintOnly; - - private ArrayList mContentList; - private int mCounter; - private static final int QR_CODE_SIZE = 1000; /** * Creates new instance of this dialog fragment */ - public static ShareQrCodeDialogFragment newInstance(Uri dataUri, boolean fingerprintOnly) { + public static ShareQrCodeDialogFragment newInstance(Uri dataUri) { ShareQrCodeDialogFragment frag = new ShareQrCodeDialogFragment(); Bundle args = new Bundle(); args.putParcelable(ARG_KEY_URI, dataUri); - args.putBoolean(ARG_FINGERPRINT_ONLY, fingerprintOnly); frag.setArguments(args); @@ -79,7 +67,6 @@ public class ShareQrCodeDialogFragment extends DialogFragment { final Activity activity = getActivity(); Uri dataUri = getArguments().getParcelable(ARG_KEY_URI); - mFingerprintOnly = getArguments().getBoolean(ARG_FINGERPRINT_ONLY); AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); alert.setTitle(R.string.share_qr_code_dialog_title); @@ -94,45 +81,21 @@ public class ShareQrCodeDialogFragment extends DialogFragment { ProviderHelper providerHelper = new ProviderHelper(getActivity()); String content; try { - if (mFingerprintOnly) { - alert.setPositiveButton(R.string.btn_okay, null); - - byte[] blob = (byte[]) providerHelper.getGenericData( - KeyRings.buildUnifiedKeyRingUri(dataUri), - KeyRings.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); - if (blob == null) { - Log.e(Constants.TAG, "key not found!"); - AppMsg.makeText(getActivity(), R.string.error_key_not_found, AppMsg.STYLE_ALERT).show(); - return null; - } - - String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob); - mText.setText(getString(R.string.share_qr_code_dialog_fingerprint_text) + " " + fingerprint); - content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; - setQrCode(content); - } else { - mText.setText(R.string.share_qr_code_dialog_start); - - try { - Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); - content = providerHelper.getKeyRingAsArmoredString(uri); - } catch (IOException e) { - Log.e(Constants.TAG, "error processing key!", e); - AppMsg.makeText(getActivity(), R.string.error_invalid_data, AppMsg.STYLE_ALERT).show(); - return null; - } - - // OnClickListener are set in onResume to prevent automatic dismissing of Dialogs - // http://bit.ly/O5vfaR - alert.setPositiveButton(R.string.btn_next, null); - alert.setNegativeButton(android.R.string.cancel, null); - - mContentList = splitString(content, 1000); - - // start with first - mCounter = 0; - updatePartsQrCode(); + alert.setPositiveButton(R.string.btn_okay, null); + + byte[] blob = (byte[]) providerHelper.getGenericData( + KeyRings.buildUnifiedKeyRingUri(dataUri), + KeyRings.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); + if (blob == null) { + Log.e(Constants.TAG, "key not found!"); + AppMsg.makeText(getActivity(), R.string.error_key_not_found, AppMsg.STYLE_ALERT).show(); + return null; } + + String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob); + mText.setText(getString(R.string.share_qr_code_dialog_fingerprint_text) + " " + fingerprint); + content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; + setQrCode(content); } catch (ProviderHelper.NotFoundException e) { Log.e(Constants.TAG, "key not found!", e); AppMsg.makeText(getActivity(), R.string.error_key_not_found, AppMsg.STYLE_ALERT).show(); @@ -142,83 +105,8 @@ public class ShareQrCodeDialogFragment extends DialogFragment { return alert.create(); } - @Override - public void onResume() { - super.onResume(); - - if (!mFingerprintOnly) { - AlertDialog alertDialog = (AlertDialog) getDialog(); - final Button backButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE); - final Button nextButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); - - backButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mCounter > 0) { - mCounter--; - updatePartsQrCode(); - updateDialog(backButton, nextButton); - } else { - dismiss(); - } - } - }); - nextButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - - if (mCounter < mContentList.size() - 1) { - mCounter++; - updatePartsQrCode(); - updateDialog(backButton, nextButton); - } else { - dismiss(); - } - } - }); - } - } - - private void updatePartsQrCode() { - // Content: ,, - setQrCode(mCounter + "," + mContentList.size() + "," + mContentList.get(mCounter)); - } - private void setQrCode(String data) { mImage.setImageBitmap(QrCodeUtils.getQRCodeBitmap(data, QR_CODE_SIZE)); } - private void updateDialog(Button backButton, Button nextButton) { - if (mCounter == 0) { - backButton.setText(android.R.string.cancel); - } else { - backButton.setText(R.string.btn_back); - } - if (mCounter == mContentList.size() - 1) { - nextButton.setText(android.R.string.ok); - } else { - nextButton.setText(R.string.btn_next); - } - - mText.setText(getResources().getString(R.string.share_qr_code_dialog_progress, - mCounter + 1, mContentList.size())); - } - - /** - * Split String by number of characters - * - * @param text - * @param size - * @return - */ - private ArrayList splitString(String text, int size) { - ArrayList strings = new ArrayList(); - int index = 0; - while (index < text.length()) { - strings.add(text.substring(index, Math.min(index + size, text.length()))); - index += size; - } - - return strings; - } } -- cgit v1.2.3 From b4a9d1a2db941a66bade5be2e12fe3ea7f1a3f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 7 May 2014 18:31:31 +0200 Subject: Add applications section to help --- .../sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java | 4 ++-- .../java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java | 2 +- .../java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java | 2 +- .../sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java index 2fd1ad3b5..d0b958844 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java @@ -250,7 +250,7 @@ public class RemoteServiceActivity extends ActionBarActivity { // set text on view HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_select_pub_keys_text); - textView.setHtmlFromString(text); + textView.setHtmlFromString(text, true); /* Load select pub keys fragment */ // Check that the activity is using the layout version with @@ -292,7 +292,7 @@ public class RemoteServiceActivity extends ActionBarActivity { // set text on view HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_app_error_message_text); - textView.setHtmlFromString(text); + textView.setHtmlFromString(text, true); } else { Log.e(Constants.TAG, "Action does not exist!"); setResult(RESULT_CANCELED); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java index ec9f3a759..5909970af 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java @@ -45,7 +45,7 @@ public class HelpAboutFragment extends Fragment { HtmlTextView aboutTextView = (HtmlTextView) view.findViewById(R.id.help_about_text); // load html from raw resource (Parsing handled by HtmlTextView library) - aboutTextView.setHtmlFromRawResource(getActivity(), R.raw.help_about); + aboutTextView.setHtmlFromRawResource(getActivity(), R.raw.help_about, true); // no flickering when clicking textview for Android < 4 aboutTextView.setTextColor(getResources().getColor(android.R.color.black)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java index 98c84e5e3..a3f0ef614 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java @@ -66,7 +66,7 @@ public class HelpHtmlFragment extends Fragment { scroller.addView(text); // load html from raw resource (Parsing handled by HtmlTextView library) - text.setHtmlFromRawResource(getActivity(), mHtmlFile); + text.setHtmlFromRawResource(getActivity(), mHtmlFile, true); // no flickering when clicking textview for Android < 4 text.setTextColor(getResources().getColor(android.R.color.black)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java index 15df53dcc..cd2364d7c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java @@ -78,7 +78,7 @@ public class ShareNfcDialogFragment extends DialogFragment { + getString(R.string.error_nfc_needed)); } else { // nfc works... - textView.setHtmlFromRawResource(getActivity(), R.raw.nfc_beam_share); + textView.setHtmlFromRawResource(getActivity(), R.raw.nfc_beam_share, true); alert.setNegativeButton(R.string.menu_beam_preferences, new DialogInterface.OnClickListener() { -- cgit v1.2.3 From 346b5dbb2821254ffc7052871e5ded3207edc29f Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 7 May 2014 22:41:09 +0200 Subject: Don't allow certification using keys where primary subkey is stripped Closes #596 --- .../keychain/ui/SelectSecretKeyFragment.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java index 6de03198e..38a0c8478 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java @@ -56,7 +56,7 @@ public class SelectSecretKeyFragment extends ListFragment implements Bundle args = new Bundle(); args.putBoolean(ARG_FILTER_CERTIFY, filterCertify); - args.putBoolean(ARG_FILTER_CERTIFY, filterSign); + args.putBoolean(ARG_FILTER_SIGN, filterSign); frag.setArguments(args); return frag; @@ -124,7 +124,8 @@ public class SelectSecretKeyFragment extends ListFragment implements KeyRings.CAN_CERTIFY, // has sign may be any subkey KeyRings.HAS_SIGN, - KeyRings.HAS_ANY_SECRET + KeyRings.HAS_ANY_SECRET, + KeyRings.HAS_SECRET }; String where = KeyRings.HAS_ANY_SECRET + " = 1"; @@ -158,7 +159,7 @@ public class SelectSecretKeyFragment extends ListFragment implements private class SelectSecretKeyCursorAdapter extends SelectKeyCursorAdapter { - private int mIndexHasSign, mIndexCanCertify; + private int mIndexHasSign, mIndexCanCertify, mIndexHasSecret; public SelectSecretKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView) { super(context, c, flags, listView); @@ -170,6 +171,7 @@ public class SelectSecretKeyFragment extends ListFragment implements if (cursor != null) { mIndexCanCertify = cursor.getColumnIndexOrThrow(KeyRings.CAN_CERTIFY); mIndexHasSign = cursor.getColumnIndexOrThrow(KeyRings.HAS_SIGN); + mIndexHasSecret = cursor.getColumnIndexOrThrow(KeyRings.HAS_SECRET); } } @@ -187,7 +189,8 @@ public class SelectSecretKeyFragment extends ListFragment implements // Check if key is viable for our purposes (certify or sign) if(mFilterCertify) { // Only enable if can certify - if (cursor.getInt(mIndexCanCertify) == 0) { + if (cursor.getInt(mIndexCanCertify) == 0 + || cursor.getInt(mIndexHasSecret) == 0) { h.status.setText(R.string.can_certify_not); } else { h.status.setText(R.string.can_certify); -- cgit v1.2.3 From 596478a21297888c561276b081eb70fbd29e66ab Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 8 May 2014 13:39:59 +0200 Subject: extract generic LoaderFragment superclass from KeyList --- .../keychain/ui/KeyListFragment.java | 71 +++----------------- .../keychain/ui/LoaderFragment.java | 78 ++++++++++++++++++++++ 2 files changed, 88 insertions(+), 61 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java (limited to 'OpenKeychain/src/main/java') 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 5464a9b96..3fd958bcc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -29,7 +29,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Messenger; -import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; @@ -45,10 +44,8 @@ import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.view.animation.AnimationUtils; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; -import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; @@ -78,18 +75,13 @@ 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. */ -public class KeyListFragment extends Fragment +public class KeyListFragment extends LoaderFragment implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks { private KeyListAdapter mAdapter; private StickyListHeadersListView mStickyList; - // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 - boolean mListShown; - View mProgressContainer; - View mListContainer; - private String mCurQuery; private SearchView mSearchView; // empty list layout @@ -101,14 +93,15 @@ public class KeyListFragment extends Fragment * Load custom layout with StickyListView from library */ @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View root = inflater.inflate(R.layout.key_list_fragment, container, false); + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.key_list_fragment, getContainer()); - mStickyList = (StickyListHeadersListView) root.findViewById(R.id.key_list_list); + mStickyList = (StickyListHeadersListView) view.findViewById(R.id.key_list_list); mStickyList.setOnItemClickListener(this); // empty view - mButtonEmptyCreate = (BootstrapButton) root.findViewById(R.id.key_list_empty_button_create); + mButtonEmptyCreate = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_create); mButtonEmptyCreate.setOnClickListener(new OnClickListener() { @Override @@ -120,7 +113,7 @@ public class KeyListFragment extends Fragment startActivityForResult(intent, 0); } }); - mButtonEmptyImport = (BootstrapButton) root.findViewById(R.id.key_list_empty_button_import); + mButtonEmptyImport = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_import); mButtonEmptyImport.setOnClickListener(new OnClickListener() { @Override @@ -131,11 +124,6 @@ public class KeyListFragment extends Fragment } }); - // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 - mListContainer = root.findViewById(R.id.key_list_list_container); - mProgressContainer = root.findViewById(R.id.key_list_progress_container); - mListShown = true; - return root; } @@ -234,9 +222,8 @@ public class KeyListFragment extends Fragment // We have a menu item to show in action bar. setHasOptionsMenu(true); - // NOTE: Not supported by StickyListHeader, but reimplemented here // Start out with a progress indicator. - setListShown(false); + setContentShown(false); // Create an empty adapter we will use to display the loaded data. mAdapter = new KeyListAdapter(getActivity(), null, 0); @@ -298,12 +285,11 @@ public class KeyListFragment extends Fragment // this view is made visible if no data is available mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty)); - // NOTE: Not supported by StickyListHeader, but reimplemented here // The list should now be shown. if (isResumed()) { - setListShown(true); + setContentShown(true); } else { - setListShownNoAnimation(true); + setContentShownNoAnimation(true); } } @@ -418,43 +404,6 @@ public class KeyListFragment extends Fragment return true; } - // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 - public void setListShown(boolean shown, boolean animate) { - if (mListShown == shown) { - return; - } - mListShown = shown; - if (shown) { - if (animate) { - mProgressContainer.startAnimation(AnimationUtils.loadAnimation( - getActivity(), android.R.anim.fade_out)); - mListContainer.startAnimation(AnimationUtils.loadAnimation( - getActivity(), android.R.anim.fade_in)); - } - mProgressContainer.setVisibility(View.GONE); - mListContainer.setVisibility(View.VISIBLE); - } else { - if (animate) { - mProgressContainer.startAnimation(AnimationUtils.loadAnimation( - getActivity(), android.R.anim.fade_in)); - mListContainer.startAnimation(AnimationUtils.loadAnimation( - getActivity(), android.R.anim.fade_out)); - } - mProgressContainer.setVisibility(View.VISIBLE); - mListContainer.setVisibility(View.INVISIBLE); - } - } - - // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 - public void setListShown(boolean shown) { - setListShown(shown, true); - } - - // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 - public void setListShownNoAnimation(boolean shown) { - setListShown(shown, false); - } - /** * Implements StickyListHeadersAdapter from library */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java new file mode 100644 index 000000000..87ab1bb8c --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java @@ -0,0 +1,78 @@ +package org.sufficientlysecure.keychain.ui; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AnimationUtils; + +import org.sufficientlysecure.keychain.R; + +/** This is a fragment helper class, which implements a generic + * progressbar/container view. + * + * To use it in a fragment, simply subclass, use onCreateView to create the + * layout's root view, and ues getContainer() as root view of your subclass. + * The layout shows a progress bar by default, and can be switched to the + * actual contents by calling setContentShown(). + * + */ +public class LoaderFragment extends Fragment { + private boolean mContentShown; + private View mProgressContainer; + private ViewGroup mContainer; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.loader_layout, container, false); + + mContentShown = true; + mContainer = (ViewGroup) root.findViewById(R.id.loader_container); + mProgressContainer = root.findViewById(R.id.loader_progress); + + // content is not shown (by visibility statuses in the layout files) + mContentShown = false; + + return root; + + } + + protected ViewGroup getContainer() { + return mContainer; + } + + public void setContentShown(boolean shown, boolean animate) { + if (mContentShown == shown) { + return; + } + mContentShown = shown; + if (shown) { + if (animate) { + mProgressContainer.startAnimation(AnimationUtils.loadAnimation( + getActivity(), android.R.anim.fade_out)); + mContainer.startAnimation(AnimationUtils.loadAnimation( + getActivity(), android.R.anim.fade_in)); + } + mProgressContainer.setVisibility(View.GONE); + mContainer.setVisibility(View.VISIBLE); + } else { + if (animate) { + mProgressContainer.startAnimation(AnimationUtils.loadAnimation( + getActivity(), android.R.anim.fade_in)); + mContainer.startAnimation(AnimationUtils.loadAnimation( + getActivity(), android.R.anim.fade_out)); + } + mProgressContainer.setVisibility(View.VISIBLE); + mContainer.setVisibility(View.INVISIBLE); + } + } + + public void setContentShown(boolean shown) { + setContentShown(shown, true); + } + + public void setContentShownNoAnimation(boolean shown) { + setContentShown(shown, false); + } +} -- cgit v1.2.3 From 185c4eed4349d7539c2ddcbe696a8c80b523d214 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 8 May 2014 13:57:46 +0200 Subject: use LoaderFragment in ViewKey tabs Closes #616 --- .../keychain/ui/ViewKeyCertsFragment.java | 17 +++++++++------- .../keychain/ui/ViewKeyKeysFragment.java | 18 +++++++---------- .../keychain/ui/ViewKeyMainFragment.java | 23 ++++++++-------------- .../keychain/ui/ViewKeyShareFragment.java | 18 +++++++---------- 4 files changed, 32 insertions(+), 44 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java index e1c2013ea..d5658586d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java @@ -23,7 +23,6 @@ import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; @@ -46,7 +45,7 @@ import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; import se.emilsjolander.stickylistheaders.StickyListHeadersListView; -public class ViewKeyCertsFragment extends Fragment +public class ViewKeyCertsFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks, AdapterView.OnItemClickListener { // These are the rows that we will retrieve. @@ -79,18 +78,19 @@ public class ViewKeyCertsFragment extends Fragment private static final int LOADER_ID = 4; @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.view_key_certs_fragment, container, false); + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.view_key_certs_fragment, getContainer()); - return view; + mStickyList = (StickyListHeadersListView) view.findViewById(R.id.list); + + return root; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - mStickyList = (StickyListHeadersListView) getActivity().findViewById(R.id.list); - if (!getArguments().containsKey(ARG_DATA_URI)) { Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); getActivity().finish(); @@ -120,6 +120,7 @@ public class ViewKeyCertsFragment extends Fragment @Override public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. return new CursorLoader(getActivity(), mDataUri, PROJECTION, null, null, SORT_ORDER); @@ -132,6 +133,8 @@ public class ViewKeyCertsFragment extends Fragment mAdapter.swapCursor(data); mStickyList.setAdapter(mAdapter); + + setContentShown(true); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java index 9ab6878d0..fb228f032 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java @@ -44,12 +44,11 @@ import org.sufficientlysecure.keychain.util.Log; import java.util.Date; -public class ViewKeyKeysFragment extends Fragment implements +public class ViewKeyKeysFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks { public static final String ARG_DATA_URI = "uri"; - private LinearLayout mContainer; private ListView mKeys; private ViewKeyKeysAdapter mKeysAdapter; @@ -57,13 +56,13 @@ public class ViewKeyKeysFragment extends Fragment implements private Uri mDataUri; @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.view_key_keys_fragment, container, false); + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.view_key_keys_fragment, getContainer()); - mContainer = (LinearLayout) view.findViewById(R.id.container); mKeys = (ListView) view.findViewById(R.id.keys); - return view; + return root; } @Override @@ -81,9 +80,6 @@ public class ViewKeyKeysFragment extends Fragment implements } private void loadData(Uri dataUri) { - getActivity().setProgressBarIndeterminateVisibility(true); - mContainer.setVisibility(View.GONE); - mDataUri = dataUri; Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); @@ -104,6 +100,7 @@ public class ViewKeyKeysFragment extends Fragment implements }; public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); Uri baseUri = Keys.buildKeysUri(mDataUri); return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, null); } @@ -117,8 +114,7 @@ public class ViewKeyKeysFragment extends Fragment implements // old cursor once we return.) mKeysAdapter.swapCursor(data); - getActivity().setProgressBarIndeterminateVisibility(false); - mContainer.setVisibility(View.VISIBLE); + setContentShown(true); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index b30c9aaec..026417776 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -21,15 +21,12 @@ import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; -import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.LinearLayout; import android.widget.ListView; import com.devspark.appmsg.AppMsg; @@ -37,7 +34,6 @@ import com.devspark.appmsg.AppMsg; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R;import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter; @@ -45,12 +41,11 @@ import org.sufficientlysecure.keychain.util.Log; import java.util.Date; -public class ViewKeyMainFragment extends Fragment implements +public class ViewKeyMainFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks { public static final String ARG_DATA_URI = "uri"; - private LinearLayout mContainer; private View mActionEdit; private View mActionEditDivider; private View mActionEncrypt; @@ -70,10 +65,10 @@ public class ViewKeyMainFragment extends Fragment implements private Uri mDataUri; @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.view_key_main_fragment, container, false); + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.view_key_main_fragment, getContainer()); - mContainer = (LinearLayout) view.findViewById(R.id.container); mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); mActionEdit = view.findViewById(R.id.view_key_action_edit); mActionEditDivider = view.findViewById(R.id.view_key_action_edit_divider); @@ -81,7 +76,7 @@ public class ViewKeyMainFragment extends Fragment implements mActionCertify = view.findViewById(R.id.view_key_action_certify); mActionCertifyDivider = view.findViewById(R.id.view_key_action_certify_divider); - return view; + return root; } @Override @@ -99,9 +94,6 @@ public class ViewKeyMainFragment extends Fragment implements } private void loadData(Uri dataUri) { - getActivity().setProgressBarIndeterminateVisibility(true); - mContainer.setVisibility(View.GONE); - mDataUri = dataUri; Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); @@ -143,6 +135,8 @@ public class ViewKeyMainFragment extends Fragment implements static final int INDEX_UNIFIED_HAS_ENCRYPT = 5; public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); + switch (id) { case LOADER_ID_UNIFIED: { Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); @@ -219,8 +213,7 @@ public class ViewKeyMainFragment extends Fragment implements break; } - getActivity().setProgressBarIndeterminateVisibility(false); - mContainer.setVisibility(View.VISIBLE); + setContentShown(true); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java index 1a76f5eed..b3655133d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java @@ -53,12 +53,11 @@ import org.sufficientlysecure.keychain.util.QrCodeUtils; import java.io.IOException; -public class ViewKeyShareFragment extends Fragment implements +public class ViewKeyShareFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks { public static final String ARG_DATA_URI = "uri"; - private LinearLayout mContainer; private TextView mFingerprint; private ImageView mFingerprintQrCode; private View mFingerprintShareButton; @@ -77,12 +76,12 @@ public class ViewKeyShareFragment extends Fragment implements private Uri mDataUri; @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.view_key_share_fragment, container, false); + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.view_key_share_fragment, getContainer()); mProviderHelper = new ProviderHelper(ViewKeyShareFragment.this.getActivity()); - mContainer = (LinearLayout) view.findViewById(R.id.container); mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint); mFingerprintQrCode = (ImageView) view.findViewById(R.id.view_key_fingerprint_qr_code_image); mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share); @@ -142,7 +141,7 @@ public class ViewKeyShareFragment extends Fragment implements } }); - return view; + return root; } private void share(Uri dataUri, ProviderHelper providerHelper, boolean fingerprintOnly, @@ -232,9 +231,6 @@ public class ViewKeyShareFragment extends Fragment implements } private void loadData(Uri dataUri) { - getActivity().setProgressBarIndeterminateVisibility(true); - mContainer.setVisibility(View.GONE); - mDataUri = dataUri; Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); @@ -260,6 +256,7 @@ public class ViewKeyShareFragment extends Fragment implements static final int INDEX_UNIFIED_EXPIRY = 8; public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); switch (id) { case LOADER_ID_UNIFIED: { Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); @@ -299,8 +296,7 @@ public class ViewKeyShareFragment extends Fragment implements } } - getActivity().setProgressBarIndeterminateVisibility(false); - mContainer.setVisibility(View.VISIBLE); + setContentShown(true); } /** -- cgit v1.2.3 From 9c5c013538a833aa071c15fefb5e918098d7fc6c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 8 May 2014 15:31:03 +0200 Subject: use setEncryptToSigner for asymmetric encryption (tested and works, closes #569) --- .../main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java | 2 -- .../org/sufficientlysecure/keychain/service/KeychainIntentService.java | 1 + .../org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java | 3 --- 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java index 30cac9b77..665dc82cc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -192,8 +192,6 @@ public class PgpSignEncrypt { } /** - * TODO: test this option! - * * @param encryptToSigner * @return */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index d2e9533a7..d363a4119 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -324,6 +324,7 @@ public class KeychainIntentService extends IntentService .setEncryptionMasterKeyIds(encryptionKeyIds) .setSymmetricPassphrase(symmetricPassphrase) .setSignatureMasterKeyId(signatureKeyId) + .setEncryptToSigner(true) .setSignatureHashAlgorithm( Preferences.getPreferences(this).getDefaultHashAlgorithm()) .setSignaturePassphrase( diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index d1a5dca07..c954e6465 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -226,9 +226,6 @@ public class EncryptAsymmetricFragment extends Fragment { private void selectPublicKeys() { Intent intent = new Intent(getActivity(), SelectPublicKeyActivity.class); Vector keyIds = new Vector(); - if (mSecretKeyId != 0) { - keyIds.add(mSecretKeyId); - } if (mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0) { for (int i = 0; i < mEncryptionKeyIds.length; ++i) { keyIds.add(mEncryptionKeyIds[i]); -- cgit v1.2.3 From 33cad382f96b673587e841932ea322a1dd6fa23b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 8 May 2014 15:46:57 +0200 Subject: Use flat buttons where appropriate --- .../org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java | 10 ++++------ .../org/sufficientlysecure/keychain/ui/ImportKeysActivity.java | 4 ++-- .../org/sufficientlysecure/keychain/ui/UploadKeyActivity.java | 10 ++++------ 3 files changed, 10 insertions(+), 14 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index 29969ca55..bd12a3b52 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -29,7 +29,6 @@ import android.support.v4.app.LoaderManager; import android.support.v4.app.NavUtils; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.view.MenuItem; import android.view.View; @@ -42,7 +41,6 @@ import android.widget.ListView; import android.widget.Spinner; import android.widget.TextView; -import com.beardedhen.androidbootstrap.BootstrapButton; import com.devspark.appmsg.AppMsg; import org.spongycastle.openpgp.PGPPublicKeyRing; @@ -68,7 +66,7 @@ import java.util.ArrayList; */ public class CertifyKeyActivity extends ActionBarActivity implements SelectSecretKeyLayoutFragment.SelectSecretKeyCallback, LoaderManager.LoaderCallbacks { - private BootstrapButton mSignButton; + private View mSignButton; private CheckBox mUploadKeyCheckbox; private Spinner mSelectKeyserverSpinner; @@ -95,7 +93,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements mSelectKeyFragment.setCallback(this); mSelectKeyFragment.setFilterCertify(true); - mSelectKeyserverSpinner = (Spinner) findViewById(R.id.sign_key_keyserver); + mSelectKeyserverSpinner = (Spinner) findViewById(R.id.upload_key_keyserver); ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, Preferences.getPreferences(this) .getKeyServers() @@ -122,7 +120,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements } }); - mSignButton = (BootstrapButton) findViewById(R.id.sign_key_sign_button); + mSignButton = findViewById(R.id.sign_key_sign_button); mSignButton.setOnClickListener(new OnClickListener() { @Override @@ -350,7 +348,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements // fill values for this action Bundle data = new Bundle(); - Spinner keyServer = (Spinner) findViewById(R.id.sign_key_keyserver); + Spinner keyServer = (Spinner) findViewById(R.id.upload_key_keyserver); String server = (String) keyServer.getSelectedItem(); data.putString(KeychainIntentService.UPLOAD_KEY_SERVER, server); 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 f71ef6d46..bb5d2e922 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -86,7 +86,7 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O private ImportKeysListFragment mListFragment; private String[] mNavigationStrings; private Fragment mCurrentFragment; - private BootstrapButton mImportButton; + private View mImportButton; private static final Class[] NAVIGATION_CLASSES = new Class[]{ ImportKeysServerFragment.class, @@ -111,7 +111,7 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O setContentView(R.layout.import_keys_activity); - mImportButton = (BootstrapButton) findViewById(R.id.import_import); + mImportButton = findViewById(R.id.import_import); mImportButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { 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 90783aa8b..dbd1b7507 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -32,8 +32,6 @@ import android.widget.ArrayAdapter; import android.widget.Spinner; import android.widget.Toast; -import com.beardedhen.androidbootstrap.BootstrapButton; - import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.Preferences; @@ -46,7 +44,7 @@ import org.sufficientlysecure.keychain.util.Log; * Sends the selected public key to a keyserver */ public class UploadKeyActivity extends ActionBarActivity { - private BootstrapButton mUploadButton; + private View mUploadButton; private Spinner mKeyServerSpinner; private Uri mDataUri; @@ -55,10 +53,10 @@ public class UploadKeyActivity extends ActionBarActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.key_server_export); + setContentView(R.layout.upload_key_activity); - mUploadButton = (BootstrapButton) findViewById(R.id.btn_export_to_server); - mKeyServerSpinner = (Spinner) findViewById(R.id.sign_key_keyserver); + mUploadButton = findViewById(R.id.upload_key_action_upload); + mKeyServerSpinner = (Spinner) findViewById(R.id.upload_key_keyserver); ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, Preferences.getPreferences(this) -- cgit v1.2.3 From 79117b1ef8074434579191e1dd734f9445d6544f Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 8 May 2014 15:56:49 +0200 Subject: use longsparsearrays instead of hashmaps in that one place --- .../keychain/provider/ProviderHelper.java | 35 ++++++++++++---------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 214a9988c..7ef186f00 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -26,6 +26,7 @@ import android.database.Cursor; import android.database.DatabaseUtils; import android.net.Uri; import android.os.RemoteException; +import android.support.v4.util.LongSparseArray; import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.S2K; @@ -167,33 +168,35 @@ public class ProviderHelper { } } - public Map getPGPKeyRings(Uri queryUri) { + public LongSparseArray getPGPKeyRings(Uri queryUri) { Cursor cursor = mContentResolver.query(queryUri, new String[]{KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA}, null, null, null); - Map result = new HashMap(cursor.getCount()); - if (cursor != null && cursor.moveToFirst()) do { - long masterKeyId = cursor.getLong(0); - byte[] data = cursor.getBlob(1); - if (data != null) { - result.put(masterKeyId, PgpConversionHelper.BytesToPGPKeyRing(data)); + LongSparseArray result = new LongSparseArray(cursor.getCount()); + try { + if (cursor != null && cursor.moveToFirst()) do { + long masterKeyId = cursor.getLong(0); + byte[] data = cursor.getBlob(1); + if (data != null) { + result.put(masterKeyId, PgpConversionHelper.BytesToPGPKeyRing(data)); + } + } while (cursor.moveToNext()); + } finally { + if (cursor != null) { + cursor.close(); } - } while (cursor.moveToNext()); - - if (cursor != null) { - cursor.close(); } return result; } public PGPKeyRing getPGPKeyRing(Uri queryUri) throws NotFoundException { - Map result = getPGPKeyRings(queryUri); - if (result.isEmpty()) { + LongSparseArray result = getPGPKeyRings(queryUri); + if (result.size() == 0) { throw new NotFoundException("PGPKeyRing object not found!"); } else { - return result.values().iterator().next(); + return result.valueAt(0); } } @@ -267,7 +270,7 @@ public class ProviderHelper { } // get a list of owned secret keys, for verification filtering - Map allKeyRings = getPGPKeyRings(KeyRingData.buildSecretKeyRingUri()); + LongSparseArray allKeyRings = getPGPKeyRings(KeyRingData.buildSecretKeyRingUri()); // special case: available secret keys verify themselves! if (secretRing != null) allKeyRings.put(secretRing.getSecretKey().getKeyID(), secretRing); @@ -305,7 +308,7 @@ public class ProviderHelper { } } // verify signatures from known private keys - if (allKeyRings.containsKey(certId)) { + if (allKeyRings.indexOfKey(certId) >= 0) { // mark them as verified cert.init(new JcaPGPContentVerifierBuilderProvider().setProvider( Constants.BOUNCY_CASTLE_PROVIDER_NAME), -- cgit v1.2.3 From cbc3988628d09ed8a4fe967e1f21786f46cb038b Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 8 May 2014 15:56:32 +0200 Subject: proper null checks and closing of cursors everywhere --- .../keychain/helper/FileHelper.java | 12 +- .../keychain/provider/KeychainDatabase.java | 65 ++++--- .../keychain/provider/KeychainProvider.java | 13 +- .../keychain/provider/ProviderHelper.java | 208 ++++++++++++--------- .../keychain/remote/OpenPgpService.java | 32 ++-- .../keychain/service/KeychainIntentService.java | 7 +- 6 files changed, 189 insertions(+), 148 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/FileHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/FileHelper.java index f22fcd4b8..d7d73cf3d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/FileHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/FileHelper.java @@ -112,16 +112,18 @@ public class FileHelper { if ("content".equalsIgnoreCase(uri.getScheme())) { String[] projection = {"_data"}; - Cursor cursor = null; - + Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null); try { - cursor = context.getContentResolver().query(uri, projection, null, null, null); - int columnIndex = cursor.getColumnIndexOrThrow("_data"); - if (cursor.moveToFirst()) { + if (cursor != null && cursor.moveToFirst()) { + int columnIndex = cursor.getColumnIndexOrThrow("_data"); return cursor.getString(columnIndex); } } catch (Exception e) { // Eat it + } finally { + if (cursor != null) { + cursor.close(); + } } } else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index 061f91176..68726d3e0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -255,53 +255,60 @@ public class KeychainDatabase extends SQLiteOpenHelper { } }.getReadableDatabase(); - Cursor c = null; + Cursor cursor = null; try { // we insert in two steps: first, all public keys that have secret keys - c = db.rawQuery("SELECT key_ring_data FROM key_rings WHERE type = 1 OR EXISTS (" + cursor = db.rawQuery("SELECT key_ring_data FROM key_rings WHERE type = 1 OR EXISTS (" + " SELECT 1 FROM key_rings d2 WHERE key_rings.master_key_id = d2.master_key_id" + " AND d2.type = 1) ORDER BY type ASC", null); - Log.d(Constants.TAG, "Importing " + c.getCount() + " secret keyrings from apg.db..."); - for (int i = 0; i < c.getCount(); i++) { - c.moveToPosition(i); - byte[] data = c.getBlob(0); - PGPKeyRing ring = PgpConversionHelper.BytesToPGPKeyRing(data); - ProviderHelper providerHelper = new ProviderHelper(context); - if (ring instanceof PGPPublicKeyRing) - providerHelper.saveKeyRing((PGPPublicKeyRing) ring); - else if (ring instanceof PGPSecretKeyRing) - providerHelper.saveKeyRing((PGPSecretKeyRing) ring); - else { - Log.e(Constants.TAG, "Unknown blob data type!"); + Log.d(Constants.TAG, "Importing " + cursor.getCount() + " secret keyrings from apg.db..."); + if (cursor != null) { + for (int i = 0; i < cursor.getCount(); i++) { + cursor.moveToPosition(i); + byte[] data = cursor.getBlob(0); + PGPKeyRing ring = PgpConversionHelper.BytesToPGPKeyRing(data); + ProviderHelper providerHelper = new ProviderHelper(context); + if (ring instanceof PGPPublicKeyRing) + providerHelper.saveKeyRing((PGPPublicKeyRing) ring); + else if (ring instanceof PGPSecretKeyRing) + providerHelper.saveKeyRing((PGPSecretKeyRing) ring); + else { + Log.e(Constants.TAG, "Unknown blob data type!"); + } } } + if (cursor != null) { + cursor.close(); + } // afterwards, insert all keys, starting with public keys that have secret keys, then // secret keys, then all others. this order is necessary to ensure all certifications // are recognized properly. - c = db.rawQuery("SELECT key_ring_data FROM key_rings ORDER BY (type = 0 AND EXISTS (" + cursor = db.rawQuery("SELECT key_ring_data FROM key_rings ORDER BY (type = 0 AND EXISTS (" + " SELECT 1 FROM key_rings d2 WHERE key_rings.master_key_id = d2.master_key_id AND" + " d2.type = 1)) DESC, type DESC", null); // import from old database - Log.d(Constants.TAG, "Importing " + c.getCount() + " keyrings from apg.db..."); - for (int i = 0; i < c.getCount(); i++) { - c.moveToPosition(i); - byte[] data = c.getBlob(0); - PGPKeyRing ring = PgpConversionHelper.BytesToPGPKeyRing(data); - ProviderHelper providerHelper = new ProviderHelper(context); - if (ring instanceof PGPPublicKeyRing) { - providerHelper.saveKeyRing((PGPPublicKeyRing) ring); - } else if (ring instanceof PGPSecretKeyRing) { - providerHelper.saveKeyRing((PGPSecretKeyRing) ring); - } else { - Log.e(Constants.TAG, "Unknown blob data type!"); + Log.d(Constants.TAG, "Importing " + cursor.getCount() + " keyrings from apg.db..."); + if (cursor != null) { + for (int i = 0; i < cursor.getCount(); i++) { + cursor.moveToPosition(i); + byte[] data = cursor.getBlob(0); + PGPKeyRing ring = PgpConversionHelper.BytesToPGPKeyRing(data); + ProviderHelper providerHelper = new ProviderHelper(context); + if (ring instanceof PGPPublicKeyRing) { + providerHelper.saveKeyRing((PGPPublicKeyRing) ring); + } else if (ring instanceof PGPSecretKeyRing) { + providerHelper.saveKeyRing((PGPSecretKeyRing) ring); + } else { + Log.e(Constants.TAG, "Unknown blob data type!"); + } } } } catch (IOException e) { Log.e(Constants.TAG, "Error importing apg.db!", e); } finally { - if (c != null) { - c.close(); + if (cursor != null) { + cursor.close(); } if (db != null) { db.close(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 1dc822ac2..ec7bf58d9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -541,20 +541,21 @@ public class KeychainProvider extends ContentProvider { } SQLiteDatabase db = getDb().getReadableDatabase(); - Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, having, orderBy); - - // Tell the cursor what uri to watch, so it knows when its source data changes - c.setNotificationUri(getContext().getContentResolver(), uri); + Cursor cursor = qb.query(db, projection, selection, selectionArgs, groupBy, having, orderBy); + if (cursor != null) { + // Tell the cursor what uri to watch, so it knows when its source data changes + cursor.setNotificationUri(getContext().getContentResolver(), uri); + } if (Constants.DEBUG) { Log.d(Constants.TAG, "Query: " + qb.buildQuery(projection, selection, selectionArgs, null, null, orderBy, null)); - Log.d(Constants.TAG, "Cursor: " + DatabaseUtils.dumpCursorToString(c)); + Log.d(Constants.TAG, "Cursor: " + DatabaseUtils.dumpCursorToString(cursor)); } - return c; + return cursor; } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 7ef186f00..ab00db13a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -100,36 +100,38 @@ public class ProviderHelper { throws NotFoundException { Cursor cursor = mContentResolver.query(uri, proj, null, null, null); - HashMap result = new HashMap(proj.length); - if (cursor != null && cursor.moveToFirst()) { - int pos = 0; - for (String p : proj) { - switch (types[pos]) { - case FIELD_TYPE_NULL: - result.put(p, cursor.isNull(pos)); - break; - case FIELD_TYPE_INTEGER: - result.put(p, cursor.getLong(pos)); - break; - case FIELD_TYPE_FLOAT: - result.put(p, cursor.getFloat(pos)); - break; - case FIELD_TYPE_STRING: - result.put(p, cursor.getString(pos)); - break; - case FIELD_TYPE_BLOB: - result.put(p, cursor.getBlob(pos)); - break; + try { + HashMap result = new HashMap(proj.length); + if (cursor != null && cursor.moveToFirst()) { + int pos = 0; + for (String p : proj) { + switch (types[pos]) { + case FIELD_TYPE_NULL: + result.put(p, cursor.isNull(pos)); + break; + case FIELD_TYPE_INTEGER: + result.put(p, cursor.getLong(pos)); + break; + case FIELD_TYPE_FLOAT: + result.put(p, cursor.getFloat(pos)); + break; + case FIELD_TYPE_STRING: + result.put(p, cursor.getString(pos)); + break; + case FIELD_TYPE_BLOB: + result.put(p, cursor.getBlob(pos)); + break; + } + pos += 1; } - pos += 1; } - } - if (cursor != null) { - cursor.close(); + return result; + } finally { + if (cursor != null) { + cursor.close(); + } } - - return result; } public Object getUnifiedData(long masterKeyId, String column, int type) @@ -576,27 +578,29 @@ public class ProviderHelper { }, inMasterKeyList, null, null); } - if (cursor != null) { - int masterIdCol = cursor.getColumnIndex(KeyRingData.MASTER_KEY_ID); - int dataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA); - if (cursor.moveToFirst()) { - do { - Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol)); - - byte[] data = cursor.getBlob(dataCol); - - // get actual keyring data blob and write it to ByteArrayOutputStream - try { - output.add(getKeyRingAsArmoredString(data)); - } catch (IOException e) { - Log.e(Constants.TAG, "IOException", e); - } - } while (cursor.moveToNext()); + try { + if (cursor != null) { + int masterIdCol = cursor.getColumnIndex(KeyRingData.MASTER_KEY_ID); + int dataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA); + if (cursor.moveToFirst()) { + do { + Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol)); + + byte[] data = cursor.getBlob(dataCol); + + // get actual keyring data blob and write it to ByteArrayOutputStream + try { + output.add(getKeyRingAsArmoredString(data)); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException", e); + } + } while (cursor.moveToNext()); + } + } + } finally { + if (cursor != null) { + cursor.close(); } - } - - if (cursor != null) { - cursor.close(); } if (output.size() > 0) { @@ -610,17 +614,19 @@ public class ProviderHelper { Cursor cursor = mContentResolver.query(ApiApps.CONTENT_URI, null, null, null, null); ArrayList packageNames = new ArrayList(); - if (cursor != null) { - int packageNameCol = cursor.getColumnIndex(ApiApps.PACKAGE_NAME); - if (cursor.moveToFirst()) { - do { - packageNames.add(cursor.getString(packageNameCol)); - } while (cursor.moveToNext()); + try { + if (cursor != null) { + int packageNameCol = cursor.getColumnIndex(ApiApps.PACKAGE_NAME); + if (cursor.moveToFirst()) { + do { + packageNames.add(cursor.getString(packageNameCol)); + } while (cursor.moveToNext()); + } + } + } finally { + if (cursor != null) { + cursor.close(); } - } - - if (cursor != null) { - cursor.close(); } return packageNames; @@ -668,13 +674,19 @@ public class ProviderHelper { public AppSettings getApiAppSettings(Uri uri) { AppSettings settings = null; - Cursor cur = mContentResolver.query(uri, null, null, null, null); - if (cur != null && cur.moveToFirst()) { - settings = new AppSettings(); - settings.setPackageName(cur.getString( - cur.getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME))); - settings.setPackageSignature(cur.getBlob( - cur.getColumnIndex(KeychainContract.ApiApps.PACKAGE_SIGNATURE))); + Cursor cursor = mContentResolver.query(uri, null, null, null, null); + try { + if (cursor != null && cursor.moveToFirst()) { + settings = new AppSettings(); + settings.setPackageName(cursor.getString( + cursor.getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME))); + settings.setPackageSignature(cursor.getBlob( + cursor.getColumnIndex(KeychainContract.ApiApps.PACKAGE_SIGNATURE))); + } + } finally { + if (cursor != null) { + cursor.close(); + } } return settings; @@ -683,20 +695,26 @@ public class ProviderHelper { public AccountSettings getApiAccountSettings(Uri accountUri) { AccountSettings settings = null; - Cursor cur = mContentResolver.query(accountUri, null, null, null, null); - if (cur != null && cur.moveToFirst()) { - settings = new AccountSettings(); - - settings.setAccountName(cur.getString( - cur.getColumnIndex(KeychainContract.ApiAccounts.ACCOUNT_NAME))); - settings.setKeyId(cur.getLong( - cur.getColumnIndex(KeychainContract.ApiAccounts.KEY_ID))); - settings.setCompression(cur.getInt( - cur.getColumnIndexOrThrow(KeychainContract.ApiAccounts.COMPRESSION))); - settings.setHashAlgorithm(cur.getInt( - cur.getColumnIndexOrThrow(KeychainContract.ApiAccounts.HASH_ALORITHM))); - settings.setEncryptionAlgorithm(cur.getInt( - cur.getColumnIndexOrThrow(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM))); + Cursor cursor = mContentResolver.query(accountUri, null, null, null, null); + try { + if (cursor != null && cursor.moveToFirst()) { + settings = new AccountSettings(); + + settings.setAccountName(cursor.getString( + cursor.getColumnIndex(KeychainContract.ApiAccounts.ACCOUNT_NAME))); + settings.setKeyId(cursor.getLong( + cursor.getColumnIndex(KeychainContract.ApiAccounts.KEY_ID))); + settings.setCompression(cursor.getInt( + cursor.getColumnIndexOrThrow(KeychainContract.ApiAccounts.COMPRESSION))); + settings.setHashAlgorithm(cursor.getInt( + cursor.getColumnIndexOrThrow(KeychainContract.ApiAccounts.HASH_ALORITHM))); + settings.setEncryptionAlgorithm(cursor.getInt( + cursor.getColumnIndexOrThrow(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM))); + } + } finally { + if (cursor != null) { + cursor.close(); + } } return settings; @@ -706,10 +724,16 @@ public class ProviderHelper { Set keyIds = new HashSet(); Cursor cursor = mContentResolver.query(uri, null, null, null, null); - if (cursor != null) { - int keyIdColumn = cursor.getColumnIndex(KeychainContract.ApiAccounts.KEY_ID); - while (cursor.moveToNext()) { - keyIds.add(cursor.getLong(keyIdColumn)); + try { + if (cursor != null) { + int keyIdColumn = cursor.getColumnIndex(KeychainContract.ApiAccounts.KEY_ID); + while (cursor.moveToNext()) { + keyIds.add(cursor.getLong(keyIdColumn)); + } + } + } finally { + if (cursor != null) { + cursor.close(); } } @@ -722,18 +746,18 @@ public class ProviderHelper { String[] projection = new String[]{ApiApps.PACKAGE_SIGNATURE}; Cursor cursor = mContentResolver.query(queryUri, projection, null, null, null); + try { + byte[] signature = null; + if (cursor != null && cursor.moveToFirst()) { + int signatureCol = 0; - byte[] signature = null; - if (cursor != null && cursor.moveToFirst()) { - int signatureCol = 0; - - signature = cursor.getBlob(signatureCol); - } - - if (cursor != null) { - cursor.close(); + signature = cursor.getBlob(signatureCol); + } + return signature; + } finally { + if (cursor != null) { + cursor.close(); + } } - - return signature; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index 5691d2fe2..db2db668d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -70,19 +70,25 @@ public class OpenPgpService extends RemoteService { for (String email : encryptionUserIds) { Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email); - Cursor cur = getContentResolver().query(uri, null, null, null, null); - if (cur.moveToFirst()) { - long id = cur.getLong(cur.getColumnIndex(KeyRings.MASTER_KEY_ID)); - keyIds.add(id); - } else { - missingUserIdsCheck = true; - missingUserIds.add(email); - Log.d(Constants.TAG, "user id missing"); - } - if (cur.moveToNext()) { - duplicateUserIdsCheck = true; - duplicateUserIds.add(email); - Log.d(Constants.TAG, "more than one user id with the same email"); + Cursor cursor = getContentResolver().query(uri, null, null, null, null); + try { + if (cursor != null && cursor.moveToFirst()) { + long id = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID)); + keyIds.add(id); + } else { + missingUserIdsCheck = true; + missingUserIds.add(email); + Log.d(Constants.TAG, "user id missing"); + } + if (cursor != null && cursor.moveToNext()) { + duplicateUserIdsCheck = true; + duplicateUserIds.add(email); + Log.d(Constants.TAG, "more than one user id with the same email"); + } + } finally { + if (cursor != null) { + cursor.close(); + } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index d363a4119..f1e30c560 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -690,8 +690,7 @@ public class KeychainIntentService extends IntentService new String[]{KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET}, selection, null, null); try { - cursor.moveToFirst(); - do { + if (cursor != null && cursor.moveToFirst()) do { // export public either way publicMasterKeyIds.add(cursor.getLong(0)); // add secret if available (and requested) @@ -699,7 +698,9 @@ public class KeychainIntentService extends IntentService secretMasterKeyIds.add(cursor.getLong(0)); } while (cursor.moveToNext()); } finally { - cursor.close(); + if (cursor != null) { + cursor.close(); + } } PgpImportExport pgpImportExport = new PgpImportExport(this, this, this); -- cgit v1.2.3 From 4ba06e7735eb64c7b3d02c605e8c91fe986c1976 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 8 May 2014 18:06:12 +0200 Subject: ui: purplize dialog headers (huge hack inside) --- .../keychain/ui/EditKeyActivity.java | 9 ++--- .../keychain/ui/ImportKeysActivity.java | 1 - .../ui/dialog/BadImportKeyDialogFragment.java | 5 ++- .../ui/dialog/CreateKeyDialogFragment.java | 4 +-- .../ui/dialog/CustomAlertDialogBuilder.java | 40 ++++++++++++++++++++++ .../ui/dialog/DeleteFileDialogFragment.java | 5 ++- .../ui/dialog/DeleteKeyDialogFragment.java | 5 ++- .../keychain/ui/dialog/FileDialogFragment.java | 4 +-- .../ui/dialog/PassphraseDialogFragment.java | 4 +-- .../ui/dialog/SetPassphraseDialogFragment.java | 4 +-- .../keychain/ui/dialog/ShareNfcDialogFragment.java | 5 ++- .../ui/dialog/ShareQrCodeDialogFragment.java | 5 ++- 12 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 4c747d0d9..bd3a98567 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -59,6 +59,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; +import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.widget.Editor; @@ -504,7 +505,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener int curID = 0; for (String userID : userIDs) { if (userID.equals("") && (!userID.equals(originalIDs.get(curID)) || newIDs.get(curID))) { - AlertDialog.Builder alert = new AlertDialog.Builder( + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder( EditKeyActivity.this); alert.setIcon(R.drawable.ic_dialog_alert_holo_light); @@ -527,7 +528,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener } ); alert.setCancelable(false); - alert.create().show(); + alert.show(); return; } curID++; @@ -617,7 +618,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener private void cancelClicked() { if (needsSaving()) { //ask if we want to save - AlertDialog.Builder alert = new AlertDialog.Builder( + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder( EditKeyActivity.this); alert.setIcon(R.drawable.ic_dialog_alert_holo_light); @@ -640,7 +641,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener } }); alert.setCancelable(false); - alert.create().show(); + alert.show(); } else { setResult(RESULT_CANCELED); finish(); 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 bb5d2e922..35076287b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -38,7 +38,6 @@ import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; -import com.beardedhen.androidbootstrap.BootstrapButton; import com.devspark.appmsg.AppMsg; import org.sufficientlysecure.keychain.Constants; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java index 35e464423..19cf27259 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java @@ -17,7 +17,6 @@ package org.sufficientlysecure.keychain.ui.dialog; -import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; @@ -50,7 +49,7 @@ public class BadImportKeyDialogFragment extends DialogFragment { final FragmentActivity activity = getActivity(); final int badImport = getArguments().getInt(ARG_BAD_IMPORT); - AlertDialog.Builder alert = new AlertDialog.Builder(activity); + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); alert.setIcon(R.drawable.ic_dialog_alert_holo_light); alert.setTitle(R.string.warning); alert.setMessage(activity.getResources() @@ -63,6 +62,6 @@ public class BadImportKeyDialogFragment extends DialogFragment { }); alert.setCancelable(true); - return alert.create(); + return alert.show(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java index c71bc160a..6c012cb94 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java @@ -83,7 +83,7 @@ public class CreateKeyDialogFragment extends DialogFragment { final int childCount = getArguments().getInt(ARG_EDITOR_CHILD_COUNT); mInflater = context.getLayoutInflater(); - AlertDialog.Builder dialog = new AlertDialog.Builder(context); + CustomAlertDialogBuilder dialog = new CustomAlertDialogBuilder(context); View view = mInflater.inflate(R.layout.create_key_dialog, null); dialog.setView(view); @@ -146,7 +146,7 @@ public class CreateKeyDialogFragment extends DialogFragment { } }); - final AlertDialog alertDialog = dialog.create(); + final AlertDialog alertDialog = dialog.show(); mCustomKeyEditText.addTextChangedListener(new TextWatcher() { @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java new file mode 100644 index 000000000..4b40b7ef1 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java @@ -0,0 +1,40 @@ +package org.sufficientlysecure.keychain.ui.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.view.View; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.R; + +/** This class extends AlertDiaog.Builder, styling the header using emphasis color. + * Note that this class is a huge hack, because dialog boxes aren't easily stylable. + * Also, the dialog NEEDS to be called with show() directly, not create(), otherwise + * the order of internal operations will lead to a crash! + */ +public class CustomAlertDialogBuilder extends AlertDialog.Builder { + + public CustomAlertDialogBuilder(Activity activity) { + super(activity); + } + + @Override + public AlertDialog show() { + AlertDialog dialog = super.show(); + + int dividerId = dialog.getContext().getResources().getIdentifier("android:id/titleDivider", null, null); + View divider = dialog.findViewById(dividerId); + if (divider != null) { + divider.setBackgroundColor(dialog.getContext().getResources().getColor(R.color.emphasis)); + } + + int textViewId = dialog.getContext().getResources().getIdentifier("android:id/alertTitle", null, null); + TextView tv = (TextView) dialog.findViewById(textViewId); + if (tv != null) { + tv.setTextColor(dialog.getContext().getResources().getColor(R.color.emphasis)); + } + + return dialog; + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java index 37dec70cd..b42a79993 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java @@ -17,7 +17,6 @@ package org.sufficientlysecure.keychain.ui.dialog; -import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.DialogInterface; @@ -59,7 +58,7 @@ public class DeleteFileDialogFragment extends DialogFragment { final String deleteFile = getArguments().getString(ARG_DELETE_FILE); - AlertDialog.Builder alert = new AlertDialog.Builder(activity); + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); alert.setIcon(R.drawable.ic_dialog_alert_holo_light); @@ -120,6 +119,6 @@ public class DeleteFileDialogFragment extends DialogFragment { }); alert.setCancelable(true); - return alert.create(); + return alert.show(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java index 93cdef5e3..01d2fae6a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java @@ -17,7 +17,6 @@ package org.sufficientlysecure.keychain.ui.dialog; -import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; @@ -73,7 +72,7 @@ public class DeleteKeyDialogFragment extends DialogFragment { final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS); - AlertDialog.Builder builder = new AlertDialog.Builder(activity); + CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(activity); // Setup custom View to display in AlertDialog LayoutInflater inflater = activity.getLayoutInflater(); @@ -144,7 +143,7 @@ public class DeleteKeyDialogFragment extends DialogFragment { } }); - return builder.create(); + return builder.show(); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java index 6a5baf658..24f93bed7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java @@ -97,7 +97,7 @@ public class FileDialogFragment extends DialogFragment { LayoutInflater inflater = (LayoutInflater) activity .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - AlertDialog.Builder alert = new AlertDialog.Builder(activity); + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); alert.setTitle(title); View view = inflater.inflate(R.layout.file_dialog, null); @@ -157,7 +157,7 @@ public class FileDialogFragment extends DialogFragment { dismiss(); } }); - return alert.create(); + return alert.show(); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java index 3cb1ce7b4..12fd77141 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java @@ -135,7 +135,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor final long secretKeyId = getArguments().getLong(ARG_SECRET_KEY_ID); mMessenger = getArguments().getParcelable(ARG_MESSENGER); - AlertDialog.Builder alert = new AlertDialog.Builder(activity); + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); alert.setTitle(R.string.title_authentication); @@ -262,7 +262,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor }); mCanKB = true; - return alert.create(); + return alert.show(); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java index e5db22a04..04bec3282 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java @@ -81,7 +81,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi int title = getArguments().getInt(ARG_TITLE); mMessenger = getArguments().getParcelable(ARG_MESSENGER); - AlertDialog.Builder alert = new AlertDialog.Builder(activity); + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); alert.setTitle(title); alert.setMessage(R.string.enter_passphrase_twice); @@ -135,7 +135,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi } }); - return alert.create(); + return alert.show(); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java index cd2364d7c..961f92f03 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java @@ -18,7 +18,6 @@ package org.sufficientlysecure.keychain.ui.dialog; import android.annotation.TargetApi; -import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; @@ -51,7 +50,7 @@ public class ShareNfcDialogFragment extends DialogFragment { public Dialog onCreateDialog(Bundle savedInstanceState) { final FragmentActivity activity = getActivity(); - AlertDialog.Builder alert = new AlertDialog.Builder(activity); + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); alert.setTitle(R.string.share_nfc_dialog); alert.setCancelable(true); @@ -93,6 +92,6 @@ public class ShareNfcDialogFragment extends DialogFragment { } } - return alert.create(); + return alert.show(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java index 1b998ec8d..24608784b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java @@ -18,7 +18,6 @@ package org.sufficientlysecure.keychain.ui.dialog; import android.app.Activity; -import android.app.AlertDialog; import android.app.Dialog; import android.net.Uri; import android.os.Bundle; @@ -68,7 +67,7 @@ public class ShareQrCodeDialogFragment extends DialogFragment { Uri dataUri = getArguments().getParcelable(ARG_KEY_URI); - AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(getActivity()); alert.setTitle(R.string.share_qr_code_dialog_title); LayoutInflater inflater = activity.getLayoutInflater(); @@ -102,7 +101,7 @@ public class ShareQrCodeDialogFragment extends DialogFragment { return null; } - return alert.create(); + return alert.show(); } private void setQrCode(String data) { -- cgit v1.2.3 From c0b48a616e8e5a1d66921e9d9ef1e8db2b0498f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ha=C3=9F?= Date: Sun, 11 May 2014 20:28:16 +0200 Subject: Fixed wrong AppMsg-Style --- .../org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java index ddc326acf..daa48b526 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java @@ -108,11 +108,11 @@ public class DecryptMessageFragment extends DecryptFragment { mCiphertext = matcher.group(1); decryptStart(null); } else { - AppMsg.makeText(getActivity(), R.string.error_invalid_data, AppMsg.STYLE_INFO) + AppMsg.makeText(getActivity(), R.string.error_invalid_data, AppMsg.STYLE_ALERT) .show(); } } else { - AppMsg.makeText(getActivity(), R.string.error_invalid_data, AppMsg.STYLE_INFO) + AppMsg.makeText(getActivity(), R.string.error_invalid_data, AppMsg.STYLE_ALERT) .show(); } } -- cgit v1.2.3 From 010dcf1887d5f1246505f7ebe9129ac4ee237e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ha=C3=9F?= Date: Sun, 11 May 2014 22:15:45 +0200 Subject: Toast replacement --- .../keychain/service/KeychainIntentServiceHandler.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java index 8f0a3ab8d..d0c17416d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java @@ -26,6 +26,8 @@ import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.widget.Toast; +import com.devspark.appmsg.AppMsg; + import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; @@ -99,9 +101,9 @@ public class KeychainIntentServiceHandler extends Handler { // show error from service if (data.containsKey(DATA_ERROR)) { - Toast.makeText(mActivity, + AppMsg.makeText(mActivity, mActivity.getString(R.string.error_message, data.getString(DATA_ERROR)), - Toast.LENGTH_SHORT).show(); + AppMsg.STYLE_ALERT).show(); } break; -- cgit v1.2.3 From 4ed8e457033406e90c5cee4ff6ec206d84ddf5db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ha=C3=9F?= Date: Sun, 11 May 2014 22:20:44 +0200 Subject: Removed unused Toast import --- .../keychain/service/KeychainIntentServiceHandler.java | 1 - 1 file changed, 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java index d0c17416d..d5d02081a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java @@ -24,7 +24,6 @@ import android.os.Handler; import android.os.Message; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; -import android.widget.Toast; import com.devspark.appmsg.AppMsg; -- cgit v1.2.3