From face67d64b06f14913fff9ce61ae4a23421cec28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 13 Jan 2014 00:39:51 +0100 Subject: [PATCH] key view is working --- .../res/layout/select_key_item.xml | 20 +- .../res/layout/share_qr_code_dialog.xml | 16 - .../res/layout/view_key_activity.xml | 341 +++++++++++------- .../res/layout/view_key_userids_item.xml | 1 - OpenPGP-Keychain/res/values/strings.xml | 2 + .../keychain/helper/OtherHelper.java | 19 - .../keychain/pgp/PgpKeyHelper.java | 30 ++ .../keychain/provider/KeychainContract.java | 20 +- .../keychain/ui/KeyListSecretFragment.java | 9 +- .../keychain/ui/ViewKeyActivity.java | 183 ++++++++-- .../ui/adapter/KeyListAdapterOLD.java | 279 -------------- .../ui/adapter/KeyListPublicAdapter.java | 6 +- .../ui/adapter/KeyListSecretAdapter.java | 4 +- .../ui/adapter/SelectKeyCursorAdapter.java | 5 +- .../ui/adapter/ViewKeyKeysAdapter.java | 90 +++++ .../ui/adapter/ViewKeyUserIdsAdapter.java | 36 +- .../keychain/ui/widget/FixedListView.java | 55 +++ 17 files changed, 576 insertions(+), 540 deletions(-) delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapterOLD.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/FixedListView.java diff --git a/OpenPGP-Keychain/res/layout/select_key_item.xml b/OpenPGP-Keychain/res/layout/select_key_item.xml index d5b1655ed..bbfe17c44 100644 --- a/OpenPGP-Keychain/res/layout/select_key_item.xml +++ b/OpenPGP-Keychain/res/layout/select_key_item.xml @@ -1,22 +1,6 @@ - - diff --git a/OpenPGP-Keychain/res/layout/share_qr_code_dialog.xml b/OpenPGP-Keychain/res/layout/share_qr_code_dialog.xml index 88b06b698..66102d3e5 100644 --- a/OpenPGP-Keychain/res/layout/share_qr_code_dialog.xml +++ b/OpenPGP-Keychain/res/layout/share_qr_code_dialog.xml @@ -1,20 +1,4 @@ - - + android:layout_width="match_parent" + android:layout_height="match_parent" > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_height="wrap_content" + android:layout_marginRight="?android:attr/scrollbarSize" + android:orientation="vertical" + android:paddingLeft="16dp" + android:paddingRight="16dp" > - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenPGP-Keychain/res/layout/view_key_userids_item.xml b/OpenPGP-Keychain/res/layout/view_key_userids_item.xml index cbc85189f..2d022ba13 100644 --- a/OpenPGP-Keychain/res/layout/view_key_userids_item.xml +++ b/OpenPGP-Keychain/res/layout/view_key_userids_item.xml @@ -4,7 +4,6 @@ android:layout_height="?android:attr/listPreferredItemHeight" android:layout_marginRight="?android:attr/scrollbarSize" android:orientation="vertical" - android:paddingLeft="36dip" android:singleLine="true" > Defaults Advanced Master Key + Master User ID Actions @@ -137,6 +138,7 @@ Comment Email Send Key to Server? + Fingerprint Select 1 Selected Selected diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/OtherHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/OtherHelper.java index 8fa2df1f5..9f3cd8e88 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/OtherHelper.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/OtherHelper.java @@ -79,23 +79,4 @@ public class OtherHelper { } } - /** - * Splits userId string into naming part and email part - * - * @param userId - * @return array with naming (0) and email (1) - */ - public static String[] splitUserId(String userId) { - String[] output = new String[2]; - - String chunks[] = userId.split(" <", 2); - userId = chunks[0]; - if (chunks.length > 1) { - output[1] = "<" + chunks[1]; - } - output[0] = userId; - - return output; - } - } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index daba94b99..edb30496a 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -22,6 +22,8 @@ import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPPublicKey; @@ -524,4 +526,32 @@ public class PgpKeyHelper { return (Long.parseLong(s1, 16) << 32) | Long.parseLong(s2, 16); } + /** + * Splits userId string into naming part, email part, and comment part + * + * @param userId + * @return array with naming (0), email (1), comment (2) + */ + public static String[] splitUserId(String userId) { + String[] result = new String[] { "", "", "" }; + + Pattern withComment = Pattern.compile("^(.*) \\((.*)\\) <(.*)>$"); + Matcher matcher = withComment.matcher(userId); + if (matcher.matches()) { + result[0] = matcher.group(1); + result[1] = matcher.group(3); + result[2] = matcher.group(2); + return result; + } + + Pattern withoutComment = Pattern.compile("^(.*) <(.*)>$"); + matcher = withoutComment.matcher(userId); + if (matcher.matches()) { + result[0] = matcher.group(1); + result[1] = matcher.group(2); + return result; + } + return result; + } + } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java index 82bb473f6..d2381f6f0 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -69,8 +69,8 @@ public class KeychainContract { public static final String CONTENT_AUTHORITY = Constants.PACKAGE_NAME + ".provider"; - private static final Uri BASE_CONTENT_URI_INTERNAL = Uri.parse("content://" - + CONTENT_AUTHORITY); + private static final Uri BASE_CONTENT_URI_INTERNAL = Uri + .parse("content://" + CONTENT_AUTHORITY); public static final String BASE_KEY_RINGS = "key_rings"; public static final String BASE_DATA = "data"; @@ -185,6 +185,14 @@ public class KeychainContract { return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).appendPath(keyRingRowId) .appendPath(PATH_KEYS).appendPath(keyRowId).build(); } + + public static Uri buildKeysUri(Uri keyRingUri) { + return keyRingUri.buildUpon().appendPath(PATH_KEYS).build(); + } + + public static Uri buildKeysUri(Uri keyRingUri, String keyRowId) { + return keyRingUri.buildUpon().appendPath(PATH_KEYS).appendPath(keyRowId).build(); + } } public static class UserIds implements UserIdsColumns, BaseColumns { @@ -216,6 +224,14 @@ public class KeychainContract { return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).appendPath(keyRingRowId) .appendPath(PATH_USER_IDS).appendPath(userIdRowId).build(); } + + public static Uri buildUserIdsUri(Uri keyRingUri) { + return keyRingUri.buildUpon().appendPath(PATH_USER_IDS).build(); + } + + public static Uri buildUserIdsUri(Uri keyRingUri, String userIdRowId) { + return keyRingUri.buildUpon().appendPath(PATH_USER_IDS).appendPath(userIdRowId).build(); + } } public static class ApiApps implements ApiAppsColumns, BaseColumns { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java index c0b67719e..0e2d22e1e 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java @@ -51,7 +51,6 @@ public class KeyListSecretFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks, OnItemClickListener { private KeyListSecretActivity mKeyListSecretActivity; - private KeyListSecretAdapter mAdapter; /** @@ -146,7 +145,7 @@ public class KeyListSecretFragment extends SherlockListFragment implements setListShown(false); // Create an empty adapter we will use to display the loaded data. - mAdapter = new KeyListSecretAdapter(mKeyListSecretActivity, null, Id.type.secret_key); + mAdapter = new KeyListSecretAdapter(mKeyListSecretActivity, null, 0); setListAdapter(mAdapter); // Prepare the loader. Either re-connect with an existing one, @@ -157,8 +156,7 @@ public class KeyListSecretFragment extends SherlockListFragment implements // These are the rows that we will retrieve. static final String[] PROJECTION = new String[] { KeyRings._ID, KeyRings.MASTER_KEY_ID, UserIds.USER_ID }; - - static final String SORT_ORDER = UserIds.USER_ID + " ASC"; + static final String SORT_ORDER = UserIds.USER_ID + " COLLATE LOCALIZED ASC"; public Loader onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This @@ -169,8 +167,7 @@ public class KeyListSecretFragment extends SherlockListFragment implements // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, PROJECTION, null, null, UserIds.USER_ID - + " COLLATE LOCALIZED ASC"); + return new CursorLoader(getActivity(), baseUri, PROJECTION, null, null, SORT_ORDER); } public void onLoadFinished(Loader loader, Cursor data) { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 5bc30ccc5..e2f90e87c 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Dominik Schürmann + * Copyright (C) 2013-2014 Dominik Schürmann * Copyright (C) 2013 Bahtiar 'kalkin' Gadimov * * This program is free software: you can redistribute it and/or modify @@ -20,8 +20,6 @@ package org.sufficientlysecure.keychain.ui; import java.util.ArrayList; import java.util.Date; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyRing; @@ -31,7 +29,12 @@ 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.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.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment; @@ -39,6 +42,7 @@ import org.sufficientlysecure.keychain.util.Log; import android.annotation.SuppressLint; import android.content.Intent; +import android.database.Cursor; import android.net.Uri; import android.nfc.NdefMessage; import android.nfc.NdefRecord; @@ -50,6 +54,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.text.format.DateFormat; import android.view.View; import android.view.View.OnClickListener; @@ -64,7 +71,7 @@ import com.beardedhen.androidbootstrap.BootstrapButton; @SuppressLint("NewApi") public class ViewKeyActivity extends SherlockFragmentActivity implements CreateNdefMessageCallback, - OnNdefPushCompleteCallback { + OnNdefPushCompleteCallback, LoaderManager.LoaderCallbacks { ExportHelper mExportHelper; @@ -72,10 +79,14 @@ public class ViewKeyActivity extends SherlockFragmentActivity implements CreateN private PGPPublicKey mPublicKey; + private TextView mName; + private TextView mEmail; + private TextView mComment; private TextView mAlgorithm; - private TextView mFingerint; + private TextView mKeyId; private TextView mExpiry; private TextView mCreation; + private TextView mFingerprint; private BootstrapButton mActionEncrypt; private ListView mUserIds; @@ -86,6 +97,12 @@ public class ViewKeyActivity extends SherlockFragmentActivity implements CreateN private byte[] mSharedKeyringBytes; private static final int NFC_SENT = 1; + private static final int LOADER_ID_KEYRING = 0; + private static final int LOADER_ID_USER_IDS = 1; + private static final int LOADER_ID_KEYS = 2; + private ViewKeyUserIdsAdapter mUserIdsAdapter; + private ViewKeyKeysAdapter mKeysAdapter; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -93,14 +110,19 @@ public class ViewKeyActivity extends SherlockFragmentActivity implements CreateN mExportHelper = new ExportHelper(this); getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setIcon(android.R.color.transparent); getSupportActionBar().setHomeButtonEnabled(true); setContentView(R.layout.view_key_activity); - mFingerint = (TextView) findViewById(R.id.fingerprint); - mExpiry = (TextView) findViewById(R.id.expiry); - mCreation = (TextView) findViewById(R.id.creation); + mName = (TextView) findViewById(R.id.name); + mEmail = (TextView) findViewById(R.id.email); + mComment = (TextView) findViewById(R.id.comment); + mKeyId = (TextView) findViewById(R.id.key_id); mAlgorithm = (TextView) findViewById(R.id.algorithm); + mCreation = (TextView) findViewById(R.id.creation); + mExpiry = (TextView) findViewById(R.id.expiry); + mFingerprint = (TextView) findViewById(R.id.fingerprint); mActionEncrypt = (BootstrapButton) findViewById(R.id.action_encrypt); mUserIds = (ListView) findViewById(R.id.user_ids); mKeys = (ListView) findViewById(R.id.keys); @@ -128,6 +150,11 @@ public class ViewKeyActivity extends SherlockFragmentActivity implements CreateN @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { + case android.R.id.home: + Intent homeIntent = new Intent(this, KeyListPublicActivity.class); + homeIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(homeIntent); + return true; case R.id.menu_key_view_update: updateFromKeyserver(mDataUri); return true; @@ -173,16 +200,23 @@ public class ViewKeyActivity extends SherlockFragmentActivity implements CreateN } private void loadData(Uri dataUri) { + // TODO: don't use pubkey object, use database!!! + PGPPublicKeyRing ring = (PGPPublicKeyRing) ProviderHelper.getPGPKeyRing(this, dataUri); mPublicKey = ring.getPublicKey(); - mFingerint.setText(PgpKeyHelper.shortifyFingerprint(PgpKeyHelper + mKeyId.setText(PgpKeyHelper.shortifyFingerprint(PgpKeyHelper .convertFingerprintToHex(mPublicKey.getFingerprint()))); - String[] mainUserId = splitUserId(""); + + String fingerprint = PgpKeyHelper.convertFingerprintToHex(mPublicKey.getFingerprint()); + fingerprint = fingerprint.replace(" ", "\n"); + mFingerprint.setText(fingerprint); + + // TODO: get image with getUserAttributes() on key and then PGPUserAttributeSubpacketVector Date expiryDate = PgpKeyHelper.getExpiryDate(mPublicKey); if (expiryDate == null) { - mExpiry.setText(""); + mExpiry.setText(R.string.none); } else { mExpiry.setText(DateFormat.getDateFormat(getApplicationContext()).format(expiryDate)); } @@ -203,32 +237,117 @@ public class ViewKeyActivity extends SherlockFragmentActivity implements CreateN startActivityForResult(intent, 0); } }); + + mUserIdsAdapter = new ViewKeyUserIdsAdapter(this, null, 0); + + mUserIds.setAdapter(mUserIdsAdapter); + // mUserIds.setEmptyView(findViewById(android.R.id.empty)); + // mUserIds.setClickable(true); + // mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() { + // @Override + // public void onItemClick(AdapterView arg0, View arg1, int position, long id) { + // } + // }); + + mKeysAdapter = new ViewKeyKeysAdapter(this, null, 0); + + mKeys.setAdapter(mKeysAdapter); + + // Prepare the loader. Either re-connect with an existing one, + // or start a new one. + getSupportLoaderManager().initLoader(LOADER_ID_KEYRING, null, this); + getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); + getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this); + } + + static final String[] KEYRING_PROJECTION = new String[] { KeyRings._ID, KeyRings.MASTER_KEY_ID, + UserIds.USER_ID }; + + static final String[] USER_IDS_PROJECTION = new String[] { UserIds._ID, UserIds.USER_ID, + UserIds.RANK, }; + // not the main user id + static final String USER_IDS_SELECTION = UserIds.RANK + " > 0 "; + static final String USER_IDS_SORT_ORDER = UserIds.USER_ID + " COLLATE LOCALIZED ASC"; + + static final String[] KEYS_PROJECTION = new String[] { Keys._ID, Keys.KEY_ID, + Keys.IS_MASTER_KEY, Keys.ALGORITHM, Keys.KEY_SIZE, Keys.CAN_CERTIFY, Keys.CAN_SIGN, + Keys.CAN_ENCRYPT, }; + static final String KEYS_SORT_ORDER = Keys.RANK + " ASC"; + + public Loader onCreateLoader(int id, Bundle args) { + switch (id) { + case LOADER_ID_KEYRING: { + Uri baseUri = mDataUri; + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + return new CursorLoader(this, baseUri, KEYRING_PROJECTION, null, null, null); + } + case LOADER_ID_USER_IDS: { + Uri baseUri = UserIds.buildUserIdsUri(mDataUri); + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + return new CursorLoader(this, baseUri, USER_IDS_PROJECTION, USER_IDS_SELECTION, null, + USER_IDS_SORT_ORDER); + } + case LOADER_ID_KEYS: { + Uri baseUri = Keys.buildKeysUri(mDataUri); + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + return new CursorLoader(this, baseUri, KEYS_PROJECTION, null, null, KEYS_SORT_ORDER); + } + + default: + return null; + } + } + + public void onLoadFinished(Loader loader, Cursor data) { + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + switch (loader.getId()) { + case LOADER_ID_KEYRING: + if (data.moveToFirst()) { + String[] mainUserId = PgpKeyHelper.splitUserId(data.getString(2)); + setTitle(mainUserId[0]); + mName.setText(mainUserId[0]); + mEmail.setText(mainUserId[1]); + mComment.setText(mainUserId[2]); + } + + break; + case LOADER_ID_USER_IDS: + mUserIdsAdapter.swapCursor(data); + break; + case LOADER_ID_KEYS: + mKeysAdapter.swapCursor(data); + break; + + default: + break; + } } /** - * TODO: does this duplicate functionality from elsewhere? put in helper! + * 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. */ - private String[] splitUserId(String userId) { - String[] result = new String[] { "", "", "" }; - Log.v("UserID", userId); - - Pattern withComment = Pattern.compile("^(.*) [(](.*)[)] <(.*)>$"); - Matcher matcher = withComment.matcher(userId); - if (matcher.matches()) { - result[0] = matcher.group(1); - result[1] = matcher.group(2); - result[2] = matcher.group(3); - return result; + public void onLoaderReset(Loader loader) { + switch (loader.getId()) { + case LOADER_ID_KEYRING: + // TODO? + break; + case LOADER_ID_USER_IDS: + mUserIdsAdapter.swapCursor(null); + break; + case LOADER_ID_KEYS: + mKeysAdapter.swapCursor(null); + break; + default: + break; } - - Pattern withoutComment = Pattern.compile("^(.*) <(.*)>$"); - matcher = withoutComment.matcher(userId); - if (matcher.matches()) { - result[0] = matcher.group(1); - result[1] = matcher.group(2); - return result; - } - return result; } private void uploadToKeyserver(Uri dataUri) { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapterOLD.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapterOLD.java deleted file mode 100644 index 8f745bdd3..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapterOLD.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann - * - * 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.adapter; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.OtherHelper; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.util.Log; - -import android.content.Context; -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.database.MergeCursor; -import android.net.Uri; -import android.provider.BaseColumns; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CursorTreeAdapter; -import android.widget.ImageView; -import android.widget.TextView; - -public class KeyListAdapterOLD extends CursorTreeAdapter { - private Context mContext; - private LayoutInflater mInflater; - - protected int mKeyType; - - private static final int CHILD_KEY = 0; - private static final int CHILD_USER_ID = 1; - private static final int CHILD_FINGERPRINT = 2; - - public KeyListAdapterOLD(Context context, Cursor groupCursor, int keyType) { - super(groupCursor, context); - mContext = context; - mInflater = LayoutInflater.from(context); - mKeyType = keyType; - } - - /** - * Inflate new view for group items - */ - @Override - public View newGroupView(Context context, Cursor cursor, boolean isExpanded, ViewGroup parent) { - return mInflater.inflate(R.layout.key_list_item, null); - } - - /** - * Binds TextViews from group view to results from database group cursor. - */ - @Override - protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) { - int userIdIndex = cursor.getColumnIndex(UserIds.USER_ID); - - TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); - mainUserId.setText(R.string.unknown_user_id); - TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - mainUserIdRest.setText(""); - - String userId = cursor.getString(userIdIndex); - if (userId != null) { - String[] userIdSplit = OtherHelper.splitUserId(userId); - - if (userIdSplit[1] != null) { - mainUserIdRest.setText(userIdSplit[1]); - } - mainUserId.setText(userIdSplit[0]); - } - - if (mainUserId.getText().length() == 0) { - mainUserId.setText(R.string.unknown_user_id); - } - - if (mainUserIdRest.getText().length() == 0) { - mainUserIdRest.setVisibility(View.GONE); - } else { - mainUserIdRest.setVisibility(View.VISIBLE); - } - } - -// /** -// * Inflate new view for child items -// */ -// @Override -// public View newChildView(Context context, Cursor cursor, boolean isLastChild, ViewGroup parent) { -// return mInflater.inflate(R.layout.key_list_child_item, null); -// } - - /** - * Bind TextViews from view of childs based on query results - */ - @Override - protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) { -// LinearLayout keyLayout = (LinearLayout) view.findViewById(R.id.keyLayout); -// LinearLayout userIdLayout = (LinearLayout) view.findViewById(R.id.userIdLayout); - - // first entry is fingerprint - if (cursor.getPosition() == 0) { - // show only userId layout -// keyLayout.setVisibility(View.GONE); -// userIdLayout.setVisibility(View.VISIBLE); - - String fingerprint = PgpKeyHelper.getFingerPrint(context, - cursor.getLong(cursor.getColumnIndex(Keys.KEY_ID))); - fingerprint = fingerprint.replace(" ", "\n"); - - TextView userId = (TextView) view.findViewById(R.id.userId); - if (userId == null) { - Log.d(Constants.TAG, "userId is null!"); - } - userId.setText(context.getString(R.string.fingerprint) + "\n" + fingerprint); - } else { - // differentiate between keys and userIds in MergeCursor - if (cursor.getColumnIndex(Keys.KEY_ID) != -1) { -// keyLayout.setVisibility(View.VISIBLE); -// userIdLayout.setVisibility(View.GONE); - - String keyIdStr = PgpKeyHelper.convertKeyIdToHex(cursor.getLong(cursor - .getColumnIndex(Keys.KEY_ID))); - String algorithmStr = PgpKeyHelper.getAlgorithmInfo( - cursor.getInt(cursor.getColumnIndex(Keys.ALGORITHM)), - cursor.getInt(cursor.getColumnIndex(Keys.KEY_SIZE))); - - TextView keyId = (TextView) view.findViewById(R.id.keyId); - keyId.setText(keyIdStr); - - TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails); - keyDetails.setText("(" + algorithmStr + ")"); - - ImageView masterKeyIcon = (ImageView) view.findViewById(R.id.ic_masterKey); - if (cursor.getInt(cursor.getColumnIndex(Keys.IS_MASTER_KEY)) != 1) { - masterKeyIcon.setVisibility(View.INVISIBLE); - } else { - masterKeyIcon.setVisibility(View.VISIBLE); - } - - ImageView certifyIcon = (ImageView) view.findViewById(R.id.ic_certifyKey); - if (cursor.getInt(cursor.getColumnIndex(Keys.CAN_CERTIFY)) != 1) { - certifyIcon.setVisibility(View.GONE); - } else { - certifyIcon.setVisibility(View.VISIBLE); - } - - ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey); - if (cursor.getInt(cursor.getColumnIndex(Keys.CAN_ENCRYPT)) != 1) { - encryptIcon.setVisibility(View.GONE); - } else { - encryptIcon.setVisibility(View.VISIBLE); - } - - ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey); - if (cursor.getInt(cursor.getColumnIndex(Keys.CAN_SIGN)) != 1) { - signIcon.setVisibility(View.GONE); - } else { - signIcon.setVisibility(View.VISIBLE); - } - } else { -// keyLayout.setVisibility(View.GONE); -// userIdLayout.setVisibility(View.VISIBLE); - - String userIdStr = cursor.getString(cursor.getColumnIndex(UserIds.USER_ID)); - - TextView userId = (TextView) view.findViewById(R.id.userId); - userId.setText(userIdStr); - } - } - } - - /** - * Given the group cursor, we start cursors for a fingerprint, keys, and userIds, which are - * merged together and build the child cursor - */ - @Override - protected Cursor getChildrenCursor(Cursor groupCursor) { - final long keyRingRowId = groupCursor.getLong(groupCursor.getColumnIndex(BaseColumns._ID)); - - Cursor fingerprintCursor = getChildCursor(keyRingRowId, CHILD_FINGERPRINT); - Cursor keyCursor = getChildCursor(keyRingRowId, CHILD_KEY); - Cursor userIdCursor = getChildCursor(keyRingRowId, CHILD_USER_ID); - - MergeCursor mergeCursor = new MergeCursor(new Cursor[] { fingerprintCursor, keyCursor, - userIdCursor }); - Log.d(Constants.TAG, "mergeCursor:" + DatabaseUtils.dumpCursorToString(mergeCursor)); - - return mergeCursor; - } - - /** - * This builds a cursor for a specific type of children - * - * @param keyRingRowId - * foreign row id of the keyRing - * @param type - * @return - */ - private Cursor getChildCursor(long keyRingRowId, int type) { - Uri uri = null; - String[] projection = null; - String sortOrder = null; - String selection = null; - - switch (type) { - case CHILD_FINGERPRINT: - projection = new String[] { Keys._ID, Keys.KEY_ID, Keys.IS_MASTER_KEY, Keys.ALGORITHM, - Keys.KEY_SIZE, Keys.CAN_CERTIFY, Keys.CAN_SIGN, Keys.CAN_ENCRYPT, }; - sortOrder = Keys.RANK + " ASC"; - - // use only master key for fingerprint - selection = Keys.IS_MASTER_KEY + " = 1 "; - - if (mKeyType == Id.type.public_key) { - uri = Keys.buildPublicKeysUri(String.valueOf(keyRingRowId)); - } else { - uri = Keys.buildSecretKeysUri(String.valueOf(keyRingRowId)); - } - break; - - case CHILD_KEY: - projection = new String[] { Keys._ID, Keys.KEY_ID, Keys.IS_MASTER_KEY, Keys.ALGORITHM, - Keys.KEY_SIZE, Keys.CAN_CERTIFY, Keys.CAN_SIGN, Keys.CAN_ENCRYPT, }; - sortOrder = Keys.RANK + " ASC"; - - if (mKeyType == Id.type.public_key) { - uri = Keys.buildPublicKeysUri(String.valueOf(keyRingRowId)); - } else { - uri = Keys.buildSecretKeysUri(String.valueOf(keyRingRowId)); - } - - break; - - case CHILD_USER_ID: - projection = new String[] { UserIds._ID, UserIds.USER_ID, UserIds.RANK, }; - sortOrder = UserIds.RANK + " ASC"; - - // not the main user id - selection = UserIds.RANK + " > 0 "; - - if (mKeyType == Id.type.public_key) { - uri = UserIds.buildPublicUserIdsUri(String.valueOf(keyRingRowId)); - } else { - uri = UserIds.buildSecretUserIdsUri(String.valueOf(keyRingRowId)); - } - - break; - - default: - return null; - - } - - return mContext.getContentResolver().query(uri, projection, selection, null, sortOrder); - } - - @Override - protected View newChildView(Context context, Cursor cursor, boolean isLastChild, - ViewGroup parent) { - // TODO Auto-generated method stub - return null; - } - -} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java index 140781b4f..f1e58a5d3 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java @@ -19,11 +19,13 @@ package org.sufficientlysecure.keychain.ui.adapter; import java.util.HashMap; import java.util.Set; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.OtherHelper; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.util.Log; + import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; import android.annotation.SuppressLint; import android.content.Context; @@ -69,7 +71,7 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea String userId = cursor.getString(userIdIndex); if (userId != null) { - String[] userIdSplit = OtherHelper.splitUserId(userId); + String[] userIdSplit = PgpKeyHelper.splitUserId(userId); if (userIdSplit[1] != null) { mainUserIdRest.setText(userIdSplit[1]); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java index f78eaf627..d06c0287c 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java @@ -21,7 +21,7 @@ import java.util.HashMap; import java.util.Set; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.OtherHelper; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import android.annotation.SuppressLint; @@ -57,7 +57,7 @@ public class KeyListSecretAdapter extends CursorAdapter { String userId = cursor.getString(userIdIndex); if (userId != null) { - String[] userIdSplit = OtherHelper.splitUserId(userId); + String[] userIdSplit = PgpKeyHelper.splitUserId(userId); if (userIdSplit[1] != null) { mainUserIdRest.setText(userIdSplit[1]); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java index ebb7261be..c6eca0296 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java @@ -18,11 +18,10 @@ package org.sufficientlysecure.keychain.ui.adapter; import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.helper.OtherHelper; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.R; import android.content.Context; import android.database.Cursor; @@ -78,7 +77,7 @@ public class SelectKeyCursorAdapter extends CursorAdapter { String userId = cursor.getString(cursor.getColumnIndex(UserIds.USER_ID)); if (userId != null) { - String[] userIdSplit = OtherHelper.splitUserId(userId); + String[] userIdSplit = PgpKeyHelper.splitUserId(userId); if (userIdSplit[1] != null) { mainUserIdRest.setText(userIdSplit[1]); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java new file mode 100644 index 000000000..51286af66 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java @@ -0,0 +1,90 @@ +/* + * 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 org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; + +import android.content.Context; +import android.database.Cursor; +import android.support.v4.widget.CursorAdapter; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +public class ViewKeyKeysAdapter extends CursorAdapter { + private LayoutInflater mInflater; + + public ViewKeyKeysAdapter(Context context, Cursor c, int flags) { + super(context, c, flags); + + mInflater = LayoutInflater.from(context); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + String keyIdStr = PgpKeyHelper.convertKeyIdToHex(cursor.getLong(cursor + .getColumnIndex(Keys.KEY_ID))); + String algorithmStr = PgpKeyHelper.getAlgorithmInfo( + cursor.getInt(cursor.getColumnIndex(Keys.ALGORITHM)), + cursor.getInt(cursor.getColumnIndex(Keys.KEY_SIZE))); + + TextView keyId = (TextView) view.findViewById(R.id.keyId); + keyId.setText(keyIdStr); + + TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails); + keyDetails.setText("(" + algorithmStr + ")"); + + ImageView masterKeyIcon = (ImageView) view.findViewById(R.id.ic_masterKey); + if (cursor.getInt(cursor.getColumnIndex(Keys.IS_MASTER_KEY)) != 1) { + masterKeyIcon.setVisibility(View.INVISIBLE); + } else { + masterKeyIcon.setVisibility(View.VISIBLE); + } + + ImageView certifyIcon = (ImageView) view.findViewById(R.id.ic_certifyKey); + if (cursor.getInt(cursor.getColumnIndex(Keys.CAN_CERTIFY)) != 1) { + certifyIcon.setVisibility(View.GONE); + } else { + certifyIcon.setVisibility(View.VISIBLE); + } + + ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey); + if (cursor.getInt(cursor.getColumnIndex(Keys.CAN_ENCRYPT)) != 1) { + encryptIcon.setVisibility(View.GONE); + } else { + encryptIcon.setVisibility(View.VISIBLE); + } + + ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey); + if (cursor.getInt(cursor.getColumnIndex(Keys.CAN_SIGN)) != 1) { + signIcon.setVisibility(View.GONE); + } else { + signIcon.setVisibility(View.VISIBLE); + } + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mInflater.inflate(R.layout.view_key_keys_item, null); + } + +} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java index 55821b11e..2e2606fd0 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Dominik Schürmann + * 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 @@ -17,17 +17,11 @@ package org.sufficientlysecure.keychain.ui.adapter; -import java.util.HashMap; -import java.util.Set; - import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.OtherHelper; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import android.annotation.SuppressLint; import android.content.Context; import android.database.Cursor; -import android.graphics.Color; import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; import android.view.View; @@ -47,35 +41,15 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter { public void bindView(View view, Context context, Cursor cursor) { int userIdIndex = cursor.getColumnIndex(UserIds.USER_ID); - TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); - mainUserId.setText(R.string.unknown_user_id); - TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - mainUserIdRest.setText(""); + String userIdStr = cursor.getString(userIdIndex); - String userId = cursor.getString(userIdIndex); - if (userId != null) { - String[] userIdSplit = OtherHelper.splitUserId(userId); - - if (userIdSplit[1] != null) { - mainUserIdRest.setText(userIdSplit[1]); - } - mainUserId.setText(userIdSplit[0]); - } - - if (mainUserId.getText().length() == 0) { - mainUserId.setText(R.string.unknown_user_id); - } - - if (mainUserIdRest.getText().length() == 0) { - mainUserIdRest.setVisibility(View.GONE); - } else { - mainUserIdRest.setVisibility(View.VISIBLE); - } + TextView userId = (TextView) view.findViewById(R.id.userId); + userId.setText(userIdStr); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.key_list_item, null); + return mInflater.inflate(R.layout.view_key_userids_item, null); } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/FixedListView.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/FixedListView.java new file mode 100644 index 000000000..277f14b6f --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/FixedListView.java @@ -0,0 +1,55 @@ +package org.sufficientlysecure.keychain.ui.widget; + +/* + * 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 . + */ + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ListView; + +/** + * Automatically calculate height of listview based on contained items. This enables to put this + * ListView into a ScrollView without messing up. + * + * from + * http://stackoverflow.com/questions/2419246/how-do-i-create-a-listview-thats-not-in-a-scrollview- + * or-has-the-scrollview-dis + */ +public class FixedListView extends ListView { + + public FixedListView(Context context) { + super(context); + } + + public FixedListView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public FixedListView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Calculate height of the entire list by providing a very large + // height hint. But do not use the highest 2 bits of this integer; + // those are reserved for the MeasureSpec mode. + int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); + super.onMeasure(widthMeasureSpec, expandSpec); + } + +} \ No newline at end of file