From ed01c37fe18f98c25b7515c459ae446efa8232ca Mon Sep 17 00:00:00 2001 From: Bahtiar `kalkin-` Gadimov Date: Wed, 25 Dec 2013 18:14:38 +0100 Subject: Added shortifyFingerprint() to PGPHelper --- .../src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index e2d89bfab..5a3d332c4 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -40,6 +40,17 @@ import android.content.Context; public class PgpKeyHelper { + /** + * Returns the last 9 chars of a fingerprint + * + * @param fingerprint + * String containing short or long fingerprint + * @return + */ + public static String shortifyFingerprint(String fingerprint) { + return fingerprint.substring(41); + } + public static Date getCreationDate(PGPPublicKey key) { return key.getCreationTime(); } -- cgit v1.2.3 From 208ea19d5d56fe374bbf26e4ab4cce13dc99656b Mon Sep 17 00:00:00 2001 From: Bahtiar `kalkin-` Gadimov Date: Wed, 25 Dec 2013 18:15:30 +0100 Subject: Added first draft of KeyDetailsActivity --- .../keychain/ui/KeyDetailsActivity.java | 90 ++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java new file mode 100644 index 000000000..652b8a89b --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java @@ -0,0 +1,90 @@ +package org.sufficientlysecure.keychain.ui; + +import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.spongycastle.openpgp.PGPPublicKey; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.util.Log; + +import android.os.Bundle; +import android.text.format.DateFormat; +import android.widget.TextView; + +import com.actionbarsherlock.app.SherlockActivity; + +public class KeyDetailsActivity extends SherlockActivity { + + private PGPPublicKey publicKey; + private TextView mAlgorithm; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle extras = getIntent().getExtras(); + setContentView(R.layout.key_view); + if (extras == null) { + return; + } + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeButtonEnabled(true); + + long key = extras.getLong("key"); + + KeyRings.buildPublicKeyRingsByMasterKeyIdUri(key + ""); + String[] projection = new String[]{""}; + + this.publicKey = ProviderHelper.getPGPPublicKeyByKeyId( + getApplicationContext(), key); + + TextView fingerprint = (TextView) this.findViewById(R.id.fingerprint); + fingerprint.setText(PgpKeyHelper.shortifyFingerprint(PgpKeyHelper.getFingerPrint(getApplicationContext(), key))); + String[] mainUserId = splitUserId(""); + + TextView expiry = (TextView) this.findViewById(R.id.expiry); + Date expiryDate = PgpKeyHelper.getExpiryDate(publicKey); + if (expiryDate == null) { + expiry.setText(""); + } else { + expiry.setText(DateFormat.getDateFormat(getApplicationContext()) + .format(expiryDate)); + } + + TextView creation = (TextView) this.findViewById(R.id.creation); + creation.setText(DateFormat.getDateFormat(getApplicationContext()) + .format(PgpKeyHelper.getCreationDate(publicKey))); + mAlgorithm = (TextView) this.findViewById(R.id.algorithm); + mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(publicKey)); + + } + + 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; + } + + 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; + } +} -- cgit v1.2.3 From f265cd4d68a4bb398467da1a8d19b6ca0b125602 Mon Sep 17 00:00:00 2001 From: Bahtiar `kalkin-` Gadimov Date: Wed, 25 Dec 2013 19:33:53 +0100 Subject: Added context menu item KeyDetails to KeyListPublicFragment --- .../keychain/ui/KeyListPublicFragment.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index 0fdcea809..790ec5ccf 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -73,9 +73,10 @@ public class KeyListPublicFragment extends KeyListFragment implements @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); - menu.add(0, Id.menu.update, 1, R.string.menu_update_key); - menu.add(0, Id.menu.signKey, 2, R.string.menu_sign_key); - menu.add(0, Id.menu.exportToServer, 3, R.string.menu_export_key_to_server); + menu.add(0, 23, 1, R.string.title_key_details); // :TODO: Fix magic number + menu.add(0, Id.menu.update, 2, R.string.menu_update_key); + menu.add(0, Id.menu.signKey, 3, R.string.menu_sign_key); + menu.add(0, Id.menu.exportToServer, 4, R.string.menu_export_key_to_server); menu.add(0, Id.menu.share, 6, R.string.menu_share); menu.add(0, Id.menu.share_qr_code, 7, R.string.menu_share_qr_code); menu.add(0, Id.menu.share_nfc, 8, R.string.menu_share_nfc); @@ -112,7 +113,13 @@ public class KeyListPublicFragment extends KeyListFragment implements startActivityForResult(queryIntent, Id.request.look_up_key_id); return true; - + case 23: + + Intent detailsIntent = new Intent(mKeyListActivity, KeyDetailsActivity.class); + detailsIntent.putExtra("key", ProviderHelper.getPublicMasterKeyId(mKeyListActivity, keyRingRowId)); + startActivity(detailsIntent); + return true; + case Id.menu.exportToServer: Intent uploadIntent = new Intent(mKeyListActivity, KeyServerUploadActivity.class); uploadIntent.setAction(KeyServerUploadActivity.ACTION_EXPORT_KEY_TO_SERVER); -- cgit v1.2.3 From 52c55aaabeac7f35b4800e4cbf0ca098d3d6c54e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 31 Dec 2013 01:41:37 +0100 Subject: code styling --- .../keychain/pgp/PgpKeyHelper.java | 20 +-- .../keychain/ui/KeyDetailsActivity.java | 153 ++++++++++++--------- 2 files changed, 95 insertions(+), 78 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index 5a3d332c4..daba94b99 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -40,16 +40,16 @@ import android.content.Context; public class PgpKeyHelper { - /** - * Returns the last 9 chars of a fingerprint - * - * @param fingerprint - * String containing short or long fingerprint - * @return - */ - public static String shortifyFingerprint(String fingerprint) { - return fingerprint.substring(41); - } + /** + * Returns the last 9 chars of a fingerprint + * + * @param fingerprint + * String containing short or long fingerprint + * @return + */ + public static String shortifyFingerprint(String fingerprint) { + return fingerprint.substring(41); + } public static Date getCreationDate(PGPPublicKey key) { return key.getCreationTime(); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java index 652b8a89b..82d66e2c0 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2013 Bahtiar 'kalkin' Gadimov + * 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; import java.util.Date; @@ -19,72 +37,71 @@ import com.actionbarsherlock.app.SherlockActivity; public class KeyDetailsActivity extends SherlockActivity { - private PGPPublicKey publicKey; - private TextView mAlgorithm; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Bundle extras = getIntent().getExtras(); - setContentView(R.layout.key_view); - if (extras == null) { - return; - } - - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); - - long key = extras.getLong("key"); - - KeyRings.buildPublicKeyRingsByMasterKeyIdUri(key + ""); - String[] projection = new String[]{""}; - - this.publicKey = ProviderHelper.getPGPPublicKeyByKeyId( - getApplicationContext(), key); - - TextView fingerprint = (TextView) this.findViewById(R.id.fingerprint); - fingerprint.setText(PgpKeyHelper.shortifyFingerprint(PgpKeyHelper.getFingerPrint(getApplicationContext(), key))); - String[] mainUserId = splitUserId(""); - - TextView expiry = (TextView) this.findViewById(R.id.expiry); - Date expiryDate = PgpKeyHelper.getExpiryDate(publicKey); - if (expiryDate == null) { - expiry.setText(""); - } else { - expiry.setText(DateFormat.getDateFormat(getApplicationContext()) - .format(expiryDate)); - } - - TextView creation = (TextView) this.findViewById(R.id.creation); - creation.setText(DateFormat.getDateFormat(getApplicationContext()) - .format(PgpKeyHelper.getCreationDate(publicKey))); - mAlgorithm = (TextView) this.findViewById(R.id.algorithm); - mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(publicKey)); - - } - - 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; - } - - 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 PGPPublicKey publicKey; + private TextView mAlgorithm; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle extras = getIntent().getExtras(); + setContentView(R.layout.key_view); + if (extras == null) { + return; + } + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeButtonEnabled(true); + + long key = extras.getLong("key"); + + KeyRings.buildPublicKeyRingsByMasterKeyIdUri(key + ""); + String[] projection = new String[] { "" }; + + this.publicKey = ProviderHelper.getPGPPublicKeyByKeyId(getApplicationContext(), key); + + TextView fingerprint = (TextView) this.findViewById(R.id.fingerprint); + fingerprint.setText(PgpKeyHelper.shortifyFingerprint(PgpKeyHelper.getFingerPrint( + getApplicationContext(), key))); + String[] mainUserId = splitUserId(""); + + TextView expiry = (TextView) this.findViewById(R.id.expiry); + Date expiryDate = PgpKeyHelper.getExpiryDate(publicKey); + if (expiryDate == null) { + expiry.setText(""); + } else { + expiry.setText(DateFormat.getDateFormat(getApplicationContext()).format(expiryDate)); + } + + TextView creation = (TextView) this.findViewById(R.id.creation); + creation.setText(DateFormat.getDateFormat(getApplicationContext()).format( + PgpKeyHelper.getCreationDate(publicKey))); + mAlgorithm = (TextView) this.findViewById(R.id.algorithm); + mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(publicKey)); + + } + + 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; + } + + 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; + } } -- cgit v1.2.3 From 6c1a58ef15e6b5d826326fa9636e44cc6f501d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 1 Jan 2014 16:54:55 +0100 Subject: Use data uri instead of extra for key details --- .../keychain/provider/ProviderHelper.java | 2 +- .../keychain/ui/KeyDetailsActivity.java | 63 +++++++++++++--------- .../keychain/ui/KeyListPublicFragment.java | 16 +++--- 3 files changed, 49 insertions(+), 32 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java index f12048277..b07ac53f8 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -60,7 +60,7 @@ public class ProviderHelper { * @param queryUri * @return */ - private static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) { + public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) { Cursor cursor = context.getContentResolver().query(queryUri, new String[] { KeyRings._ID, KeyRings.KEY_RING_DATA }, null, null, null); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java index 82d66e2c0..5c8444d80 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java @@ -23,12 +23,15 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +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.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; +import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.text.format.DateFormat; import android.widget.TextView; @@ -36,49 +39,59 @@ import android.widget.TextView; import com.actionbarsherlock.app.SherlockActivity; public class KeyDetailsActivity extends SherlockActivity { + private Uri mDataUri; + + private PGPPublicKey mPublicKey; - private PGPPublicKey publicKey; private TextView mAlgorithm; + private TextView mFingerint; + private TextView mExpiry; + private TextView mCreation; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Bundle extras = getIntent().getExtras(); - setContentView(R.layout.key_view); - if (extras == null) { - return; - } - getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); - long key = extras.getLong("key"); + setContentView(R.layout.key_view); + + mFingerint = (TextView) this.findViewById(R.id.fingerprint); + mExpiry = (TextView) this.findViewById(R.id.expiry); + mCreation = (TextView) this.findViewById(R.id.creation); + mAlgorithm = (TextView) this.findViewById(R.id.algorithm); - KeyRings.buildPublicKeyRingsByMasterKeyIdUri(key + ""); - String[] projection = new String[] { "" }; + Intent intent = getIntent(); + mDataUri = intent.getData(); + if (mDataUri == null) { + Log.e(Constants.TAG, "Intent data missing. Should be Uri of app!"); + finish(); + return; + } else { + Log.d(Constants.TAG, "uri: " + mDataUri); + loadData(mDataUri); + } + } - this.publicKey = ProviderHelper.getPGPPublicKeyByKeyId(getApplicationContext(), key); + private void loadData(Uri dataUri) { + PGPPublicKeyRing ring = (PGPPublicKeyRing) ProviderHelper.getPGPKeyRing(this, dataUri); + mPublicKey = ring.getPublicKey(); - TextView fingerprint = (TextView) this.findViewById(R.id.fingerprint); - fingerprint.setText(PgpKeyHelper.shortifyFingerprint(PgpKeyHelper.getFingerPrint( - getApplicationContext(), key))); + mFingerint.setText(PgpKeyHelper.shortifyFingerprint(PgpKeyHelper + .convertFingerprintToHex(mPublicKey.getFingerprint()))); String[] mainUserId = splitUserId(""); - TextView expiry = (TextView) this.findViewById(R.id.expiry); - Date expiryDate = PgpKeyHelper.getExpiryDate(publicKey); + Date expiryDate = PgpKeyHelper.getExpiryDate(mPublicKey); if (expiryDate == null) { - expiry.setText(""); + mExpiry.setText(""); } else { - expiry.setText(DateFormat.getDateFormat(getApplicationContext()).format(expiryDate)); + mExpiry.setText(DateFormat.getDateFormat(getApplicationContext()).format(expiryDate)); } - TextView creation = (TextView) this.findViewById(R.id.creation); - creation.setText(DateFormat.getDateFormat(getApplicationContext()).format( - PgpKeyHelper.getCreationDate(publicKey))); - mAlgorithm = (TextView) this.findViewById(R.id.algorithm); - mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(publicKey)); - + mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format( + PgpKeyHelper.getCreationDate(mPublicKey))); + mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(mPublicKey)); } private String[] splitUserId(String userId) { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index 790ec5ccf..0cf15a451 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -20,12 +20,15 @@ package org.sufficientlysecure.keychain.ui; import org.spongycastle.openpgp.PGPPublicKeyRing; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; +import org.sufficientlysecure.keychain.service.remote.AppSettingsActivity; import org.sufficientlysecure.keychain.ui.adapter.KeyListAdapter; import org.sufficientlysecure.keychain.R; +import android.content.ContentUris; import android.content.Intent; import android.database.Cursor; import android.net.Uri; @@ -114,16 +117,17 @@ public class KeyListPublicFragment extends KeyListFragment implements return true; case 23: - - Intent detailsIntent = new Intent(mKeyListActivity, KeyDetailsActivity.class); - detailsIntent.putExtra("key", ProviderHelper.getPublicMasterKeyId(mKeyListActivity, keyRingRowId)); - startActivity(detailsIntent); + + Intent detailsIntent = new Intent(mKeyListActivity, KeyDetailsActivity.class); + detailsIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long + .toString(keyRingRowId))); + startActivity(detailsIntent); return true; - + case Id.menu.exportToServer: Intent uploadIntent = new Intent(mKeyListActivity, KeyServerUploadActivity.class); uploadIntent.setAction(KeyServerUploadActivity.ACTION_EXPORT_KEY_TO_SERVER); - uploadIntent.putExtra(KeyServerUploadActivity.EXTRA_KEYRING_ROW_ID, (int)keyRingRowId); + uploadIntent.putExtra(KeyServerUploadActivity.EXTRA_KEYRING_ROW_ID, (int) keyRingRowId); startActivityForResult(uploadIntent, Id.request.export_to_server); return true; -- cgit v1.2.3 From c8d0ff77b10bc5e0103df473076fc7cacadf9014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 1 Jan 2014 20:29:56 +0100 Subject: show layout not before passphrase is entered --- .../keychain/ui/EditKeyActivity.java | 56 +++++++++++----------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 7abee78f3..2995a839a 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -119,12 +119,6 @@ public class EditKeyActivity extends SherlockFragmentActivity { } }); - setContentView(R.layout.edit_key); - - // find views - mChangePassPhrase = (Button) findViewById(R.id.edit_key_btn_change_pass_phrase); - mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase); - mUserIds = new Vector(); mKeys = new Vector(); mKeysUsages = new Vector(); @@ -138,28 +132,6 @@ public class EditKeyActivity extends SherlockFragmentActivity { handleActionEditKey(intent); } - mChangePassPhrase.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - showSetPassphraseDialog(); - } - }); - - // disable passphrase when no passphrase checkobox is checked! - mNoPassphrase.setOnCheckedChangeListener(new OnCheckedChangeListener() { - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - // remove passphrase - mNewPassPhrase = null; - - mChangePassPhrase.setVisibility(View.GONE); - } else { - mChangePassPhrase.setVisibility(View.VISIBLE); - } - } - }); - if (mBuildLayout) { buildLayout(); } @@ -402,6 +374,12 @@ public class EditKeyActivity extends SherlockFragmentActivity { * id and key. */ private void buildLayout() { + setContentView(R.layout.edit_key); + + // find views + mChangePassPhrase = (Button) findViewById(R.id.edit_key_btn_change_pass_phrase); + mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase); + // Build layout based on given userIds and keys LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -418,6 +396,28 @@ public class EditKeyActivity extends SherlockFragmentActivity { container.addView(mKeysView); updatePassPhraseButtonText(); + + mChangePassPhrase.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + showSetPassphraseDialog(); + } + }); + + // disable passphrase when no passphrase checkobox is checked! + mNoPassphrase.setOnCheckedChangeListener(new OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + // remove passphrase + mNewPassPhrase = null; + + mChangePassPhrase.setVisibility(View.GONE); + } else { + mChangePassPhrase.setVisibility(View.VISIBLE); + } + } + }); } private long getMasterKeyId() { -- cgit v1.2.3 From 1d91804dc7943e7149d02141a46c3eb0763e2b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 1 Jan 2014 22:26:19 +0100 Subject: Simple new list implementations, remove library, use simple adapter with headings --- .../service/remote/RegisteredAppsListFragment.java | 8 +- .../keychain/ui/EditKeyActivity.java | 4 +- .../keychain/ui/KeyDetailsActivity.java | 120 ---------- .../keychain/ui/KeyListActivity.java | 22 +- .../keychain/ui/KeyListFragment.java | 88 ------- .../keychain/ui/KeyListPublicFragment.java | 174 +++----------- .../keychain/ui/KeyListSecretActivity.java | 22 +- .../keychain/ui/KeyListSecretFragment.java | 112 ++++----- .../keychain/ui/KeyViewActivity.java | 228 ++++++++++++++++++ .../keychain/ui/adapter/KeyListPublicAdapter.java | 77 ++++++ .../keychain/ui/adapter/KeyListSecretAdapter.java | 82 +++++++ .../keychain/util/SectionCursorAdapter.java | 266 +++++++++++++++++++++ 12 files changed, 760 insertions(+), 443 deletions(-) delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListFragment.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/util/SectionCursorAdapter.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListFragment.java index 1b504a374..4c9d553ad 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListFragment.java @@ -41,9 +41,6 @@ public class RegisteredAppsListFragment extends SherlockListFragment implements // This is the Adapter being used to display the list's data. RegisteredAppsAdapter mAdapter; - // If non-null, this is the current filter the user has provided. - String mCurFilter; - @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); @@ -75,8 +72,7 @@ public class RegisteredAppsListFragment extends SherlockListFragment implements } // These are the Contacts rows that we will retrieve. - static final String[] CONSUMERS_SUMMARY_PROJECTION = new String[] { ApiApps._ID, - ApiApps.PACKAGE_NAME }; + static final String[] PROJECTION = new String[] { ApiApps._ID, ApiApps.PACKAGE_NAME }; public Loader onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This @@ -87,7 +83,7 @@ public class RegisteredAppsListFragment 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, CONSUMERS_SUMMARY_PROJECTION, null, null, + return new CursorLoader(getActivity(), baseUri, PROJECTION, null, null, ApiApps.PACKAGE_NAME + " COLLATE LOCALIZED ASC"); } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 2995a839a..7aeb51c8f 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Dominik Schürmann + * Copyright (C) 2012-2013 Dominik Schürmann * Copyright (C) 2010 Thialfihar * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -268,7 +268,6 @@ public class EditKeyActivity extends SherlockFragmentActivity { * * @param intent */ - @SuppressWarnings("unchecked") private void handleActionEditKey(Intent intent) { Bundle extras = intent.getExtras(); @@ -291,7 +290,6 @@ public class EditKeyActivity extends SherlockFragmentActivity { finallyEdit(masterKeyId, masterCanSign); } - } } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java deleted file mode 100644 index 5c8444d80..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyDetailsActivity.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2013 Bahtiar 'kalkin' Gadimov - * 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; - -import java.util.Date; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.Log; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.text.format.DateFormat; -import android.widget.TextView; - -import com.actionbarsherlock.app.SherlockActivity; - -public class KeyDetailsActivity extends SherlockActivity { - private Uri mDataUri; - - private PGPPublicKey mPublicKey; - - private TextView mAlgorithm; - private TextView mFingerint; - private TextView mExpiry; - private TextView mCreation; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); - - setContentView(R.layout.key_view); - - mFingerint = (TextView) this.findViewById(R.id.fingerprint); - mExpiry = (TextView) this.findViewById(R.id.expiry); - mCreation = (TextView) this.findViewById(R.id.creation); - mAlgorithm = (TextView) this.findViewById(R.id.algorithm); - - Intent intent = getIntent(); - mDataUri = intent.getData(); - if (mDataUri == null) { - Log.e(Constants.TAG, "Intent data missing. Should be Uri of app!"); - finish(); - return; - } else { - Log.d(Constants.TAG, "uri: " + mDataUri); - loadData(mDataUri); - } - } - - private void loadData(Uri dataUri) { - PGPPublicKeyRing ring = (PGPPublicKeyRing) ProviderHelper.getPGPKeyRing(this, dataUri); - mPublicKey = ring.getPublicKey(); - - mFingerint.setText(PgpKeyHelper.shortifyFingerprint(PgpKeyHelper - .convertFingerprintToHex(mPublicKey.getFingerprint()))); - String[] mainUserId = splitUserId(""); - - Date expiryDate = PgpKeyHelper.getExpiryDate(mPublicKey); - if (expiryDate == null) { - mExpiry.setText(""); - } else { - mExpiry.setText(DateFormat.getDateFormat(getApplicationContext()).format(expiryDate)); - } - - mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format( - PgpKeyHelper.getCreationDate(mPublicKey))); - mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(mPublicKey)); - } - - 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; - } - - 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/ui/KeyListActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListActivity.java index 7b844fe08..4d1849029 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListActivity.java @@ -1,18 +1,18 @@ /* - * Copyright (C) 2012 Dominik Schürmann - * Copyright (C) 2010 Thialfihar + * Copyright (C) 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 + * 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.ui; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListFragment.java deleted file mode 100644 index 0d61b1108..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2012-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; - -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.widget.ExpandableListFragment; -import org.sufficientlysecure.keychain.R; - -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.View; -import android.widget.ExpandableListView; -import android.widget.ExpandableListView.ExpandableListContextMenuInfo; - -public class KeyListFragment extends ExpandableListFragment { - protected KeyListActivity mKeyListActivity; - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mKeyListActivity = (KeyListActivity) getActivity(); - - // register long press context menu - registerForContextMenu(getListView()); - - // Give some text to display if there is no data. In a real - // application this would come from a resource. - setEmptyText(getString(R.string.list_empty)); - } - - /** - * Context Menu on Long Click - */ - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - menu.add(0, Id.menu.export, 5, R.string.menu_export_key); - menu.add(0, Id.menu.delete, 111, R.string.menu_delete_key); - } - - @Override - public boolean onContextItemSelected(android.view.MenuItem item) { - ExpandableListContextMenuInfo expInfo = (ExpandableListContextMenuInfo) item.getMenuInfo(); - - // expInfo.id would also return row id of childs, but we always want to get the row id of - // the group item, thus we are using the following way - int groupPosition = ExpandableListView.getPackedPositionGroup(expInfo.packedPosition); - long keyRingRowId = getExpandableListAdapter().getGroupId(groupPosition); - - switch (item.getItemId()) { - case Id.menu.export: - long masterKeyId = ProviderHelper.getPublicMasterKeyId(mKeyListActivity, keyRingRowId); - if (masterKeyId == -1) { - masterKeyId = ProviderHelper.getSecretMasterKeyId(mKeyListActivity, keyRingRowId); - } - - mKeyListActivity.showExportKeysDialog(masterKeyId); - return true; - - case Id.menu.delete: - mKeyListActivity.showDeleteKeyDialog(keyRingRowId); - return true; - - default: - return super.onContextItemSelected(item); - - } - } - -} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index 0cf15a451..3dafc84ca 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Dominik Schürmann + * 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 @@ -17,37 +17,32 @@ package org.sufficientlysecure.keychain.ui; -import org.spongycastle.openpgp.PGPPublicKeyRing; import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.service.remote.AppSettingsActivity; -import org.sufficientlysecure.keychain.ui.adapter.KeyListAdapter; -import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.adapter.KeyListPublicAdapter; -import android.content.ContentUris; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; +import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.support.v4.app.LoaderManager; -import android.view.ContextMenu; import android.view.View; -import android.view.ContextMenu.ContextMenuInfo; -import android.widget.ExpandableListView; -import android.widget.ExpandableListView.ExpandableListContextMenuInfo; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; + +import com.actionbarsherlock.app.SherlockListFragment; -public class KeyListPublicFragment extends KeyListFragment implements +public class KeyListPublicFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks { private KeyListPublicActivity mKeyListPublicActivity; - private KeyListAdapter mAdapter; + private KeyListPublicAdapter mAdapter; /** * Define Adapter and Loader on create of Activity @@ -58,135 +53,34 @@ public class KeyListPublicFragment extends KeyListFragment implements mKeyListPublicActivity = (KeyListPublicActivity) getActivity(); - mAdapter = new KeyListAdapter(mKeyListPublicActivity, null, Id.type.public_key); - setListAdapter(mAdapter); - - // Start out with a progress indicator. - setListShown(false); - - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - // id is -1 as the child cursors are numbered 0,...,n - getLoaderManager().initLoader(-1, null, this); - } - - /** - * Context Menu on Long Click - */ - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - menu.add(0, 23, 1, R.string.title_key_details); // :TODO: Fix magic number - menu.add(0, Id.menu.update, 2, R.string.menu_update_key); - menu.add(0, Id.menu.signKey, 3, R.string.menu_sign_key); - menu.add(0, Id.menu.exportToServer, 4, R.string.menu_export_key_to_server); - menu.add(0, Id.menu.share, 6, R.string.menu_share); - menu.add(0, Id.menu.share_qr_code, 7, R.string.menu_share_qr_code); - menu.add(0, Id.menu.share_nfc, 8, R.string.menu_share_nfc); - - } - - @Override - public boolean onContextItemSelected(android.view.MenuItem item) { - ExpandableListContextMenuInfo expInfo = (ExpandableListContextMenuInfo) item.getMenuInfo(); - - // expInfo.id would also return row id of childs, but we always want to get the row id of - // the group item, thus we are using the following way - int groupPosition = ExpandableListView.getPackedPositionGroup(expInfo.packedPosition); - long keyRingRowId = getExpandableListAdapter().getGroupId(groupPosition); - - switch (item.getItemId()) { - case Id.menu.update: - long updateKeyId = 0; - PGPPublicKeyRing updateKeyRing = ProviderHelper.getPGPPublicKeyRingByRowId( - mKeyListActivity, keyRingRowId); - if (updateKeyRing != null) { - updateKeyId = PgpKeyHelper.getMasterKey(updateKeyRing).getKeyID(); + getListView().setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int position, long id) { + // start key view on click + Intent detailsIntent = new Intent(mKeyListPublicActivity, KeyViewActivity.class); + detailsIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long + .toString(id))); + startActivity(detailsIntent); } - if (updateKeyId == 0) { - // this shouldn't happen - return true; - } - - Intent queryIntent = new Intent(mKeyListActivity, KeyServerQueryActivity.class); - queryIntent.setAction(KeyServerQueryActivity.ACTION_LOOK_UP_KEY_ID_AND_RETURN); - queryIntent.putExtra(KeyServerQueryActivity.EXTRA_KEY_ID, updateKeyId); + }); - // TODO: lookup?? - startActivityForResult(queryIntent, Id.request.look_up_key_id); + // Give some text to display if there is no data. In a real + // application this would come from a resource. + setEmptyText(getString(R.string.list_empty)); - return true; - case 23: + // We have a menu item to show in action bar. + setHasOptionsMenu(true); - Intent detailsIntent = new Intent(mKeyListActivity, KeyDetailsActivity.class); - detailsIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long - .toString(keyRingRowId))); - startActivity(detailsIntent); - return true; - - case Id.menu.exportToServer: - Intent uploadIntent = new Intent(mKeyListActivity, KeyServerUploadActivity.class); - uploadIntent.setAction(KeyServerUploadActivity.ACTION_EXPORT_KEY_TO_SERVER); - uploadIntent.putExtra(KeyServerUploadActivity.EXTRA_KEYRING_ROW_ID, (int) keyRingRowId); - startActivityForResult(uploadIntent, Id.request.export_to_server); - - return true; - - case Id.menu.signKey: - long keyId = 0; - PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByRowId( - mKeyListActivity, keyRingRowId); - if (signKeyRing != null) { - keyId = PgpKeyHelper.getMasterKey(signKeyRing).getKeyID(); - } - if (keyId == 0) { - // this shouldn't happen - return true; - } - - Intent signIntent = new Intent(mKeyListActivity, SignKeyActivity.class); - signIntent.putExtra(SignKeyActivity.EXTRA_KEY_ID, keyId); - startActivity(signIntent); - - return true; - - case Id.menu.share_qr_code: - // get master key id using row id - long masterKeyId = ProviderHelper.getPublicMasterKeyId(mKeyListActivity, keyRingRowId); - - Intent qrCodeIntent = new Intent(mKeyListActivity, ShareActivity.class); - qrCodeIntent.setAction(ShareActivity.ACTION_SHARE_KEYRING_WITH_QR_CODE); - qrCodeIntent.putExtra(ShareActivity.EXTRA_MASTER_KEY_ID, masterKeyId); - startActivityForResult(qrCodeIntent, 0); - - return true; - - case Id.menu.share_nfc: - // get master key id using row id - long masterKeyId2 = ProviderHelper.getPublicMasterKeyId(mKeyListActivity, keyRingRowId); - - Intent nfcIntent = new Intent(mKeyListActivity, ShareNfcBeamActivity.class); - nfcIntent.setAction(ShareNfcBeamActivity.ACTION_SHARE_KEYRING_WITH_NFC); - nfcIntent.putExtra(ShareNfcBeamActivity.EXTRA_MASTER_KEY_ID, masterKeyId2); - startActivityForResult(nfcIntent, 0); - - return true; - - case Id.menu.share: - // get master key id using row id - long masterKeyId3 = ProviderHelper.getPublicMasterKeyId(mKeyListActivity, keyRingRowId); - - Intent shareIntent = new Intent(mKeyListActivity, ShareActivity.class); - shareIntent.setAction(ShareActivity.ACTION_SHARE_KEYRING); - shareIntent.putExtra(ShareActivity.EXTRA_MASTER_KEY_ID, masterKeyId3); - startActivityForResult(shareIntent, 0); - - return true; + // Start out with a progress indicator. + setListShown(false); - default: - return super.onContextItemSelected(item); + // Create an empty adapter we will use to display the loaded data. + mAdapter = new KeyListPublicAdapter(mKeyListPublicActivity, null, Id.type.public_key); + setListAdapter(mAdapter); - } + // Prepare the loader. Either re-connect with an existing one, + // or start a new one. + getLoaderManager().initLoader(0, null, this); } // These are the rows that we will retrieve. @@ -210,7 +104,7 @@ public class KeyListPublicFragment extends KeyListFragment implements 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.) - mAdapter.setGroupCursor(data); + mAdapter.swapCursor(data); // The list should now be shown. if (isResumed()) { @@ -225,7 +119,7 @@ public class KeyListPublicFragment extends KeyListFragment implements // 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. - mAdapter.setGroupCursor(null); + mAdapter.swapCursor(null); } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java index 822c73872..d98b5ab37 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java @@ -1,18 +1,18 @@ /* - * Copyright (C) 2012 Dominik Schürmann - * Copyright (C) 2010 Thialfihar + * Copyright (C) 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 + * 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.ui; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java index 4bbf3d6ef..e8a306063 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java @@ -1,18 +1,18 @@ /* - * Copyright (C) 2012 Dominik Schürmann - * Copyright (C) 2010 Thialfihar + * Copyright (C) 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 + * 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.ui; @@ -22,7 +22,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.adapter.KeyListAdapter; +import org.sufficientlysecure.keychain.ui.adapter.KeyListSecretAdapter; import android.database.Cursor; import android.net.Uri; @@ -30,18 +30,18 @@ import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; import android.view.View; -import android.widget.ExpandableListView; -import android.widget.ExpandableListView.ExpandableListContextMenuInfo; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; -public class KeyListSecretFragment extends KeyListFragment implements +import com.actionbarsherlock.app.SherlockListFragment; + +public class KeyListSecretFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks { private KeyListSecretActivity mKeyListSecretActivity; - private KeyListAdapter mAdapter; + private KeyListSecretAdapter mAdapter; /** * Define Adapter and Loader on create of Activity @@ -52,53 +52,38 @@ public class KeyListSecretFragment extends KeyListFragment implements mKeyListSecretActivity = (KeyListSecretActivity) getActivity(); - mAdapter = new KeyListAdapter(mKeyListSecretActivity, null, Id.type.secret_key); - setListAdapter(mAdapter); + getListView().setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int position, long id) { + // TODO: currently this is EDIT directly, later first show VIEW - // Start out with a progress indicator. - setListShown(false); + // get master key id using row id + long masterKeyId = ProviderHelper.getSecretMasterKeyId(mKeyListSecretActivity, id); - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - // id is -1 as the child cursors are numbered 0,...,n - getLoaderManager().initLoader(-1, null, this); - } + boolean masterCanSign = ProviderHelper.getSecretMasterKeyCanSign( + mKeyListSecretActivity, id); - /** - * Context Menu on Long Click - */ - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - menu.add(0, Id.menu.edit, 0, R.string.menu_edit_key); - } - - @Override - public boolean onContextItemSelected(android.view.MenuItem item) { - ExpandableListContextMenuInfo expInfo = (ExpandableListContextMenuInfo) item.getMenuInfo(); + mKeyListSecretActivity.editKey(masterKeyId, masterCanSign); + } + }); - // expInfo.id would also return row id of childs, but we always want to get the row id of - // the group item, thus we are using the following way - int groupPosition = ExpandableListView.getPackedPositionGroup(expInfo.packedPosition); - long keyRingRowId = getExpandableListAdapter().getGroupId(groupPosition); + // Give some text to display if there is no data. In a real + // application this would come from a resource. + setEmptyText(getString(R.string.list_empty)); - // get master key id using row id - long masterKeyId = ProviderHelper - .getSecretMasterKeyId(mKeyListSecretActivity, keyRingRowId); + // We have a menu item to show in action bar. + setHasOptionsMenu(true); - boolean masterCanSign = ProviderHelper.getSecretMasterKeyCanSign(mKeyListSecretActivity, - keyRingRowId); - - switch (item.getItemId()) { - case Id.menu.edit: - mKeyListSecretActivity.editKey(masterKeyId, masterCanSign); - - return true; + // Start out with a progress indicator. + setListShown(false); - default: - return super.onContextItemSelected(item); + // Create an empty adapter we will use to display the loaded data. + mAdapter = new KeyListSecretAdapter(mKeyListSecretActivity, null, Id.type.secret_key); + setListAdapter(mAdapter); - } + // Prepare the loader. Either re-connect with an existing one, + // or start a new one. + getLoaderManager().initLoader(0, null, this); } // These are the rows that we will retrieve. @@ -107,22 +92,23 @@ public class KeyListSecretFragment extends KeyListFragment implements static final String SORT_ORDER = UserIds.USER_ID + " ASC"; - @Override public Loader onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. + // First, pick the base URI to use depending on whether we are + // currently filtering. Uri baseUri = KeyRings.buildSecretKeyRingsUri(); // 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, SORT_ORDER); + return new CursorLoader(getActivity(), baseUri, PROJECTION, null, null, UserIds.USER_ID + + " COLLATE LOCALIZED ASC"); } - @Override 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.) - mAdapter.setGroupCursor(data); + mAdapter.swapCursor(data); // The list should now be shown. if (isResumed()) { @@ -132,12 +118,10 @@ public class KeyListSecretFragment extends KeyListFragment implements } } - @Override public void onLoaderReset(Loader loader) { // 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. - mAdapter.setGroupCursor(null); + mAdapter.swapCursor(null); } - } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java new file mode 100644 index 000000000..c2ef64d51 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2013 Bahtiar 'kalkin' Gadimov + * 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; + +import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.util.Log; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.provider.ContactsContract.DataUsageFeedback; +import android.text.format.DateFormat; +import android.widget.TextView; + +import com.actionbarsherlock.app.SherlockActivity; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; + +public class KeyViewActivity extends SherlockActivity { + private Uri mDataUri; + + private PGPPublicKey mPublicKey; + + private TextView mAlgorithm; + private TextView mFingerint; + private TextView mExpiry; + private TextView mCreation; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeButtonEnabled(true); + + setContentView(R.layout.key_view_activity); + + mFingerint = (TextView) this.findViewById(R.id.fingerprint); + mExpiry = (TextView) this.findViewById(R.id.expiry); + mCreation = (TextView) this.findViewById(R.id.creation); + mAlgorithm = (TextView) this.findViewById(R.id.algorithm); + + Intent intent = getIntent(); + mDataUri = intent.getData(); + if (mDataUri == null) { + Log.e(Constants.TAG, "Intent data missing. Should be Uri of app!"); + finish(); + return; + } else { + Log.d(Constants.TAG, "uri: " + mDataUri); + loadData(mDataUri); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + getSupportMenuInflater().inflate(R.menu.key_view, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // TODO: use data uri in the other activities instead of givin key ring row id! + + long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); + + switch (item.getItemId()) { + case R.id.menu_key_view_update: + long updateKeyId = 0; + PGPPublicKeyRing updateKeyRing = ProviderHelper.getPGPPublicKeyRingByRowId(this, + keyRingRowId); + if (updateKeyRing != null) { + updateKeyId = PgpKeyHelper.getMasterKey(updateKeyRing).getKeyID(); + } + if (updateKeyId == 0) { + // this shouldn't happen + return true; + } + + Intent queryIntent = new Intent(this, KeyServerQueryActivity.class); + queryIntent.setAction(KeyServerQueryActivity.ACTION_LOOK_UP_KEY_ID_AND_RETURN); + queryIntent.putExtra(KeyServerQueryActivity.EXTRA_KEY_ID, updateKeyId); + + // TODO: lookup?? + startActivityForResult(queryIntent, Id.request.look_up_key_id); + + return true; + case R.id.menu_key_view_sign: + long keyId = 0; + PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByRowId(this, + keyRingRowId); + if (signKeyRing != null) { + keyId = PgpKeyHelper.getMasterKey(signKeyRing).getKeyID(); + } + if (keyId == 0) { + // this shouldn't happen + return true; + } + + Intent signIntent = new Intent(this, SignKeyActivity.class); + signIntent.putExtra(SignKeyActivity.EXTRA_KEY_ID, keyId); + startActivity(signIntent); + return true; + case R.id.menu_key_view_export_keyserver: + Intent uploadIntent = new Intent(this, KeyServerUploadActivity.class); + uploadIntent.setAction(KeyServerUploadActivity.ACTION_EXPORT_KEY_TO_SERVER); + uploadIntent.putExtra(KeyServerUploadActivity.EXTRA_KEYRING_ROW_ID, (int) keyRingRowId); + startActivityForResult(uploadIntent, Id.request.export_to_server); + + return true; + case R.id.menu_key_view_export_file: +// long masterKeyId = ProviderHelper.getPublicMasterKeyId(mKeyListActivity, keyRingRowId); +// if (masterKeyId == -1) { +// masterKeyId = ProviderHelper.getSecretMasterKeyId(mKeyListActivity, keyRingRowId); +// } +// +// mKeyListActivity.showExportKeysDialog(masterKeyId); + return true; + case R.id.menu_key_view_share: + // get master key id using row id + long masterKeyId3 = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); + + Intent shareIntent = new Intent(this, ShareActivity.class); + shareIntent.setAction(ShareActivity.ACTION_SHARE_KEYRING); + shareIntent.putExtra(ShareActivity.EXTRA_MASTER_KEY_ID, masterKeyId3); + startActivityForResult(shareIntent, 0); + + return true; + case R.id.menu_key_view_share_qr_code: + // get master key id using row id + long masterKeyId = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); + + Intent qrCodeIntent = new Intent(this, ShareActivity.class); + qrCodeIntent.setAction(ShareActivity.ACTION_SHARE_KEYRING_WITH_QR_CODE); + qrCodeIntent.putExtra(ShareActivity.EXTRA_MASTER_KEY_ID, masterKeyId); + startActivityForResult(qrCodeIntent, 0); + + return true; + case R.id.menu_key_view_share_nfc: + // get master key id using row id + long masterKeyId2 = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); + + Intent nfcIntent = new Intent(this, ShareNfcBeamActivity.class); + nfcIntent.setAction(ShareNfcBeamActivity.ACTION_SHARE_KEYRING_WITH_NFC); + nfcIntent.putExtra(ShareNfcBeamActivity.EXTRA_MASTER_KEY_ID, masterKeyId2); + startActivityForResult(nfcIntent, 0); + + return true; + case R.id.menu_key_view_delete: +// mKeyListActivity.showDeleteKeyDialog(keyRingRowId); + + return true; + + } + return super.onOptionsItemSelected(item); + } + + private void loadData(Uri dataUri) { + PGPPublicKeyRing ring = (PGPPublicKeyRing) ProviderHelper.getPGPKeyRing(this, dataUri); + mPublicKey = ring.getPublicKey(); + + mFingerint.setText(PgpKeyHelper.shortifyFingerprint(PgpKeyHelper + .convertFingerprintToHex(mPublicKey.getFingerprint()))); + String[] mainUserId = splitUserId(""); + + Date expiryDate = PgpKeyHelper.getExpiryDate(mPublicKey); + if (expiryDate == null) { + mExpiry.setText(""); + } else { + mExpiry.setText(DateFormat.getDateFormat(getApplicationContext()).format(expiryDate)); + } + + mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format( + PgpKeyHelper.getCreationDate(mPublicKey))); + mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(mPublicKey)); + } + + 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; + } + + 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/ui/adapter/KeyListPublicAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java new file mode 100644 index 000000000..d72c9d42a --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java @@ -0,0 +1,77 @@ +/* + * 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 org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.OtherHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; +import org.sufficientlysecure.keychain.util.SectionCursorAdapter; + +import android.content.Context; +import android.database.Cursor; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +public class KeyListPublicAdapter extends SectionCursorAdapter { + + private LayoutInflater mInflater; + + public KeyListPublicAdapter(Context context, Cursor c, int flags) { + super(context, c, android.R.layout.preference_category, 2); // TODO: 2 is user id + + mInflater = LayoutInflater.from(context); + } + + @Override + 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 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); + } + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mInflater.inflate(R.layout.key_list_group_item, null); + } + +} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java new file mode 100644 index 000000000..6f3129e4f --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java @@ -0,0 +1,82 @@ +/* + * 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 org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.OtherHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +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 KeyListSecretAdapter extends CursorAdapter { + + private LayoutInflater mInflater; + + public KeyListSecretAdapter(Context context, Cursor c, int flags) { + super(context, c, flags); + + mInflater = LayoutInflater.from(context); + } + + @Override + 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 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); + } + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mInflater.inflate(R.layout.key_list_group_item, null); + } + +} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/util/SectionCursorAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/util/SectionCursorAdapter.java new file mode 100644 index 000000000..0d4092d9e --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/util/SectionCursorAdapter.java @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * Copyright (C) 2011 Gonçalo Ferreira + * + * 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 java.util.LinkedHashMap; + +import android.content.Context; +import android.database.Cursor; +import android.database.DataSetObserver; +import android.support.v4.widget.CursorAdapter; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +/** + * Originally from https://github.com/monxalo/android-section-adapter + * + * getCustomGroup() has been modified + */ +public abstract class SectionCursorAdapter extends CursorAdapter { + + private static final String TAG = "SectionCursorAdapter"; + private static final boolean LOGV = false; + + private static final int TYPE_NORMAL = 1; + private static final int TYPE_HEADER = 0; + private static final int TYPE_COUNT = 2; + + private final int mHeaderRes; + private final int mGroupColumn; + private final LayoutInflater mLayoutInflater; + + private LinkedHashMap sectionsIndexer; + + public static class ViewHolder { + public TextView textView; + } + + public SectionCursorAdapter(Context context, Cursor c, int headerLayout, int groupColumn) { + super(context, c, 0); + + sectionsIndexer = new LinkedHashMap(); + + mHeaderRes = headerLayout; + mGroupColumn = groupColumn; + mLayoutInflater = LayoutInflater.from(context); + + if (c != null) { + calculateSectionHeaders(); + c.registerDataSetObserver(mDataSetObserver); + } + } + + private DataSetObserver mDataSetObserver = new DataSetObserver() { + public void onChanged() { + calculateSectionHeaders(); + }; + + public void onInvalidated() { + sectionsIndexer.clear(); + }; + }; + + /** + *

+ * This method serve as an intercepter before the sections are calculated so you can transform + * some computer data into human readable, e.g. format a unix timestamp, or a status. + *

+ * + *

+ * By default this method returns the original data for the group column. + *

+ * + * @param groupData + * @return + */ + protected String getCustomGroup(String groupData) { + return groupData.substring(0, 1); + } + + private void calculateSectionHeaders() { + int i = 0; + + String previous = ""; + int count = 0; + + final Cursor c = getCursor(); + + sectionsIndexer.clear(); + + if (c == null) { + return; + } + + c.moveToPosition(-1); + + while (c.moveToNext()) { + final String group = getCustomGroup(c.getString(mGroupColumn)); + + if (!previous.equals(group)) { + sectionsIndexer.put(i + count, group); + previous = group; + + if (LOGV) + Log.v(TAG, "Group " + group + "at position: " + (i + count)); + + count++; + } + + i++; + } + } + + public String getGroupCustomFormat(Object obj) { + return null; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + int viewType = getItemViewType(position); + + if (viewType == TYPE_NORMAL) { + Cursor c = (Cursor) getItem(position); + + if (c == null) { + if (LOGV) + Log.d(TAG, "getItem(" + position + ") = null"); + return mLayoutInflater.inflate(mHeaderRes, parent, false); + } + + final int mapCursorPos = getSectionForPosition(position); + c.moveToPosition(mapCursorPos); + + return super.getView(mapCursorPos, convertView, parent); + } else { + ViewHolder holder = null; + + if (convertView == null) { + if (LOGV) + Log.v(TAG, "Creating new view for section"); + + holder = new ViewHolder(); + convertView = mLayoutInflater.inflate(mHeaderRes, parent, false); + holder.textView = (TextView) convertView; + + convertView.setTag(holder); + } else { + if (LOGV) + Log.v(TAG, "Reusing view for section"); + + holder = (ViewHolder) convertView.getTag(); + } + + TextView sectionText = holder.textView; + + final String group = sectionsIndexer.get(position); + final String customFormat = getGroupCustomFormat(group); + + sectionText.setText(customFormat == null ? group : customFormat); + + return sectionText; + } + } + + @Override + public int getViewTypeCount() { + return TYPE_COUNT; + } + + @Override + public int getCount() { + return super.getCount() + sectionsIndexer.size(); + } + + @Override + public boolean isEnabled(int position) { + return getItemViewType(position) == TYPE_NORMAL; + } + + public int getPositionForSection(int section) { + if (sectionsIndexer.containsKey(section)) { + return section + 1; + } + return section; + } + + public int getSectionForPosition(int position) { + int offset = 0; + for (Integer key : sectionsIndexer.keySet()) { + if (position > key) { + offset++; + } else { + break; + } + } + + return position - offset; + } + + @Override + public Object getItem(int position) { + if (getItemViewType(position) == TYPE_NORMAL) { + return super.getItem(getSectionForPosition(position)); + } + return super.getItem(position); + } + + @Override + public long getItemId(int position) { + if (getItemViewType(position) == TYPE_NORMAL) { + return super.getItemId(getSectionForPosition(position)); + } + return super.getItemId(position); + } + + @Override + public int getItemViewType(int position) { + if (position == getPositionForSection(position)) { + return TYPE_NORMAL; + } + return TYPE_HEADER; + } + + @Override + public void changeCursor(Cursor cursor) { + final Cursor old = swapCursor(cursor); + + if (old != null) { + old.close(); + } + } + + @Override + public Cursor swapCursor(Cursor newCursor) { + if (getCursor() != null) { + getCursor().unregisterDataSetObserver(mDataSetObserver); + } + + final Cursor oldCursor = super.swapCursor(newCursor); + + calculateSectionHeaders(); + + if (newCursor != null) { + newCursor.registerDataSetObserver(mDataSetObserver); + } + + return oldCursor; + } +} \ No newline at end of file -- cgit v1.2.3 From f5da63f9882e1807c6bd2adb5205ad7482c45339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 2 Jan 2014 21:10:08 +0100 Subject: New list with sticky list headers library --- .../keychain/ui/KeyListPublicFragment.java | 93 ++++++++++++++++------ .../keychain/ui/adapter/KeyListPublicAdapter.java | 80 +++++++++++++++++-- .../stickylistheaders/views/UnderlineTextView.java | 50 ++++++++++++ 3 files changed, 193 insertions(+), 30 deletions(-) create mode 100644 OpenPGP-Keychain/src/se/emilsjolander/stickylistheaders/views/UnderlineTextView.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index 3dafc84ca..8167ff439 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -24,6 +24,9 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.ui.adapter.KeyListPublicAdapter; +import se.emilsjolander.stickylistheaders.ApiLevelTooLowException; +import se.emilsjolander.stickylistheaders.StickyListHeadersListView; +import android.annotation.SuppressLint; import android.content.Intent; import android.database.Cursor; import android.net.Uri; @@ -31,58 +34,84 @@ import android.os.Bundle; 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.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import com.actionbarsherlock.app.SherlockListFragment; - -public class KeyListPublicFragment extends SherlockListFragment implements - LoaderManager.LoaderCallbacks { +import com.actionbarsherlock.app.SherlockFragment; + +/** + * Public key list with sticky list headers. + * + * - uses StickyListHeaders library + * - custom adapter: KeyListPublicAdapter + * + * TODO: + * - fix loader with spinning animation + * - fix design + * - fix view holder in adapter + * + */ +public class KeyListPublicFragment extends SherlockFragment implements + AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks { private KeyListPublicActivity mKeyListPublicActivity; private KeyListPublicAdapter mAdapter; + StickyListHeadersListView stickyList; + /** * Define Adapter and Loader on create of Activity */ + @SuppressLint("NewApi") @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mKeyListPublicActivity = (KeyListPublicActivity) getActivity(); - getListView().setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView adapterView, View view, int position, long id) { - // start key view on click - Intent detailsIntent = new Intent(mKeyListPublicActivity, KeyViewActivity.class); - detailsIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long - .toString(id))); - startActivity(detailsIntent); - } - }); + stickyList = (StickyListHeadersListView) getActivity().findViewById( + R.id.key_list_public_fragment_stickylist); + + stickyList.setOnItemClickListener(this); + // stickyList.setOnHeaderClickListener(this); + // stickyList.setOnStickyHeaderOffsetChangedListener(this); + // mStickyList.addHeaderView(inflater.inflate(R.layout.list_header, null)); + // mStickyList.addFooterView(inflater.inflate(R.layout.list_footer, null)); + // stickyList.setEmptyView(findViewById(R.id.empty)); + stickyList.setAreHeadersSticky(true); + stickyList.setDrawingListUnderStickyHeader(true); + stickyList.setFastScrollEnabled(true); + try { + stickyList.setFastScrollAlwaysVisible(true); + } catch (ApiLevelTooLowException e) { + } // Give some text to display if there is no data. In a real // application this would come from a resource. - setEmptyText(getString(R.string.list_empty)); - - // We have a menu item to show in action bar. - setHasOptionsMenu(true); + // setEmptyText(getString(R.string.list_empty)); // Start out with a progress indicator. - setListShown(false); + // setListShown(false); // Create an empty adapter we will use to display the loaded data. - mAdapter = new KeyListPublicAdapter(mKeyListPublicActivity, null, Id.type.public_key); - setListAdapter(mAdapter); + // mAdapter = new KeyListPublicAdapter(mKeyListPublicActivity, null, Id.type.public_key); + // setListAdapter(mAdapter); + // stickyList.setAdapter(mAdapter); // Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this); } + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.key_list_public_fragment, container, false); + return view; + } + // These are the rows that we will retrieve. static final String[] PROJECTION = new String[] { KeyRings._ID, KeyRings.MASTER_KEY_ID, UserIds.USER_ID }; @@ -104,13 +133,19 @@ public class KeyListPublicFragment extends SherlockListFragment implements 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.) - mAdapter.swapCursor(data); + // mAdapter.swapCursor(data); + int userIdIndex = data.getColumnIndex(UserIds.USER_ID); + + mAdapter = new KeyListPublicAdapter(mKeyListPublicActivity, data, Id.type.public_key, + userIdIndex); + + stickyList.setAdapter(mAdapter); // The list should now be shown. if (isResumed()) { - setListShown(true); + // setListShown(true); } else { - setListShownNoAnimation(true); + // setListShownNoAnimation(true); } } @@ -122,4 +157,12 @@ public class KeyListPublicFragment extends SherlockListFragment implements mAdapter.swapCursor(null); } + @Override + public void onItemClick(AdapterView adapterView, View view, int position, long id) { + // start key view on click + Intent detailsIntent = new Intent(mKeyListPublicActivity, KeyViewActivity.class); + detailsIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long.toString(id))); + startActivity(detailsIntent); + } + } 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 d72c9d42a..86a47d4d7 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java @@ -17,30 +17,40 @@ package org.sufficientlysecure.keychain.ui.adapter; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.OtherHelper; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.util.SectionCursorAdapter; +import org.sufficientlysecure.keychain.util.Log; +import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; 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.TextView; -public class KeyListPublicAdapter extends SectionCursorAdapter { - +/** + * - implements StickyListHeadersAdapter from library - uses view holder pattern for performance + * + */ +public class KeyListPublicAdapter extends CursorAdapter implements StickyListHeadersAdapter { private LayoutInflater mInflater; - public KeyListPublicAdapter(Context context, Cursor c, int flags) { - super(context, c, android.R.layout.preference_category, 2); // TODO: 2 is user id + int mSectionColumnIndex; + + public KeyListPublicAdapter(Context context, Cursor c, int flags, int sectionColumnIndex) { + super(context, c, flags); mInflater = LayoutInflater.from(context); + mSectionColumnIndex = sectionColumnIndex; } @Override public void bindView(View view, Context context, Cursor cursor) { + // TODO: view holder pattern? int userIdIndex = cursor.getColumnIndex(UserIds.USER_ID); TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); @@ -74,4 +84,64 @@ public class KeyListPublicAdapter extends SectionCursorAdapter { return mInflater.inflate(R.layout.key_list_group_item, null); } + @Override + public View getHeaderView(int position, View convertView, ViewGroup parent) { + + HeaderViewHolder holder; + if (convertView == null) { + holder = new HeaderViewHolder(); + convertView = mInflater.inflate(R.layout.stickylist_header, parent, false); + holder.text = (TextView) convertView.findViewById(R.id.stickylist_header_text); + convertView.setTag(holder); + } else { + holder = (HeaderViewHolder) convertView.getTag(); + } + + if (!mDataValid) { + // no data available at this point + Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); + return convertView; + } + + // similar to getView in CursorAdapter + if (!mCursor.moveToPosition(position)) { + throw new IllegalStateException("couldn't move cursor to position " + position); + } + + // set header text as first char in name + String headerText = "" + mCursor.getString(mSectionColumnIndex).subSequence(0, 1).charAt(0); + holder.text.setText(headerText); + return convertView; + } + + /** + * Remember that these have to be static, position=1 should always return the same Id that is. + */ + @Override + public long getHeaderId(int position) { + if (!mDataValid) { + // no data available at this point + Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); + return -1; + } + + // similar to getView in CursorAdapter + if (!mCursor.moveToPosition(position)) { + throw new IllegalStateException("couldn't move cursor to position " + position); + } + + // return the first character of the name as ID because this is what + // headers are based upon + return mCursor.getString(mSectionColumnIndex).subSequence(0, 1).charAt(0); + } + + class HeaderViewHolder { + TextView text; + } + + class ViewHolder { + TextView mainUserId; + TextView mainUserIdRest; + } + } diff --git a/OpenPGP-Keychain/src/se/emilsjolander/stickylistheaders/views/UnderlineTextView.java b/OpenPGP-Keychain/src/se/emilsjolander/stickylistheaders/views/UnderlineTextView.java new file mode 100644 index 000000000..c202c00b8 --- /dev/null +++ b/OpenPGP-Keychain/src/se/emilsjolander/stickylistheaders/views/UnderlineTextView.java @@ -0,0 +1,50 @@ +package se.emilsjolander.stickylistheaders.views; + +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; + +/** + * @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 faabf8eca264d2fa41d467e66e546f724281c47c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 2 Jan 2014 22:01:25 +0100 Subject: fixing some layout problems --- .../keychain/ui/KeyListPublicFragment.java | 15 +++++---------- .../keychain/ui/adapter/KeyListAdapter.java | 2 +- .../keychain/ui/adapter/KeyListPublicAdapter.java | 2 +- .../keychain/ui/adapter/KeyListSecretAdapter.java | 2 +- 4 files changed, 8 insertions(+), 13 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index 8167ff439..84adaef99 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -44,14 +44,10 @@ import com.actionbarsherlock.app.SherlockFragment; /** * Public key list with sticky list headers. * - * - uses StickyListHeaders library - * - custom adapter: KeyListPublicAdapter + * - uses StickyListHeaders library - custom adapter: KeyListPublicAdapter + * + * TODO: - fix loader with spinning animation - fix design - fix view holder in adapter * - * TODO: - * - fix loader with spinning animation - * - fix design - * - fix view holder in adapter - * */ public class KeyListPublicFragment extends SherlockFragment implements AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks { @@ -72,15 +68,14 @@ public class KeyListPublicFragment extends SherlockFragment implements mKeyListPublicActivity = (KeyListPublicActivity) getActivity(); - stickyList = (StickyListHeadersListView) getActivity().findViewById( - R.id.key_list_public_fragment_stickylist); + stickyList = (StickyListHeadersListView) getActivity().findViewById(R.id.list); stickyList.setOnItemClickListener(this); // stickyList.setOnHeaderClickListener(this); // stickyList.setOnStickyHeaderOffsetChangedListener(this); // mStickyList.addHeaderView(inflater.inflate(R.layout.list_header, null)); // mStickyList.addFooterView(inflater.inflate(R.layout.list_footer, null)); - // stickyList.setEmptyView(findViewById(R.id.empty)); + stickyList.setEmptyView(getActivity().findViewById(R.id.empty)); stickyList.setAreHeadersSticky(true); stickyList.setDrawingListUnderStickyHeader(true); stickyList.setFastScrollEnabled(true); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapter.java index e94934008..4719d1d1c 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapter.java @@ -61,7 +61,7 @@ public class KeyListAdapter extends CursorTreeAdapter { */ @Override public View newGroupView(Context context, Cursor cursor, boolean isExpanded, ViewGroup parent) { - return mInflater.inflate(R.layout.key_list_group_item, null); + return mInflater.inflate(R.layout.key_list_item, 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 86a47d4d7..108fad917 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java @@ -81,7 +81,7 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.key_list_group_item, null); + return mInflater.inflate(R.layout.key_list_item, null); } @Override 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 6f3129e4f..6315f84fb 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java @@ -76,7 +76,7 @@ public class KeyListSecretAdapter extends CursorAdapter { @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.key_list_group_item, null); + return mInflater.inflate(R.layout.key_list_item, null); } } -- cgit v1.2.3 From 7b9b3d07bbb507823ec4621d37e2723460124e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 2 Jan 2014 22:36:57 +0100 Subject: final fixes for public key list --- .../keychain/ui/KeyListPublicFragment.java | 46 +++++++++++----------- .../keychain/ui/adapter/KeyListPublicAdapter.java | 7 ++-- 2 files changed, 28 insertions(+), 25 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index 84adaef99..7bc0bcd96 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -44,19 +44,28 @@ import com.actionbarsherlock.app.SherlockFragment; /** * Public key list with sticky list headers. * - * - uses StickyListHeaders library - custom adapter: KeyListPublicAdapter + * - uses StickyListHeaders library * - * TODO: - fix loader with spinning animation - fix design - fix view holder in adapter + * - custom adapter: KeyListPublicAdapter + * + * TODO: - fix view holder in adapter, fix loader * */ public class KeyListPublicFragment extends SherlockFragment implements AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks { private KeyListPublicActivity mKeyListPublicActivity; - private KeyListPublicAdapter mAdapter; + private StickyListHeadersListView mStickyList; - StickyListHeadersListView stickyList; + /** + * Load custom layout with StickyListView from library + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.key_list_public_fragment, container, false); + return view; + } /** * Define Adapter and Loader on create of Activity @@ -67,20 +76,17 @@ public class KeyListPublicFragment extends SherlockFragment implements super.onActivityCreated(savedInstanceState); mKeyListPublicActivity = (KeyListPublicActivity) getActivity(); + mStickyList = (StickyListHeadersListView) getActivity().findViewById(R.id.list); - stickyList = (StickyListHeadersListView) getActivity().findViewById(R.id.list); - - stickyList.setOnItemClickListener(this); - // stickyList.setOnHeaderClickListener(this); - // stickyList.setOnStickyHeaderOffsetChangedListener(this); + mStickyList.setOnItemClickListener(this); // mStickyList.addHeaderView(inflater.inflate(R.layout.list_header, null)); // mStickyList.addFooterView(inflater.inflate(R.layout.list_footer, null)); - stickyList.setEmptyView(getActivity().findViewById(R.id.empty)); - stickyList.setAreHeadersSticky(true); - stickyList.setDrawingListUnderStickyHeader(true); - stickyList.setFastScrollEnabled(true); + mStickyList.setEmptyView(getActivity().findViewById(R.id.empty)); + mStickyList.setAreHeadersSticky(true); + mStickyList.setDrawingListUnderStickyHeader(false); + mStickyList.setFastScrollEnabled(true); try { - stickyList.setFastScrollAlwaysVisible(true); + mStickyList.setFastScrollAlwaysVisible(true); } catch (ApiLevelTooLowException e) { } @@ -101,12 +107,6 @@ public class KeyListPublicFragment extends SherlockFragment implements getLoaderManager().initLoader(0, null, this); } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.key_list_public_fragment, container, false); - return view; - } - // These are the rows that we will retrieve. static final String[] PROJECTION = new String[] { KeyRings._ID, KeyRings.MASTER_KEY_ID, UserIds.USER_ID }; @@ -134,7 +134,7 @@ public class KeyListPublicFragment extends SherlockFragment implements mAdapter = new KeyListPublicAdapter(mKeyListPublicActivity, data, Id.type.public_key, userIdIndex); - stickyList.setAdapter(mAdapter); + mStickyList.setAdapter(mAdapter); // The list should now be shown. if (isResumed()) { @@ -152,9 +152,11 @@ public class KeyListPublicFragment extends SherlockFragment implements mAdapter.swapCursor(null); } + /** + * On click on item, start key view activity + */ @Override public void onItemClick(AdapterView adapterView, View view, int position, long id) { - // start key view on click Intent detailsIntent = new Intent(mKeyListPublicActivity, KeyViewActivity.class); detailsIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long.toString(id))); startActivity(detailsIntent); 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 108fad917..ef3a0d228 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java @@ -86,7 +86,6 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea @Override public View getHeaderView(int position, View convertView, ViewGroup parent) { - HeaderViewHolder holder; if (convertView == null) { holder = new HeaderViewHolder(); @@ -97,6 +96,7 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea holder = (HeaderViewHolder) convertView.getTag(); } + // similar to getView in CursorAdapter if (!mDataValid) { // no data available at this point Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); @@ -108,17 +108,18 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea throw new IllegalStateException("couldn't move cursor to position " + position); } - // set header text as first char in name + // set header text as first char in user id String headerText = "" + mCursor.getString(mSectionColumnIndex).subSequence(0, 1).charAt(0); holder.text.setText(headerText); return convertView; } /** - * Remember that these have to be static, position=1 should always return the same Id that is. + * Header IDs should be static, position=1 should always return the same Id that is. */ @Override public long getHeaderId(int position) { + // similar to getView in CursorAdapter if (!mDataValid) { // no data available at this point Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); -- cgit v1.2.3 From bc0edfda0bae21a567b9ea340cab323f9a15a086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 2 Jan 2014 22:45:24 +0100 Subject: fix nullpointer in EditKeyActivity --- .../keychain/ui/EditKeyActivity.java | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 7aeb51c8f..4dcaa6d73 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -295,17 +295,6 @@ public class EditKeyActivity extends SherlockFragmentActivity { } private void finallyEdit(final long masterKeyId, final boolean masterCanSign) { - // TODO: ??? - if (mCurrentPassPhrase == null) { - mCurrentPassPhrase = ""; - } - - if (mCurrentPassPhrase.equals("")) { - // check "no passphrase" checkbox and remove button - mNoPassphrase.setChecked(true); - mChangePassPhrase.setVisibility(View.GONE); - } - if (masterKeyId != 0) { PGPSecretKey masterKey = null; mKeyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(this, masterKeyId); @@ -328,6 +317,17 @@ public class EditKeyActivity extends SherlockFragmentActivity { } buildLayout(); + + // TODO: ??? + if (mCurrentPassPhrase == null) { + mCurrentPassPhrase = ""; + } + + if (mCurrentPassPhrase.equals("")) { + // check "no passphrase" checkbox and remove button + mNoPassphrase.setChecked(true); + mChangePassPhrase.setVisibility(View.GONE); + } } /** -- cgit v1.2.3 From 9576aeabca5453578f297d3546f2d3526eb377de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 2 Jan 2014 23:09:10 +0100 Subject: integrate share activity in view activity --- .../keychain/ui/KeyViewActivity.java | 69 ++++++++++++------- .../keychain/ui/ShareActivity.java | 79 ---------------------- 2 files changed, 44 insertions(+), 104 deletions(-) delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ShareActivity.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java index c2ef64d51..4a628a3c3 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java @@ -18,6 +18,7 @@ package org.sufficientlysecure.keychain.ui; +import java.util.ArrayList; import java.util.Date; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -29,20 +30,21 @@ import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment; import org.sufficientlysecure.keychain.util.Log; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.provider.ContactsContract.DataUsageFeedback; import android.text.format.DateFormat; import android.widget.TextView; import com.actionbarsherlock.app.SherlockActivity; +import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; -public class KeyViewActivity extends SherlockActivity { +public class KeyViewActivity extends SherlockFragmentActivity { private Uri mDataUri; private PGPPublicKey mPublicKey; @@ -136,32 +138,19 @@ public class KeyViewActivity extends SherlockActivity { return true; case R.id.menu_key_view_export_file: -// long masterKeyId = ProviderHelper.getPublicMasterKeyId(mKeyListActivity, keyRingRowId); -// if (masterKeyId == -1) { -// masterKeyId = ProviderHelper.getSecretMasterKeyId(mKeyListActivity, keyRingRowId); -// } -// -// mKeyListActivity.showExportKeysDialog(masterKeyId); + // long masterKeyId = ProviderHelper.getPublicMasterKeyId(mKeyListActivity, + // keyRingRowId); + // if (masterKeyId == -1) { + // masterKeyId = ProviderHelper.getSecretMasterKeyId(mKeyListActivity, keyRingRowId); + // } + // + // mKeyListActivity.showExportKeysDialog(masterKeyId); return true; case R.id.menu_key_view_share: - // get master key id using row id - long masterKeyId3 = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); - - Intent shareIntent = new Intent(this, ShareActivity.class); - shareIntent.setAction(ShareActivity.ACTION_SHARE_KEYRING); - shareIntent.putExtra(ShareActivity.EXTRA_MASTER_KEY_ID, masterKeyId3); - startActivityForResult(shareIntent, 0); - + shareKey(); return true; case R.id.menu_key_view_share_qr_code: - // get master key id using row id - long masterKeyId = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); - - Intent qrCodeIntent = new Intent(this, ShareActivity.class); - qrCodeIntent.setAction(ShareActivity.ACTION_SHARE_KEYRING_WITH_QR_CODE); - qrCodeIntent.putExtra(ShareActivity.EXTRA_MASTER_KEY_ID, masterKeyId); - startActivityForResult(qrCodeIntent, 0); - + shareKeyQrCode(); return true; case R.id.menu_key_view_share_nfc: // get master key id using row id @@ -174,7 +163,7 @@ public class KeyViewActivity extends SherlockActivity { return true; case R.id.menu_key_view_delete: -// mKeyListActivity.showDeleteKeyDialog(keyRingRowId); + // mKeyListActivity.showDeleteKeyDialog(keyRingRowId); return true; @@ -225,4 +214,34 @@ public class KeyViewActivity extends SherlockActivity { } return result; } + + private void shareKey() { + // TODO: use data uri! + long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); + long masterKeyId = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); + + // get public keyring as ascii armored string + ArrayList keyringArmored = ProviderHelper.getPublicKeyRingsAsArmoredString(this, + new long[] { masterKeyId }); + + // let user choose application + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, keyringArmored.get(0)); + sendIntent.setType("text/plain"); + startActivity(Intent.createChooser(sendIntent, + getResources().getText(R.string.action_share_key_with))); + } + + private void shareKeyQrCode() { + // TODO: use data uri! + long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); + long masterKeyId = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); + // get public keyring as ascii armored string + ArrayList keyringArmored = ProviderHelper.getPublicKeyRingsAsArmoredString(this, + new long[] { masterKeyId }); + + ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(keyringArmored + .get(0)); + dialog.show(getSupportFragmentManager(), "qrCodeShareDialog"); + } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ShareActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ShareActivity.java deleted file mode 100644 index 159b2b63a..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ShareActivity.java +++ /dev/null @@ -1,79 +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; - -import java.util.ArrayList; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment; - -import android.content.Intent; -import android.os.Bundle; - -import com.actionbarsherlock.app.SherlockFragmentActivity; - -public class ShareActivity extends SherlockFragmentActivity { - // Actions for internal use only: - public static final String ACTION_SHARE_KEYRING = Constants.INTENT_PREFIX + "SHARE_KEYRING"; - public static final String ACTION_SHARE_KEYRING_WITH_QR_CODE = Constants.INTENT_PREFIX - + "SHARE_KEYRING_WITH_QR_CODE"; - - public static final String EXTRA_MASTER_KEY_ID = "master_key_id"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - handleActions(getIntent()); - } - - protected void handleActions(Intent intent) { - String action = intent.getAction(); - Bundle extras = intent.getExtras(); - - if (extras == null) { - extras = new Bundle(); - } - - long masterKeyId = extras.getLong(EXTRA_MASTER_KEY_ID); - - // get public keyring as ascii armored string - ArrayList keyringArmored = ProviderHelper.getPublicKeyRingsAsArmoredString(this, - new long[] { masterKeyId }); - - if (ACTION_SHARE_KEYRING.equals(action)) { - // let user choose application - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_TEXT, keyringArmored.get(0)); - sendIntent.setType("text/plain"); - startActivity(Intent.createChooser(sendIntent, - getResources().getText(R.string.action_share_key_with))); - } else if (ACTION_SHARE_KEYRING_WITH_QR_CODE.equals(action)) { - ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(keyringArmored - .get(0)); - dialog.show(getSupportFragmentManager(), "qrCodeShareDialog"); - } - - // close this activity - // TODO: finish() would also close dialog... - // integrate this into new KeyViewActivity when ready - // finish(); - } -} -- cgit v1.2.3 From 15be9fc99b55889a175debb57185a6a75a34b1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 3 Jan 2014 12:24:08 +0100 Subject: integrate NFC into key view and import activities --- .../keychain/ui/ImportKeysActivity.java | 49 ++++- .../keychain/ui/KeyViewActivity.java | 117 ++++++++++- .../keychain/ui/ShareNfcBeamActivity.java | 226 --------------------- .../keychain/ui/dialog/ShareNfcDialogFragment.java | 101 +++++++++ 4 files changed, 252 insertions(+), 241 deletions(-) delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ShareNfcBeamActivity.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 37edc8f49..f83d469ac 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui; import java.util.ArrayList; import java.util.List; - import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.ActionBarHelper; @@ -29,21 +28,23 @@ import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; import org.sufficientlysecure.keychain.util.Log; - +import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.nfc.NdefMessage; +import android.nfc.NfcAdapter; import android.os.Bundle; import android.os.Message; import android.os.Messenger; +import android.os.Parcelable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Toast; - import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.ActionBar.OnNavigationListener; import com.actionbarsherlock.app.SherlockFragmentActivity; @@ -345,7 +346,8 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa int bad = returnData.getInt(KeychainIntentService.RESULT_IMPORT_BAD); String toastMessage; if (added > 0 && updated > 0) { - toastMessage = getString(R.string.keys_added_and_updated, added, updated); + toastMessage = getString(R.string.keys_added_and_updated, added, + updated); } else if (added > 0) { toastMessage = getString(R.string.keys_added, added); } else if (updated > 0) { @@ -409,4 +411,43 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa .show(); } + /** + * NFC + */ + @Override + public void onResume() { + super.onResume(); + // Check to see that the Activity started due to an Android Beam + if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { + handleActionNdefDiscovered(getIntent()); + } + } + + /** + * NFC + */ + @Override + public void onNewIntent(Intent intent) { + // onResume gets called after this to handle the intent + setIntent(intent); + } + + /** + * NFC: Parses the NDEF Message from the intent and prints to the TextView + */ + @SuppressLint("NewApi") + void handleActionNdefDiscovered(Intent intent) { + Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); + // only one message sent during the beam + NdefMessage msg = (NdefMessage) rawMsgs[0]; + // record 0 contains the MIME type, record 1 is the AAR, if present + byte[] receivedKeyringBytes = msg.getRecords()[0].getPayload(); + + Intent importIntent = new Intent(this, ImportKeysActivity.class); + importIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY); + importIntent.putExtra(ImportKeysActivity.EXTRA_KEY_BYTES, receivedKeyringBytes); + + handleActions(null, importIntent); + } + } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java index 4a628a3c3..ad63f022d 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java @@ -1,6 +1,6 @@ /* - * Copyright (C) 2013 Bahtiar 'kalkin' Gadimov * Copyright (C) 2013 Dominik Schürmann + * Copyright (C) 2013 Bahtiar 'kalkin' Gadimov * * 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 @@ -30,21 +30,34 @@ import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; 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 android.annotation.SuppressLint; import android.content.Intent; import android.net.Uri; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.nfc.NfcAdapter.CreateNdefMessageCallback; +import android.nfc.NfcAdapter.OnNdefPushCompleteCallback; +import android.nfc.NfcEvent; +import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; import android.text.format.DateFormat; import android.widget.TextView; +import android.widget.Toast; -import com.actionbarsherlock.app.SherlockActivity; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; -public class KeyViewActivity extends SherlockFragmentActivity { +@SuppressLint("NewApi") +public class KeyViewActivity extends SherlockFragmentActivity implements CreateNdefMessageCallback, + OnNdefPushCompleteCallback { private Uri mDataUri; private PGPPublicKey mPublicKey; @@ -54,6 +67,11 @@ public class KeyViewActivity extends SherlockFragmentActivity { private TextView mExpiry; private TextView mCreation; + // NFC + private NfcAdapter mNfcAdapter; + private byte[] mSharedKeyringBytes; + private static final int NFC_SENT = 1; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -77,6 +95,7 @@ public class KeyViewActivity extends SherlockFragmentActivity { } else { Log.d(Constants.TAG, "uri: " + mDataUri); loadData(mDataUri); + initNfc(); } } @@ -154,12 +173,14 @@ public class KeyViewActivity extends SherlockFragmentActivity { return true; case R.id.menu_key_view_share_nfc: // get master key id using row id - long masterKeyId2 = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); + // long masterKeyId2 = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); + // + // Intent nfcIntent = new Intent(this, ShareNfcBeamActivity.class); + // nfcIntent.setAction(ShareNfcBeamActivity.ACTION_SHARE_KEYRING_WITH_NFC); + // nfcIntent.putExtra(ShareNfcBeamActivity.EXTRA_MASTER_KEY_ID, masterKeyId2); + // startActivityForResult(nfcIntent, 0); - Intent nfcIntent = new Intent(this, ShareNfcBeamActivity.class); - nfcIntent.setAction(ShareNfcBeamActivity.ACTION_SHARE_KEYRING_WITH_NFC); - nfcIntent.putExtra(ShareNfcBeamActivity.EXTRA_MASTER_KEY_ID, masterKeyId2); - startActivityForResult(nfcIntent, 0); + shareNfc(); return true; case R.id.menu_key_view_delete: @@ -191,8 +212,10 @@ public class KeyViewActivity extends SherlockFragmentActivity { mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(mPublicKey)); } + /** + * TODO: does this duplicate functionality from elsewhere? put in helper! + */ private String[] splitUserId(String userId) { - String[] result = new String[] { "", "", "" }; Log.v("UserID", userId); @@ -219,7 +242,6 @@ public class KeyViewActivity extends SherlockFragmentActivity { // TODO: use data uri! long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); long masterKeyId = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); - // get public keyring as ascii armored string ArrayList keyringArmored = ProviderHelper.getPublicKeyRingsAsArmoredString(this, new long[] { masterKeyId }); @@ -242,6 +264,79 @@ public class KeyViewActivity extends SherlockFragmentActivity { ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(keyringArmored .get(0)); - dialog.show(getSupportFragmentManager(), "qrCodeShareDialog"); + dialog.show(getSupportFragmentManager(), "shareQrCodeDialog"); + } + + private void shareNfc() { + ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); + dialog.show(getSupportFragmentManager(), "shareNfcDialog"); + } + + /** + * NFC: Initialize NFC sharing if OS and device supports it + */ + private void initNfc() { + // check if NFC Beam is supported (>= Android 4.1) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + // Check for available NFC Adapter + mNfcAdapter = NfcAdapter.getDefaultAdapter(this); + if (mNfcAdapter != null) { + // init nfc + // TODO: use data uri! + long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); + long masterKeyId = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); + + // get public keyring as byte array + mSharedKeyringBytes = ProviderHelper.getPublicKeyRingsAsByteArray(this, + new long[] { masterKeyId }); + + // Register callback to set NDEF message + mNfcAdapter.setNdefPushMessageCallback(this, this); + // Register callback to listen for message-sent success + mNfcAdapter.setOnNdefPushCompleteCallback(this, this); + } + } + } + + /** + * NFC: Implementation for the CreateNdefMessageCallback interface + */ + @Override + public NdefMessage createNdefMessage(NfcEvent event) { + /** + * When a device receives a push with an AAR in it, the application specified in the AAR is + * guaranteed to run. The AAR overrides the tag dispatch system. You can add it back in to + * guarantee that this activity starts when receiving a beamed message. For now, this code + * uses the tag dispatch system. + */ + NdefMessage msg = new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME, + mSharedKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME)); + return msg; } + + /** + * NFC: Implementation for the OnNdefPushCompleteCallback interface + */ + @Override + public void onNdefPushComplete(NfcEvent arg0) { + // A handler is needed to send messages to the activity when this + // callback occurs, because it happens from a binder thread + mNfcHandler.obtainMessage(NFC_SENT).sendToTarget(); + } + + /** + * NFC: This handler receives a message from onNdefPushComplete + */ + private final Handler mNfcHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case NFC_SENT: + Toast.makeText(getApplicationContext(), R.string.nfc_successfull, Toast.LENGTH_LONG) + .show(); + break; + } + } + }; + } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ShareNfcBeamActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ShareNfcBeamActivity.java deleted file mode 100644 index db6a156c7..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ShareNfcBeamActivity.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * Copyright (C) 2011 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.ui; - -import org.sufficientlysecure.htmltextview.HtmlTextView; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; -import org.sufficientlysecure.keychain.provider.ProviderHelper; - -import android.annotation.TargetApi; -import android.content.Intent; -import android.nfc.NdefMessage; -import android.nfc.NdefRecord; -import android.nfc.NfcAdapter; -import android.nfc.NfcAdapter.CreateNdefMessageCallback; -import android.nfc.NfcAdapter.OnNdefPushCompleteCallback; -import android.nfc.NfcEvent; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Parcelable; -import android.provider.Settings; -import android.widget.Toast; - -import com.actionbarsherlock.app.SherlockFragmentActivity; -import com.actionbarsherlock.view.Menu; -import com.actionbarsherlock.view.MenuInflater; -import com.actionbarsherlock.view.MenuItem; - -@TargetApi(Build.VERSION_CODES.JELLY_BEAN) -public class ShareNfcBeamActivity extends SherlockFragmentActivity implements - CreateNdefMessageCallback, OnNdefPushCompleteCallback { - public static final String ACTION_SHARE_KEYRING_WITH_NFC = Constants.INTENT_PREFIX - + "SHARE_KEYRING_WITH_NFC"; - - public static final String EXTRA_MASTER_KEY_ID = "master_key_id"; - - NfcAdapter mNfcAdapter; - - byte[] mSharedKeyringBytes; - - private static final int MESSAGE_SENT = 1; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { - Toast.makeText(this, - getString(R.string.error) + ": " + getString(R.string.error_jelly_bean_needed), - Toast.LENGTH_LONG).show(); - finish(); - } else { - // Check for available NFC Adapter - mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - if (mNfcAdapter == null) { - Toast.makeText(this, - getString(R.string.error) + ": " + getString(R.string.error_nfc_needed), - Toast.LENGTH_LONG).show(); - finish(); - } else { - // handle actions after verifying that nfc works... - handleActions(getIntent()); - } - } - } - - protected void handleActions(Intent intent) { - String action = intent.getAction(); - Bundle extras = intent.getExtras(); - - if (extras == null) { - extras = new Bundle(); - } - - if (ACTION_SHARE_KEYRING_WITH_NFC.equals(action)) { - long masterKeyId = extras.getLong(EXTRA_MASTER_KEY_ID); - - // get public keyring as byte array - mSharedKeyringBytes = ProviderHelper.getPublicKeyRingsAsByteArray(this, - new long[] { masterKeyId }); - - // Register callback to set NDEF message - mNfcAdapter.setNdefPushMessageCallback(this, this); - // Register callback to listen for message-sent success - mNfcAdapter.setOnNdefPushCompleteCallback(this, this); - } - } - - /** - * Parses the NDEF Message from the intent and prints to the TextView - */ - void handleActionNdefDiscovered(Intent intent) { - Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); - // only one message sent during the beam - NdefMessage msg = (NdefMessage) rawMsgs[0]; - // record 0 contains the MIME type, record 1 is the AAR, if present - byte[] receivedKeyringBytes = msg.getRecords()[0].getPayload(); - - Intent importIntent = new Intent(this, ImportKeysActivity.class); - importIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY); - importIntent.putExtra(ImportKeysActivity.EXTRA_KEY_BYTES, receivedKeyringBytes); - - finish(); - - startActivity(importIntent); - } - - private void buildView() { - setContentView(R.layout.share_nfc_beam); - - HtmlTextView aboutTextView = (HtmlTextView) findViewById(R.id.nfc_beam_text); - - // load html from raw resource (Parsing handled by HtmlTextView library) - aboutTextView.setHtmlFromRawResource(this, R.raw.nfc_beam_share); - - // no flickering when clicking textview for Android < 4 - aboutTextView.setTextColor(getResources().getColor(android.R.color.black)); - - // set actionbar without home button if called from another app - ActionBarHelper.setBackButton(this); - } - - /** - * Implementation for the CreateNdefMessageCallback interface - */ - @Override - public NdefMessage createNdefMessage(NfcEvent event) { - /** - * When a device receives a push with an AAR in it, the application specified in the AAR is - * guaranteed to run. The AAR overrides the tag dispatch system. You can add it back in to - * guarantee that this activity starts when receiving a beamed message. For now, this code - * uses the tag dispatch system. - */ - NdefMessage msg = new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME, - mSharedKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME)); - return msg; - } - - /** - * Implementation for the OnNdefPushCompleteCallback interface - */ - @Override - public void onNdefPushComplete(NfcEvent arg0) { - // A handler is needed to send messages to the activity when this - // callback occurs, because it happens from a binder thread - mHandler.obtainMessage(MESSAGE_SENT).sendToTarget(); - } - - /** This handler receives a message from onNdefPushComplete */ - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_SENT: - Toast.makeText(getApplicationContext(), R.string.nfc_successfull, Toast.LENGTH_LONG) - .show(); - break; - } - } - }; - - @Override - public void onResume() { - super.onResume(); - // Check to see that the Activity started due to an Android Beam - if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { - handleActionNdefDiscovered(getIntent()); - } else { - // build view only when sending nfc, not when receiving, as it gets directly into Import - // activity on receiving - buildView(); - } - } - - @Override - public void onNewIntent(Intent intent) { - // onResume gets called after this to handle the intent - setIntent(intent); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getSupportMenuInflater(); - inflater.inflate(R.menu.nfc_beam, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - - case android.R.id.home: - // app icon in Action Bar clicked; go to KeyListPublicActivity - Intent intent = new Intent(this, KeyListPublicActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - - case R.id.menu_settings: - Intent intentSettings = new Intent(Settings.ACTION_NFCSHARING_SETTINGS); - startActivity(intentSettings); - return true; - - default: - return super.onOptionsItemSelected(item); - } - } -} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java new file mode 100644 index 000000000..1a19390ad --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java @@ -0,0 +1,101 @@ +/* + * 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.dialog; + +import org.sufficientlysecure.htmltextview.HtmlTextView; +import org.sufficientlysecure.keychain.R; + +import android.annotation.TargetApi; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.nfc.NfcAdapter; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentActivity; + +@TargetApi(Build.VERSION_CODES.JELLY_BEAN) +public class ShareNfcDialogFragment extends DialogFragment { + + /** + * Creates new instance of this fragment + */ + public static ShareNfcDialogFragment newInstance() { + ShareNfcDialogFragment frag = new ShareNfcDialogFragment(); + + return frag; + } + + /** + * Creates dialog + */ + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final FragmentActivity activity = getActivity(); + + AlertDialog.Builder alert = new AlertDialog.Builder(activity); + + alert.setIcon(android.R.drawable.ic_dialog_alert); + alert.setTitle(R.string.warning); + alert.setCancelable(true); + + alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + dismiss(); + } + }); + + HtmlTextView textView = new HtmlTextView(getActivity()); + textView.setPadding(8, 8, 8, 8); + alert.setView(textView); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + textView.setText(getString(R.string.error) + ": " + + getString(R.string.error_jelly_bean_needed)); + } else { + // check if NFC Adapter is available + NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity()); + if (nfcAdapter == null) { + textView.setText(getString(R.string.error) + ": " + + getString(R.string.error_nfc_needed)); + } else { + // nfc works... + textView.setHtmlFromRawResource(getActivity(), R.raw.nfc_beam_share); + + alert.setNegativeButton(R.string.menu_beam_preferences, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + Intent intentSettings = new Intent( + Settings.ACTION_NFCSHARING_SETTINGS); + startActivity(intentSettings); + } + }); + } + } + + // no flickering when clicking textview for Android < 4 + // aboutTextView.setTextColor(getResources().getColor(android.R.color.black)); + + return alert.create(); + } +} \ No newline at end of file -- cgit v1.2.3 From 606caee145bfdb706a23e29b6b0434b66519a47d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 3 Jan 2014 12:28:03 +0100 Subject: prettify nfc dialog --- .../sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java index 1a19390ad..03e09cdcb 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java @@ -53,8 +53,8 @@ public class ShareNfcDialogFragment extends DialogFragment { AlertDialog.Builder alert = new AlertDialog.Builder(activity); - alert.setIcon(android.R.drawable.ic_dialog_alert); - alert.setTitle(R.string.warning); + alert.setIcon(android.R.drawable.ic_dialog_info); + alert.setTitle(R.string.share_nfc_dialog); alert.setCancelable(true); alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { -- cgit v1.2.3 From 0e4cfed9691118080506d55270842e2ba127c878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 3 Jan 2014 18:07:42 +0100 Subject: cleanup and documentation --- .../keychain/ui/KeyListPublicFragment.java | 44 +++++++++------------- .../keychain/ui/adapter/KeyListPublicAdapter.java | 29 +++++++------- 2 files changed, 32 insertions(+), 41 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index 7bc0bcd96..27461875a 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -42,14 +42,8 @@ import android.widget.AdapterView; import com.actionbarsherlock.app.SherlockFragment; /** - * Public key list with sticky list headers. - * - * - uses StickyListHeaders library - * - * - custom adapter: KeyListPublicAdapter - * - * TODO: - fix view holder in adapter, fix loader - * + * 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 KeyListPublicFragment extends SherlockFragment implements AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks { @@ -79,9 +73,6 @@ public class KeyListPublicFragment extends SherlockFragment implements mStickyList = (StickyListHeadersListView) getActivity().findViewById(R.id.list); mStickyList.setOnItemClickListener(this); - // mStickyList.addHeaderView(inflater.inflate(R.layout.list_header, null)); - // mStickyList.addFooterView(inflater.inflate(R.layout.list_footer, null)); - mStickyList.setEmptyView(getActivity().findViewById(R.id.empty)); mStickyList.setAreHeadersSticky(true); mStickyList.setDrawingListUnderStickyHeader(false); mStickyList.setFastScrollEnabled(true); @@ -90,17 +81,17 @@ public class KeyListPublicFragment extends SherlockFragment implements } catch (ApiLevelTooLowException e) { } - // Give some text to display if there is no data. In a real - // application this would come from a resource. - // setEmptyText(getString(R.string.list_empty)); + // this view is made visible if no data is available + mStickyList.setEmptyView(getActivity().findViewById(R.id.empty)); + // NOTE: Not supported by StickyListHeader, thus no indicator is shown while loading // Start out with a progress indicator. // setListShown(false); // Create an empty adapter we will use to display the loaded data. - // mAdapter = new KeyListPublicAdapter(mKeyListPublicActivity, null, Id.type.public_key); - // setListAdapter(mAdapter); - // stickyList.setAdapter(mAdapter); + mAdapter = new KeyListPublicAdapter(mKeyListPublicActivity, null, Id.type.public_key, + USER_ID_INDEX); + mStickyList.setAdapter(mAdapter); // Prepare the loader. Either re-connect with an existing one, // or start a new one. @@ -111,6 +102,8 @@ public class KeyListPublicFragment extends SherlockFragment implements static final String[] PROJECTION = new String[] { KeyRings._ID, KeyRings.MASTER_KEY_ID, UserIds.USER_ID }; + static final int USER_ID_INDEX = 2; + static final String SORT_ORDER = UserIds.USER_ID + " ASC"; @Override @@ -128,20 +121,17 @@ public class KeyListPublicFragment extends SherlockFragment implements 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.) - // mAdapter.swapCursor(data); - int userIdIndex = data.getColumnIndex(UserIds.USER_ID); - - mAdapter = new KeyListPublicAdapter(mKeyListPublicActivity, data, Id.type.public_key, - userIdIndex); + mAdapter.swapCursor(data); mStickyList.setAdapter(mAdapter); + // NOTE: Not supported by StickyListHeader, thus no indicator is shown while loading // The list should now be shown. - if (isResumed()) { - // setListShown(true); - } else { - // setListShownNoAnimation(true); - } + // if (isResumed()) { + // setListShown(true); + // } else { + // setListShownNoAnimation(true); + // } } @Override 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 ef3a0d228..83c46021c 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java @@ -33,13 +33,11 @@ import android.view.ViewGroup; import android.widget.TextView; /** - * - implements StickyListHeadersAdapter from library - uses view holder pattern for performance - * + * Implements StickyListHeadersAdapter from library */ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHeadersAdapter { private LayoutInflater mInflater; - - int mSectionColumnIndex; + private int mSectionColumnIndex; public KeyListPublicAdapter(Context context, Cursor c, int flags, int sectionColumnIndex) { super(context, c, flags); @@ -48,9 +46,14 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea mSectionColumnIndex = sectionColumnIndex; } + /** + * Bind cursor data to the item list view + * + * NOTE: CursorAdapter already implements the ViewHolder pattern in its getView() method. Thus + * no ViewHolder is required here. + */ @Override public void bindView(View view, Context context, Cursor cursor) { - // TODO: view holder pattern? int userIdIndex = cursor.getColumnIndex(UserIds.USER_ID); TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); @@ -84,6 +87,13 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea return mInflater.inflate(R.layout.key_list_item, null); } + /** + * Creates a new header view and binds the section headers to it. It uses the ViewHolder + * pattern. Most functionality is similar to getView() from Android's CursorAdapter. + * + * NOTE: The variables mDataValid and mCursor are available due to the super class + * CursorAdapter. + */ @Override public View getHeaderView(int position, View convertView, ViewGroup parent) { HeaderViewHolder holder; @@ -96,14 +106,12 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea holder = (HeaderViewHolder) convertView.getTag(); } - // similar to getView in CursorAdapter if (!mDataValid) { // no data available at this point Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); return convertView; } - // similar to getView in CursorAdapter if (!mCursor.moveToPosition(position)) { throw new IllegalStateException("couldn't move cursor to position " + position); } @@ -119,14 +127,12 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea */ @Override public long getHeaderId(int position) { - // similar to getView in CursorAdapter if (!mDataValid) { // no data available at this point Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); return -1; } - // similar to getView in CursorAdapter if (!mCursor.moveToPosition(position)) { throw new IllegalStateException("couldn't move cursor to position " + position); } @@ -140,9 +146,4 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea TextView text; } - class ViewHolder { - TextView mainUserId; - TextView mainUserIdRest; - } - } -- cgit v1.2.3 From 28d9a2f26b71158823d73451bf25e1f5cf0c5431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 3 Jan 2014 18:33:44 +0100 Subject: reorder menu in key view --- .../src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java index ad63f022d..45c79fc8e 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java @@ -165,7 +165,7 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN // // mKeyListActivity.showExportKeysDialog(masterKeyId); return true; - case R.id.menu_key_view_share: + case R.id.menu_key_view_share_default: shareKey(); return true; case R.id.menu_key_view_share_qr_code: -- cgit v1.2.3 From 708baaa68c76391a3e15cd086d3829eb058819c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 6 Jan 2014 00:58:04 +0100 Subject: Work on multiselect in key list --- .../keychain/ui/KeyListActivity.java | 6 +- .../keychain/ui/KeyListPublicFragment.java | 117 ++++++++- .../keychain/ui/adapter/KeyListAdapter.java | 273 --------------------- .../keychain/ui/adapter/KeyListPublicAdapter.java | 53 +++- .../keychain/ui/adapter/KeyListSecretAdapter.java | 5 - .../ui/dialog/DeleteKeyDialogFragment.java | 52 ++-- 6 files changed, 198 insertions(+), 308 deletions(-) delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapter.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListActivity.java index 4d1849029..5b69f9218 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListActivity.java @@ -225,9 +225,9 @@ public class KeyListActivity extends SherlockFragmentActivity { /** * Show dialog to delete key * - * @param keyRingId + * @param keyRingIds */ - public void showDeleteKeyDialog(long keyRingId) { + public void showDeleteKeyDialog(long[] keyRingIds) { // Message is received after key is deleted Handler returnHandler = new Handler() { @Override @@ -242,7 +242,7 @@ public class KeyListActivity extends SherlockFragmentActivity { Messenger messenger = new Messenger(returnHandler); DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, - keyRingId, mKeyType); + keyRingIds, mKeyType); deleteKeyDialog.show(getSupportFragmentManager(), "deleteKeyDialog"); } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index 27461875a..ed8427fd0 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -17,12 +17,16 @@ package org.sufficientlysecure.keychain.ui; +import java.util.ArrayList; +import java.util.Set; + import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.ui.adapter.KeyListPublicAdapter; +import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import se.emilsjolander.stickylistheaders.ApiLevelTooLowException; import se.emilsjolander.stickylistheaders.StickyListHeadersListView; @@ -30,23 +34,32 @@ import android.annotation.SuppressLint; import android.content.Intent; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; +import android.provider.BaseColumns; +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.ActionMode; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; - -import com.actionbarsherlock.app.SherlockFragment; +import android.widget.ListView; /** * 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 KeyListPublicFragment extends SherlockFragment implements - AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks { +public class KeyListPublicFragment extends Fragment implements AdapterView.OnItemClickListener, + LoaderManager.LoaderCallbacks { private KeyListPublicActivity mKeyListPublicActivity; private KeyListPublicAdapter mAdapter; @@ -84,6 +97,73 @@ public class KeyListPublicFragment extends SherlockFragment implements // this view is made visible if no data is available mStickyList.setEmptyView(getActivity().findViewById(R.id.empty)); + /* + * ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only + * available for Android >= 3.0 + */ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); + mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() { + + private int count = 0; + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + android.view.MenuInflater inflater = getActivity().getMenuInflater(); + inflater.inflate(R.menu.key_list_multi_selection, menu); + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + // StringBuilder sb = new StringBuilder(); + Set positions = mAdapter.getCurrentCheckedPosition(); + // for (Integer pos : positions) { + // sb.append(" " + pos + ","); + // } + switch (item.getItemId()) { + case R.id.delete_entry: + long[] ids = new long[positions.size()]; + for (int i=0; i < positions.size(); i++) { + ids[i] = mAdapter.getItemId(positions.); + } + showDeleteKeyDialog(ids.to); + + break; + } + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + count = 0; + mAdapter.clearSelection(); + } + + @Override + public void onItemCheckedStateChanged(ActionMode mode, int position, long id, + boolean checked) { + if (checked) { + count++; + mAdapter.setNewSelection(position, checked); + } else { + count--; + mAdapter.removeSelection(position); + } + + String keysSelected = getResources().getQuantityString( + R.plurals.key_list_selected_keys, count, count); + mode.setTitle(keysSelected); + } + + }); + } + // NOTE: Not supported by StickyListHeader, thus no indicator is shown while loading // Start out with a progress indicator. // setListShown(false); @@ -152,4 +232,31 @@ public class KeyListPublicFragment extends SherlockFragment implements startActivity(detailsIntent); } -} + /** + * Show dialog to delete key + * + * TODO: no messenger needed etc! + * + * @param keyRingRowIds + */ + public void showDeleteKeyDialog(long[] keyRingRowIds) { + // Message is received after key is deleted + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { + // no further actions needed + } + } + }; + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(returnHandler); + + DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, + keyRingRowIds, Id.type.public_key); + + deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog"); + } + +} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapter.java deleted file mode 100644 index 4719d1d1c..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapter.java +++ /dev/null @@ -1,273 +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.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 org.sufficientlysecure.keychain.R; - -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.LinearLayout; -import android.widget.TextView; - -public class KeyListAdapter 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 KeyListAdapter(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); - } - -} 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 83c46021c..5f71c9805 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java @@ -17,15 +17,18 @@ 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.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.util.Log; - import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; +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; @@ -39,6 +42,9 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea private LayoutInflater mInflater; private int mSectionColumnIndex; + @SuppressLint("UseSparseArrays") + private HashMap mSelection = new HashMap(); + public KeyListPublicAdapter(Context context, Cursor c, int flags, int sectionColumnIndex) { super(context, c, flags); @@ -138,7 +144,8 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea } // return the first character of the name as ID because this is what - // headers are based upon + // headers private HashMap mSelection = new HashMap();are based upon return mCursor.getString(mSectionColumnIndex).subSequence(0, 1).charAt(0); } @@ -146,4 +153,46 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea TextView text; } + /** -------------------------- MULTI-SELECTION METHODS -------------- */ + public void setNewSelection(int position, boolean value) { + mSelection.put(position, value); + notifyDataSetChanged(); + } + + public boolean isPositionChecked(int position) { + Boolean result = mSelection.get(position); + return result == null ? false : result; + } + + public Set getCurrentCheckedPosition() { + return mSelection.keySet(); + } + + public void removeSelection(int position) { + mSelection.remove(position); + notifyDataSetChanged(); + } + + public void clearSelection() { + mSelection.clear(); + notifyDataSetChanged(); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + // let the adapter handle setting up the row views + View v = super.getView(position, convertView, parent); + + /** + * Change color for multi-selection + */ + // default color + v.setBackgroundColor(Color.TRANSPARENT); + if (mSelection.get(position) != null) { + // this is a selected position, change color! + v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis)); + } + return v; + } + } 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 6315f84fb..2fda8a9f7 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java @@ -19,19 +19,14 @@ package org.sufficientlysecure.keychain.ui.adapter; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.OtherHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; 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 KeyListSecretAdapter extends CursorAdapter { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java index 638702b57..101167777 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java @@ -38,7 +38,7 @@ import android.support.v4.app.FragmentActivity; public class DeleteKeyDialogFragment extends DialogFragment { private static final String ARG_MESSENGER = "messenger"; - private static final String ARG_DELETE_KEY_RING_ROW_ID = "delete_file"; + private static final String ARG_DELETE_KEY_RING_ROW_IDS = "delete_file"; private static final String ARG_KEY_TYPE = "key_type"; public static final int MESSAGE_OKAY = 1; @@ -48,13 +48,13 @@ public class DeleteKeyDialogFragment extends DialogFragment { /** * Creates new instance of this delete file dialog fragment */ - public static DeleteKeyDialogFragment newInstance(Messenger messenger, long deleteKeyRingRowId, + public static DeleteKeyDialogFragment newInstance(Messenger messenger, long[] keyRingRowIds, int keyType) { DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment(); Bundle args = new Bundle(); args.putParcelable(ARG_MESSENGER, messenger); - args.putLong(ARG_DELETE_KEY_RING_ROW_ID, deleteKeyRingRowId); + args.putLongArray(ARG_DELETE_KEY_RING_ROW_IDS, keyRingRowIds); args.putInt(ARG_KEY_TYPE, keyType); frag.setArguments(args); @@ -70,36 +70,48 @@ public class DeleteKeyDialogFragment extends DialogFragment { final FragmentActivity activity = getActivity(); mMessenger = getArguments().getParcelable(ARG_MESSENGER); - final long deleteKeyRingRowId = getArguments().getLong(ARG_DELETE_KEY_RING_ROW_ID); + final long[] keyRingRowIds = getArguments().getLongArray(ARG_DELETE_KEY_RING_ROW_IDS); final int keyType = getArguments().getInt(ARG_KEY_TYPE); - // TODO: better way to do this? - String userId = activity.getString(R.string.unknown_user_id); + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(R.string.warning); + + if (keyRingRowIds.length == 1) { + // TODO: better way to do this? + String userId = activity.getString(R.string.unknown_user_id); + + if (keyType == Id.type.public_key) { + PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRingByRowId(activity, + keyRingRowIds[0]); + userId = PgpKeyHelper.getMainUserIdSafe(activity, + PgpKeyHelper.getMasterKey(keyRing)); + } else { + PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByRowId(activity, + keyRingRowIds[0]); + userId = PgpKeyHelper.getMainUserIdSafe(activity, + PgpKeyHelper.getMasterKey(keyRing)); + } - if (keyType == Id.type.public_key) { - PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRingByRowId(activity, - deleteKeyRingRowId); - userId = PgpKeyHelper.getMainUserIdSafe(activity, PgpKeyHelper.getMasterKey(keyRing)); + builder.setMessage(getString( + keyType == Id.type.public_key ? R.string.key_deletion_confirmation + : R.string.secret_key_deletion_confirmation, userId)); } else { - PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByRowId(activity, - deleteKeyRingRowId); - userId = PgpKeyHelper.getMainUserIdSafe(activity, PgpKeyHelper.getMasterKey(keyRing)); + builder.setMessage(R.string.key_deletion_confirmation_multi); } - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setTitle(R.string.warning); - builder.setMessage(getString( - keyType == Id.type.public_key ? R.string.key_deletion_confirmation - : R.string.secret_key_deletion_confirmation, userId)); builder.setIcon(android.R.drawable.ic_dialog_alert); builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { if (keyType == Id.type.public_key) { - ProviderHelper.deletePublicKeyRing(activity, deleteKeyRingRowId); + for (long keyRowId : keyRingRowIds) { + ProviderHelper.deletePublicKeyRing(activity, keyRowId); + } } else { - ProviderHelper.deleteSecretKeyRing(activity, deleteKeyRingRowId); + for (long keyRowId : keyRingRowIds) { + ProviderHelper.deleteSecretKeyRing(activity, keyRowId); + } } dismiss(); -- cgit v1.2.3 From de496deffa77c1297c11131894f9ec942d9d8115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 6 Jan 2014 14:35:14 +0100 Subject: multi select and delete, needs testing --- .../keychain/ui/KeyListPublicFragment.java | 16 +- .../keychain/ui/adapter/KeyListAdapterOLD.java | 273 +++++++++++++++++++++ 2 files changed, 280 insertions(+), 9 deletions(-) create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapterOLD.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index ed8427fd0..f0a009482 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -17,7 +17,6 @@ package org.sufficientlysecure.keychain.ui; -import java.util.ArrayList; import java.util.Set; import org.sufficientlysecure.keychain.Id; @@ -39,7 +38,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Messenger; -import android.provider.BaseColumns; import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; @@ -121,18 +119,18 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - // StringBuilder sb = new StringBuilder(); Set positions = mAdapter.getCurrentCheckedPosition(); - // for (Integer pos : positions) { - // sb.append(" " + pos + ","); - // } switch (item.getItemId()) { case R.id.delete_entry: + + // get IDs for checked positions as long array long[] ids = new long[positions.size()]; - for (int i=0; i < positions.size(); i++) { - ids[i] = mAdapter.getItemId(positions.); + int i = 0; + for (int pos : positions) { + ids[i] = mAdapter.getItemId(pos); + i++; } - showDeleteKeyDialog(ids.to); + showDeleteKeyDialog(ids); break; } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapterOLD.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapterOLD.java new file mode 100644 index 000000000..0c709d25a --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapterOLD.java @@ -0,0 +1,273 @@ +/* + * 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.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 org.sufficientlysecure.keychain.R; + +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.LinearLayout; +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); + } + +} -- cgit v1.2.3 From 7671c99b97ebf62b797ee69ef8412c973199c9f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 6 Jan 2014 20:30:22 +0100 Subject: copy to clipboard in key view --- .../keychain/ui/KeyViewActivity.java | 148 +++++++++++++-------- 1 file changed, 89 insertions(+), 59 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java index 45c79fc8e..4bffd9f3d 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java @@ -28,6 +28,7 @@ import org.spongycastle.openpgp.PGPPublicKeyRing; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; @@ -108,62 +109,18 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN @Override public boolean onOptionsItemSelected(MenuItem item) { - // TODO: use data uri in the other activities instead of givin key ring row id! - - long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); - switch (item.getItemId()) { case R.id.menu_key_view_update: - long updateKeyId = 0; - PGPPublicKeyRing updateKeyRing = ProviderHelper.getPGPPublicKeyRingByRowId(this, - keyRingRowId); - if (updateKeyRing != null) { - updateKeyId = PgpKeyHelper.getMasterKey(updateKeyRing).getKeyID(); - } - if (updateKeyId == 0) { - // this shouldn't happen - return true; - } - - Intent queryIntent = new Intent(this, KeyServerQueryActivity.class); - queryIntent.setAction(KeyServerQueryActivity.ACTION_LOOK_UP_KEY_ID_AND_RETURN); - queryIntent.putExtra(KeyServerQueryActivity.EXTRA_KEY_ID, updateKeyId); - - // TODO: lookup?? - startActivityForResult(queryIntent, Id.request.look_up_key_id); - + updateFromKeyserver(); return true; case R.id.menu_key_view_sign: - long keyId = 0; - PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByRowId(this, - keyRingRowId); - if (signKeyRing != null) { - keyId = PgpKeyHelper.getMasterKey(signKeyRing).getKeyID(); - } - if (keyId == 0) { - // this shouldn't happen - return true; - } - - Intent signIntent = new Intent(this, SignKeyActivity.class); - signIntent.putExtra(SignKeyActivity.EXTRA_KEY_ID, keyId); - startActivity(signIntent); + signKey(); return true; case R.id.menu_key_view_export_keyserver: - Intent uploadIntent = new Intent(this, KeyServerUploadActivity.class); - uploadIntent.setAction(KeyServerUploadActivity.ACTION_EXPORT_KEY_TO_SERVER); - uploadIntent.putExtra(KeyServerUploadActivity.EXTRA_KEYRING_ROW_ID, (int) keyRingRowId); - startActivityForResult(uploadIntent, Id.request.export_to_server); - + uploadToKeyserver(); return true; case R.id.menu_key_view_export_file: - // long masterKeyId = ProviderHelper.getPublicMasterKeyId(mKeyListActivity, - // keyRingRowId); - // if (masterKeyId == -1) { - // masterKeyId = ProviderHelper.getSecretMasterKeyId(mKeyListActivity, keyRingRowId); - // } - // - // mKeyListActivity.showExportKeysDialog(masterKeyId); + exportToFile(); return true; case R.id.menu_key_view_share_default: shareKey(); @@ -172,20 +129,13 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN shareKeyQrCode(); return true; case R.id.menu_key_view_share_nfc: - // get master key id using row id - // long masterKeyId2 = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); - // - // Intent nfcIntent = new Intent(this, ShareNfcBeamActivity.class); - // nfcIntent.setAction(ShareNfcBeamActivity.ACTION_SHARE_KEYRING_WITH_NFC); - // nfcIntent.putExtra(ShareNfcBeamActivity.EXTRA_MASTER_KEY_ID, masterKeyId2); - // startActivityForResult(nfcIntent, 0); - shareNfc(); - + return true; + case R.id.menu_key_view_share_clipboard: + copyToClipboard(); return true; case R.id.menu_key_view_delete: - // mKeyListActivity.showDeleteKeyDialog(keyRingRowId); - + deleteKey(); return true; } @@ -238,6 +188,75 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN return result; } + private void exportToFile() { + // long masterKeyId = ProviderHelper.getPublicMasterKeyId(mKeyListActivity, + // keyRingRowId); + // if (masterKeyId == -1) { + // masterKeyId = ProviderHelper.getSecretMasterKeyId(mKeyListActivity, keyRingRowId); + // } + // + // mKeyListActivity.showExportKeysDialog(masterKeyId); + } + + private void deleteKey() { + long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); + + // mKeyListActivity.showDeleteKeyDialog(keyRingRowId); + } + + private void uploadToKeyserver() { + long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); + + Intent uploadIntent = new Intent(this, KeyServerUploadActivity.class); + uploadIntent.setAction(KeyServerUploadActivity.ACTION_EXPORT_KEY_TO_SERVER); + uploadIntent.putExtra(KeyServerUploadActivity.EXTRA_KEYRING_ROW_ID, (int) keyRingRowId); + startActivityForResult(uploadIntent, Id.request.export_to_server); + } + + private void updateFromKeyserver() { + // TODO: use data uri! + long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); + + long updateKeyId = 0; + PGPPublicKeyRing updateKeyRing = ProviderHelper.getPGPPublicKeyRingByRowId(this, + keyRingRowId); + if (updateKeyRing != null) { + updateKeyId = PgpKeyHelper.getMasterKey(updateKeyRing).getKeyID(); + } + // if (updateKeyId == 0) { + // // this shouldn't happen + // return true; + // } + + Intent queryIntent = new Intent(this, KeyServerQueryActivity.class); + queryIntent.setAction(KeyServerQueryActivity.ACTION_LOOK_UP_KEY_ID_AND_RETURN); + queryIntent.putExtra(KeyServerQueryActivity.EXTRA_KEY_ID, updateKeyId); + + // TODO: lookup?? + startActivityForResult(queryIntent, Id.request.look_up_key_id); + + } + + private void signKey() { + // TODO: use data uri! + long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); + + long keyId = 0; + PGPPublicKeyRing signKeyRing = ProviderHelper + .getPGPPublicKeyRingByRowId(this, keyRingRowId); + if (signKeyRing != null) { + keyId = PgpKeyHelper.getMasterKey(signKeyRing).getKeyID(); + } + // if (keyId == 0) { + // // this shouldn't happen + // return true; + // } + + Intent signIntent = new Intent(this, SignKeyActivity.class); + signIntent.putExtra(SignKeyActivity.EXTRA_KEY_ID, keyId); + startActivity(signIntent); + } + private void shareKey() { // TODO: use data uri! long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); @@ -272,6 +291,17 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN dialog.show(getSupportFragmentManager(), "shareNfcDialog"); } + private void copyToClipboard() { + // TODO: use data uri! + long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); + long masterKeyId = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); + // get public keyring as ascii armored string + ArrayList keyringArmored = ProviderHelper.getPublicKeyRingsAsArmoredString(this, + new long[] { masterKeyId }); + + ClipboardReflection.copyToClipboard(this, keyringArmored.get(0)); + } + /** * NFC: Initialize NFC sharing if OS and device supports it */ -- cgit v1.2.3 From ccb462e94fffea71649e93dd4d91ef3748f5c726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 6 Jan 2014 22:52:45 +0100 Subject: externalize zxing lib, fix gradle build --- .../src/com/google/zxing/BarcodeFormat.java | 106 ---- .../src/com/google/zxing/Binarizer.java | 80 --- .../src/com/google/zxing/BinaryBitmap.java | 128 ----- .../src/com/google/zxing/ChecksumException.java | 37 -- .../src/com/google/zxing/DecodeHintType.java | 79 --- .../src/com/google/zxing/EncodeHintType.java | 39 -- .../src/com/google/zxing/FormatException.java | 38 -- .../src/com/google/zxing/LuminanceSource.java | 113 ---- .../src/com/google/zxing/NotFoundException.java | 37 -- OpenPGP-Keychain/src/com/google/zxing/Reader.java | 64 --- .../src/com/google/zxing/ReaderException.java | 98 ---- OpenPGP-Keychain/src/com/google/zxing/Result.java | 143 ----- .../src/com/google/zxing/ResultMetadataType.java | 109 ---- .../src/com/google/zxing/ResultPoint.java | 129 ----- .../src/com/google/zxing/ResultPointCallback.java | 29 - OpenPGP-Keychain/src/com/google/zxing/Writer.java | 54 -- .../src/com/google/zxing/WriterException.java | 35 -- .../src/com/google/zxing/common/BitArray.java | 246 --------- .../src/com/google/zxing/common/BitMatrix.java | 247 --------- .../src/com/google/zxing/common/BitSource.java | 97 ---- .../com/google/zxing/common/CharacterSetECI.java | 110 ---- .../src/com/google/zxing/common/Collections.java | 53 -- .../src/com/google/zxing/common/Comparator.java | 27 - .../src/com/google/zxing/common/DecoderResult.java | 61 --- .../google/zxing/common/DefaultGridSampler.java | 86 --- .../com/google/zxing/common/DetectorResult.java | 46 -- .../src/com/google/zxing/common/ECI.java | 52 -- .../zxing/common/GlobalHistogramBinarizer.java | 194 ------- .../src/com/google/zxing/common/GridSampler.java | 156 ------ .../com/google/zxing/common/HybridBinarizer.java | 185 ------- .../google/zxing/common/PerspectiveTransform.java | 148 ------ .../src/com/google/zxing/common/StringUtils.java | 192 ------- .../detector/MonochromeRectangleDetector.java | 209 -------- .../common/detector/WhiteRectangleDetector.java | 347 ------------ .../google/zxing/common/reedsolomon/GenericGF.java | 188 ------- .../zxing/common/reedsolomon/GenericGFPoly.java | 263 --------- .../common/reedsolomon/ReedSolomonDecoder.java | 194 ------- .../common/reedsolomon/ReedSolomonEncoder.java | 75 --- .../common/reedsolomon/ReedSolomonException.java | 31 -- .../com/google/zxing/multi/ByQuadrantReader.java | 96 ---- .../zxing/multi/GenericMultipleBarcodeReader.java | 156 ------ .../google/zxing/multi/MultipleBarcodeReader.java | 37 -- .../zxing/multi/qrcode/detector/MultiDetector.java | 72 --- .../qrcode/detector/MultiFinderPatternFinder.java | 324 ------------ .../src/com/google/zxing/qrcode/QRCodeWriter.java | 108 ---- .../zxing/qrcode/decoder/BitMatrixParser.java | 203 ------- .../com/google/zxing/qrcode/decoder/DataBlock.java | 123 ----- .../com/google/zxing/qrcode/decoder/DataMask.java | 155 ------ .../qrcode/decoder/DecodedBitStreamParser.java | 322 ----------- .../zxing/qrcode/decoder/ErrorCorrectionLevel.java | 86 --- .../zxing/qrcode/decoder/FormatInformation.java | 171 ------ .../src/com/google/zxing/qrcode/decoder/Mode.java | 117 ---- .../com/google/zxing/qrcode/decoder/Version.java | 586 --------------------- .../zxing/qrcode/detector/AlignmentPattern.java | 48 -- .../qrcode/detector/AlignmentPatternFinder.java | 279 ---------- .../com/google/zxing/qrcode/detector/Detector.java | 406 -------------- .../zxing/qrcode/detector/FinderPattern.java | 63 --- .../zxing/qrcode/detector/FinderPatternFinder.java | 585 -------------------- .../zxing/qrcode/detector/FinderPatternInfo.java | 49 -- .../com/google/zxing/qrcode/encoder/BlockPair.java | 37 -- .../google/zxing/qrcode/encoder/ByteMatrix.java | 97 ---- .../com/google/zxing/qrcode/encoder/Encoder.java | 557 -------------------- .../com/google/zxing/qrcode/encoder/MaskUtil.java | 218 -------- .../google/zxing/qrcode/encoder/MatrixUtil.java | 524 ------------------ .../com/google/zxing/qrcode/encoder/QRCode.java | 239 --------- .../keychain/ui/KeyViewActivity.java | 2 +- 66 files changed, 1 insertion(+), 10184 deletions(-) delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/BarcodeFormat.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/Binarizer.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/BinaryBitmap.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/ChecksumException.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/DecodeHintType.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/EncodeHintType.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/FormatException.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/LuminanceSource.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/NotFoundException.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/Reader.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/ReaderException.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/Result.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/ResultMetadataType.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/ResultPoint.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/ResultPointCallback.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/Writer.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/WriterException.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/BitArray.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/BitMatrix.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/BitSource.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/CharacterSetECI.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/Collections.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/Comparator.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/DecoderResult.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/DefaultGridSampler.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/DetectorResult.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/ECI.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/GlobalHistogramBinarizer.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/GridSampler.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/HybridBinarizer.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/PerspectiveTransform.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/StringUtils.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/detector/MonochromeRectangleDetector.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/detector/WhiteRectangleDetector.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/GenericGF.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/GenericGFPoly.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/ReedSolomonDecoder.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/ReedSolomonEncoder.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/ReedSolomonException.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/multi/ByQuadrantReader.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/multi/GenericMultipleBarcodeReader.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/multi/MultipleBarcodeReader.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/multi/qrcode/detector/MultiDetector.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/multi/qrcode/detector/MultiFinderPatternFinder.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/QRCodeWriter.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/BitMatrixParser.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/DataBlock.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/DataMask.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/ErrorCorrectionLevel.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/FormatInformation.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/Mode.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/Version.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/AlignmentPattern.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/AlignmentPatternFinder.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/Detector.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/FinderPattern.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/FinderPatternFinder.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/FinderPatternInfo.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/BlockPair.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/ByteMatrix.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/Encoder.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MaskUtil.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MatrixUtil.java delete mode 100644 OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/QRCode.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/com/google/zxing/BarcodeFormat.java b/OpenPGP-Keychain/src/com/google/zxing/BarcodeFormat.java deleted file mode 100644 index 1e5d47958..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/BarcodeFormat.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing; - -import java.util.Hashtable; - -/** - * Enumerates barcode formats known to this package. Please keep alphabetized. - * - * @author Sean Owen - */ -public final class BarcodeFormat { - - // No, we can't use an enum here. J2ME doesn't support it. - - private static final Hashtable VALUES = new Hashtable(); - - /** Aztec 2D barcode format. */ - public static final BarcodeFormat AZTEC = new BarcodeFormat("AZTEC"); - - /** CODABAR 1D format. */ - public static final BarcodeFormat CODABAR = new BarcodeFormat("CODABAR"); - - /** Code 39 1D format. */ - public static final BarcodeFormat CODE_39 = new BarcodeFormat("CODE_39"); - - /** Code 93 1D format. */ - public static final BarcodeFormat CODE_93 = new BarcodeFormat("CODE_93"); - - /** Code 128 1D format. */ - public static final BarcodeFormat CODE_128 = new BarcodeFormat("CODE_128"); - - /** Data Matrix 2D barcode format. */ - public static final BarcodeFormat DATA_MATRIX = new BarcodeFormat("DATA_MATRIX"); - - /** EAN-8 1D format. */ - public static final BarcodeFormat EAN_8 = new BarcodeFormat("EAN_8"); - - /** EAN-13 1D format. */ - public static final BarcodeFormat EAN_13 = new BarcodeFormat("EAN_13"); - - /** ITF (Interleaved Two of Five) 1D format. */ - public static final BarcodeFormat ITF = new BarcodeFormat("ITF"); - - /** PDF417 format. */ - public static final BarcodeFormat PDF_417 = new BarcodeFormat("PDF_417"); - - /** QR Code 2D barcode format. */ - public static final BarcodeFormat QR_CODE = new BarcodeFormat("QR_CODE"); - - /** RSS 14 */ - public static final BarcodeFormat RSS_14 = new BarcodeFormat("RSS_14"); - - /** RSS EXPANDED */ - public static final BarcodeFormat RSS_EXPANDED = new BarcodeFormat("RSS_EXPANDED"); - - /** UPC-A 1D format. */ - public static final BarcodeFormat UPC_A = new BarcodeFormat("UPC_A"); - - /** UPC-E 1D format. */ - public static final BarcodeFormat UPC_E = new BarcodeFormat("UPC_E"); - - /** UPC/EAN extension format. Not a stand-alone format. */ - public static final BarcodeFormat UPC_EAN_EXTENSION = new BarcodeFormat("UPC_EAN_EXTENSION"); - - private final String name; - - private BarcodeFormat(String name) { - this.name = name; - VALUES.put(name, this); - } - - public String getName() { - return name; - } - - public String toString() { - return name; - } - - public static BarcodeFormat valueOf(String name) { - if (name == null || name.length() == 0) { - throw new IllegalArgumentException(); - } - BarcodeFormat format = (BarcodeFormat) VALUES.get(name); - if (format == null) { - throw new IllegalArgumentException(); - } - return format; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/Binarizer.java b/OpenPGP-Keychain/src/com/google/zxing/Binarizer.java deleted file mode 100644 index 912a3b556..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/Binarizer.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * 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 com.google.zxing; - -import com.google.zxing.common.BitArray; -import com.google.zxing.common.BitMatrix; - -/** - * This class hierarchy provides a set of methods to convert luminance data to 1 bit data. - * It allows the algorithm to vary polymorphically, for example allowing a very expensive - * thresholding technique for servers and a fast one for mobile. It also permits the implementation - * to vary, e.g. a JNI version for Android and a Java fallback version for other platforms. - * - * @author dswitkin@google.com (Daniel Switkin) - */ -public abstract class Binarizer { - - private final LuminanceSource source; - - protected Binarizer(LuminanceSource source) { - if (source == null) { - throw new IllegalArgumentException("Source must be non-null."); - } - this.source = source; - } - - public LuminanceSource getLuminanceSource() { - return source; - } - - /** - * Converts one row of luminance data to 1 bit data. May actually do the conversion, or return - * cached data. Callers should assume this method is expensive and call it as seldom as possible. - * This method is intended for decoding 1D barcodes and may choose to apply sharpening. - * For callers which only examine one row of pixels at a time, the same BitArray should be reused - * and passed in with each call for performance. However it is legal to keep more than one row - * at a time if needed. - * - * @param y The row to fetch, 0 <= y < bitmap height. - * @param row An optional preallocated array. If null or too small, it will be ignored. - * If used, the Binarizer will call BitArray.clear(). Always use the returned object. - * @return The array of bits for this row (true means black). - */ - public abstract BitArray getBlackRow(int y, BitArray row) throws NotFoundException; - - /** - * Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive - * and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or - * may not apply sharpening. Therefore, a row from this matrix may not be identical to one - * fetched using getBlackRow(), so don't mix and match between them. - * - * @return The 2D array of bits for the image (true means black). - */ - public abstract BitMatrix getBlackMatrix() throws NotFoundException; - - /** - * Creates a new object with the same type as this Binarizer implementation, but with pristine - * state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache - * of 1 bit data. See Effective Java for why we can't use Java's clone() method. - * - * @param source The LuminanceSource this Binarizer will operate on. - * @return A new concrete Binarizer implementation object. - */ - public abstract Binarizer createBinarizer(LuminanceSource source); - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/BinaryBitmap.java b/OpenPGP-Keychain/src/com/google/zxing/BinaryBitmap.java deleted file mode 100644 index b97e46705..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/BinaryBitmap.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * 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 com.google.zxing; - -import com.google.zxing.common.BitArray; -import com.google.zxing.common.BitMatrix; - -/** - * This class is the core bitmap class used by ZXing to represent 1 bit data. Reader objects - * accept a BinaryBitmap and attempt to decode it. - * - * @author dswitkin@google.com (Daniel Switkin) - */ -public final class BinaryBitmap { - - private final Binarizer binarizer; - private BitMatrix matrix; - - public BinaryBitmap(Binarizer binarizer) { - if (binarizer == null) { - throw new IllegalArgumentException("Binarizer must be non-null."); - } - this.binarizer = binarizer; - matrix = null; - } - - /** - * @return The width of the bitmap. - */ - public int getWidth() { - return binarizer.getLuminanceSource().getWidth(); - } - - /** - * @return The height of the bitmap. - */ - public int getHeight() { - return binarizer.getLuminanceSource().getHeight(); - } - - /** - * Converts one row of luminance data to 1 bit data. May actually do the conversion, or return - * cached data. Callers should assume this method is expensive and call it as seldom as possible. - * This method is intended for decoding 1D barcodes and may choose to apply sharpening. - * - * @param y The row to fetch, 0 <= y < bitmap height. - * @param row An optional preallocated array. If null or too small, it will be ignored. - * If used, the Binarizer will call BitArray.clear(). Always use the returned object. - * @return The array of bits for this row (true means black). - */ - public BitArray getBlackRow(int y, BitArray row) throws NotFoundException { - return binarizer.getBlackRow(y, row); - } - - /** - * Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive - * and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or - * may not apply sharpening. Therefore, a row from this matrix may not be identical to one - * fetched using getBlackRow(), so don't mix and match between them. - * - * @return The 2D array of bits for the image (true means black). - */ - public BitMatrix getBlackMatrix() throws NotFoundException { - // The matrix is created on demand the first time it is requested, then cached. There are two - // reasons for this: - // 1. This work will never be done if the caller only installs 1D Reader objects, or if a - // 1D Reader finds a barcode before the 2D Readers run. - // 2. This work will only be done once even if the caller installs multiple 2D Readers. - if (matrix == null) { - matrix = binarizer.getBlackMatrix(); - } - return matrix; - } - - /** - * @return Whether this bitmap can be cropped. - */ - public boolean isCropSupported() { - return binarizer.getLuminanceSource().isCropSupported(); - } - - /** - * Returns a new object with cropped image data. Implementations may keep a reference to the - * original data rather than a copy. Only callable if isCropSupported() is true. - * - * @param left The left coordinate, 0 <= left < getWidth(). - * @param top The top coordinate, 0 <= top <= getHeight(). - * @param width The width of the rectangle to crop. - * @param height The height of the rectangle to crop. - * @return A cropped version of this object. - */ - public BinaryBitmap crop(int left, int top, int width, int height) { - LuminanceSource newSource = binarizer.getLuminanceSource().crop(left, top, width, height); - return new BinaryBitmap(binarizer.createBinarizer(newSource)); - } - - /** - * @return Whether this bitmap supports counter-clockwise rotation. - */ - public boolean isRotateSupported() { - return binarizer.getLuminanceSource().isRotateSupported(); - } - - /** - * Returns a new object with rotated image data. Only callable if isRotateSupported() is true. - * - * @return A rotated version of this object. - */ - public BinaryBitmap rotateCounterClockwise() { - LuminanceSource newSource = binarizer.getLuminanceSource().rotateCounterClockwise(); - return new BinaryBitmap(binarizer.createBinarizer(newSource)); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/ChecksumException.java b/OpenPGP-Keychain/src/com/google/zxing/ChecksumException.java deleted file mode 100644 index dedb4be99..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/ChecksumException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing; - -/** - * Thrown when a barcode was successfully detected and decoded, but - * was not returned because its checksum feature failed. - * - * @author Sean Owen - */ -public final class ChecksumException extends ReaderException { - - private static final ChecksumException instance = new ChecksumException(); - - private ChecksumException() { - // do nothing - } - - public static ChecksumException getChecksumInstance() { - return instance; - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/DecodeHintType.java b/OpenPGP-Keychain/src/com/google/zxing/DecodeHintType.java deleted file mode 100644 index 20b922ca1..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/DecodeHintType.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing; - -/** - * Encapsulates a type of hint that a caller may pass to a barcode reader to help it - * more quickly or accurately decode it. It is up to implementations to decide what, - * if anything, to do with the information that is supplied. - * - * @author Sean Owen - * @author dswitkin@google.com (Daniel Switkin) - * @see Reader#decode(BinaryBitmap,java.util.Hashtable) - */ -public final class DecodeHintType { - - // No, we can't use an enum here. J2ME doesn't support it. - - /** - * Unspecified, application-specific hint. Maps to an unspecified {@link Object}. - */ - public static final DecodeHintType OTHER = new DecodeHintType(); - - /** - * Image is a pure monochrome image of a barcode. Doesn't matter what it maps to; - * use {@link Boolean#TRUE}. - */ - public static final DecodeHintType PURE_BARCODE = new DecodeHintType(); - - /** - * Image is known to be of one of a few possible formats. - * Maps to a {@link java.util.Vector} of {@link BarcodeFormat}s. - */ - public static final DecodeHintType POSSIBLE_FORMATS = new DecodeHintType(); - - /** - * Spend more time to try to find a barcode; optimize for accuracy, not speed. - * Doesn't matter what it maps to; use {@link Boolean#TRUE}. - */ - public static final DecodeHintType TRY_HARDER = new DecodeHintType(); - - /** - * Specifies what character encoding to use when decoding, where applicable (type String) - */ - public static final DecodeHintType CHARACTER_SET = new DecodeHintType(); - - /** - * Allowed lengths of encoded data -- reject anything else. Maps to an int[]. - */ - public static final DecodeHintType ALLOWED_LENGTHS = new DecodeHintType(); - - /** - * Assume Code 39 codes employ a check digit. Maps to {@link Boolean}. - */ - public static final DecodeHintType ASSUME_CODE_39_CHECK_DIGIT = new DecodeHintType(); - - /** - * The caller needs to be notified via callback when a possible {@link ResultPoint} - * is found. Maps to a {@link ResultPointCallback}. - */ - public static final DecodeHintType NEED_RESULT_POINT_CALLBACK = new DecodeHintType(); - - private DecodeHintType() { - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/EncodeHintType.java b/OpenPGP-Keychain/src/com/google/zxing/EncodeHintType.java deleted file mode 100644 index 35afc1530..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/EncodeHintType.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing; - -/** - * These are a set of hints that you may pass to Writers to specify their behavior. - * - * @author dswitkin@google.com (Daniel Switkin) - */ -public final class EncodeHintType { - - /** - * Specifies what degree of error correction to use, for example in QR Codes (type Integer). - */ - public static final EncodeHintType ERROR_CORRECTION = new EncodeHintType(); - - /** - * Specifies what character encoding to use where applicable (type String) - */ - public static final EncodeHintType CHARACTER_SET = new EncodeHintType(); - - private EncodeHintType() { - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/FormatException.java b/OpenPGP-Keychain/src/com/google/zxing/FormatException.java deleted file mode 100644 index 6967e93de..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/FormatException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing; - -/** - * Thrown when a barcode was successfully detected, but some aspect of - * the content did not conform to the barcode's format rules. This could have - * been due to a mis-detection. - * - * @author Sean Owen - */ -public final class FormatException extends ReaderException { - - private static final FormatException instance = new FormatException(); - - private FormatException() { - // do nothing - } - - public static FormatException getFormatInstance() { - return instance; - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/LuminanceSource.java b/OpenPGP-Keychain/src/com/google/zxing/LuminanceSource.java deleted file mode 100644 index 4b6d4539f..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/LuminanceSource.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * 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 com.google.zxing; - -/** - * The purpose of this class hierarchy is to abstract different bitmap implementations across - * platforms into a standard interface for requesting greyscale luminance values. The interface - * only provides immutable methods; therefore crop and rotation create copies. This is to ensure - * that one Reader does not modify the original luminance source and leave it in an unknown state - * for other Readers in the chain. - * - * @author dswitkin@google.com (Daniel Switkin) - */ -public abstract class LuminanceSource { - - private final int width; - private final int height; - - protected LuminanceSource(int width, int height) { - this.width = width; - this.height = height; - } - - /** - * Fetches one row of luminance data from the underlying platform's bitmap. Values range from - * 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have - * to bitwise and with 0xff for each value. It is preferable for implementations of this method - * to only fetch this row rather than the whole image, since no 2D Readers may be installed and - * getMatrix() may never be called. - * - * @param y The row to fetch, 0 <= y < getHeight(). - * @param row An optional preallocated array. If null or too small, it will be ignored. - * Always use the returned object, and ignore the .length of the array. - * @return An array containing the luminance data. - */ - public abstract byte[] getRow(int y, byte[] row); - - /** - * Fetches luminance data for the underlying bitmap. Values should be fetched using: - * int luminance = array[y * width + x] & 0xff; - * - * @return A row-major 2D array of luminance values. Do not use result.length as it may be - * larger than width * height bytes on some platforms. Do not modify the contents - * of the result. - */ - public abstract byte[] getMatrix(); - - /** - * @return The width of the bitmap. - */ - public final int getWidth() { - return width; - } - - /** - * @return The height of the bitmap. - */ - public final int getHeight() { - return height; - } - - /** - * @return Whether this subclass supports cropping. - */ - public boolean isCropSupported() { - return false; - } - - /** - * Returns a new object with cropped image data. Implementations may keep a reference to the - * original data rather than a copy. Only callable if isCropSupported() is true. - * - * @param left The left coordinate, 0 <= left < getWidth(). - * @param top The top coordinate, 0 <= top <= getHeight(). - * @param width The width of the rectangle to crop. - * @param height The height of the rectangle to crop. - * @return A cropped version of this object. - */ - public LuminanceSource crop(int left, int top, int width, int height) { - throw new RuntimeException("This luminance source does not support cropping."); - } - - /** - * @return Whether this subclass supports counter-clockwise rotation. - */ - public boolean isRotateSupported() { - return false; - } - - /** - * Returns a new object with rotated image data. Only callable if isRotateSupported() is true. - * - * @return A rotated version of this object. - */ - public LuminanceSource rotateCounterClockwise() { - throw new RuntimeException("This luminance source does not support rotation."); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/NotFoundException.java b/OpenPGP-Keychain/src/com/google/zxing/NotFoundException.java deleted file mode 100644 index dedab8dfc..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/NotFoundException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing; - -/** - * Thrown when a barcode was not found in the image. It might have been - * partially detected but could not be confirmed. - * - * @author Sean Owen - */ -public final class NotFoundException extends ReaderException { - - private static final NotFoundException instance = new NotFoundException(); - - private NotFoundException() { - // do nothing - } - - public static NotFoundException getNotFoundInstance() { - return instance; - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/Reader.java b/OpenPGP-Keychain/src/com/google/zxing/Reader.java deleted file mode 100644 index 47e843ba6..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/Reader.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing; - -import java.util.Hashtable; - -/** - * Implementations of this interface can decode an image of a barcode in some format into - * the String it encodes. For example, {@link com.google.zxing.qrcode.QRCodeReader} can - * decode a QR code. The decoder may optionally receive hints from the caller which may help - * it decode more quickly or accurately. - * - * See {@link com.google.zxing.MultiFormatReader}, which attempts to determine what barcode - * format is present within the image as well, and then decodes it accordingly. - * - * @author Sean Owen - * @author dswitkin@google.com (Daniel Switkin) - */ -public interface Reader { - - /** - * Locates and decodes a barcode in some format within an image. - * - * @param image image of barcode to decode - * @return String which the barcode encodes - * @throws NotFoundException if the barcode cannot be located or decoded for any reason - */ - Result decode(BinaryBitmap image) throws NotFoundException, ChecksumException, FormatException; - - /** - * Locates and decodes a barcode in some format within an image. This method also accepts - * hints, each possibly associated to some data, which may help the implementation decode. - * - * @param image image of barcode to decode - * @param hints passed as a {@link java.util.Hashtable} from {@link com.google.zxing.DecodeHintType} - * to arbitrary data. The - * meaning of the data depends upon the hint type. The implementation may or may not do - * anything with these hints. - * @return String which the barcode encodes - * @throws NotFoundException if the barcode cannot be located or decoded for any reason - */ - Result decode(BinaryBitmap image, Hashtable hints) throws NotFoundException, ChecksumException, FormatException; - - /** - * Resets any internal state the implementation has after a decode, to prepare it - * for reuse. - */ - void reset(); - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/ReaderException.java b/OpenPGP-Keychain/src/com/google/zxing/ReaderException.java deleted file mode 100644 index 224a497e5..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/ReaderException.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing; - -/** - * The general exception class throw when something goes wrong during decoding of a barcode. - * This includes, but is not limited to, failing checksums / error correction algorithms, being - * unable to locate finder timing patterns, and so on. - * - * @author Sean Owen - */ -public abstract class ReaderException extends Exception { - - // TODO: Currently we throw up to 400 ReaderExceptions while scanning a single 240x240 image before - // rejecting it. This involves a lot of overhead and memory allocation, and affects both performance - // and latency on continuous scan clients. In the future, we should change all the decoders not to - // throw exceptions for routine events, like not finding a barcode on a given row. Instead, we - // should return error codes back to the callers, and simply delete this class. In the mean time, I - // have altered this class to be as lightweight as possible, by ignoring the exception string, and - // by disabling the generation of stack traces, which is especially time consuming. These are just - // temporary measures, pending the big cleanup. - - //private static final ReaderException instance = new ReaderException(); - - // EXCEPTION TRACKING SUPPORT - // Identifies who is throwing exceptions and how often. To use: - // - // 1. Uncomment these lines and the code below which uses them. - // 2. Uncomment the two corresponding lines in j2se/CommandLineRunner.decode() - // 3. Change core to build as Java 1.5 temporarily -// private static int exceptionCount = 0; -// private static Map throwers = new HashMap(32); - - ReaderException() { - // do nothing - } - - //public static ReaderException getInstance() { -// Exception e = new Exception(); -// // Take the stack frame before this one. -// StackTraceElement stack = e.getStackTrace()[1]; -// String key = stack.getClassName() + "." + stack.getMethodName() + "(), line " + -// stack.getLineNumber(); -// if (throwers.containsKey(key)) { -// Integer value = throwers.get(key); -// value++; -// throwers.put(key, value); -// } else { -// throwers.put(key, 1); -// } -// exceptionCount++; - - //return instance; - //} - -// public static int getExceptionCountAndReset() { -// int temp = exceptionCount; -// exceptionCount = 0; -// return temp; -// } -// -// public static String getThrowersAndReset() { -// StringBuilder builder = new StringBuilder(1024); -// Object[] keys = throwers.keySet().toArray(); -// for (int x = 0; x < keys.length; x++) { -// String key = (String) keys[x]; -// Integer value = throwers.get(key); -// builder.append(key); -// builder.append(": "); -// builder.append(value); -// builder.append("\n"); -// } -// throwers.clear(); -// return builder.toString(); -// } - - // Prevent stack traces from being taken - // srowen says: huh, my IDE is saying this is not an override. native methods can't be overridden? - // This, at least, does not hurt. Because we use a singleton pattern here, it doesn't matter anyhow. - public final Throwable fillInStackTrace() { - return null; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/Result.java b/OpenPGP-Keychain/src/com/google/zxing/Result.java deleted file mode 100644 index ee1af527e..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/Result.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing; - -import java.util.Enumeration; -import java.util.Hashtable; - -/** - *

Encapsulates the result of decoding a barcode within an image.

- * - * @author Sean Owen - */ -public final class Result { - - private final String text; - private final byte[] rawBytes; - private ResultPoint[] resultPoints; - private final BarcodeFormat format; - private Hashtable resultMetadata; - private final long timestamp; - - public Result(String text, - byte[] rawBytes, - ResultPoint[] resultPoints, - BarcodeFormat format) { - this(text, rawBytes, resultPoints, format, System.currentTimeMillis()); - } - - public Result(String text, - byte[] rawBytes, - ResultPoint[] resultPoints, - BarcodeFormat format, - long timestamp) { - if (text == null && rawBytes == null) { - throw new IllegalArgumentException("Text and bytes are null"); - } - this.text = text; - this.rawBytes = rawBytes; - this.resultPoints = resultPoints; - this.format = format; - this.resultMetadata = null; - this.timestamp = timestamp; - } - - /** - * @return raw text encoded by the barcode, if applicable, otherwise null - */ - public String getText() { - return text; - } - - /** - * @return raw bytes encoded by the barcode, if applicable, otherwise null - */ - public byte[] getRawBytes() { - return rawBytes; - } - - /** - * @return points related to the barcode in the image. These are typically points - * identifying finder patterns or the corners of the barcode. The exact meaning is - * specific to the type of barcode that was decoded. - */ - public ResultPoint[] getResultPoints() { - return resultPoints; - } - - /** - * @return {@link BarcodeFormat} representing the format of the barcode that was decoded - */ - public BarcodeFormat getBarcodeFormat() { - return format; - } - - /** - * @return {@link Hashtable} mapping {@link ResultMetadataType} keys to values. May be - * null. This contains optional metadata about what was detected about the barcode, - * like orientation. - */ - public Hashtable getResultMetadata() { - return resultMetadata; - } - - public void putMetadata(ResultMetadataType type, Object value) { - if (resultMetadata == null) { - resultMetadata = new Hashtable(3); - } - resultMetadata.put(type, value); - } - - public void putAllMetadata(Hashtable metadata) { - if (metadata != null) { - if (resultMetadata == null) { - resultMetadata = metadata; - } else { - Enumeration e = metadata.keys(); - while (e.hasMoreElements()) { - ResultMetadataType key = (ResultMetadataType) e.nextElement(); - Object value = metadata.get(key); - resultMetadata.put(key, value); - } - } - } - } - - public void addResultPoints(ResultPoint[] newPoints) { - if (resultPoints == null) { - resultPoints = newPoints; - } else if (newPoints != null && newPoints.length > 0) { - ResultPoint[] allPoints = new ResultPoint[resultPoints.length + newPoints.length]; - System.arraycopy(resultPoints, 0, allPoints, 0, resultPoints.length); - System.arraycopy(newPoints, 0, allPoints, resultPoints.length, newPoints.length); - resultPoints = allPoints; - } - } - - public long getTimestamp() { - return timestamp; - } - - public String toString() { - if (text == null) { - return "[" + rawBytes.length + " bytes]"; - } else { - return text; - } - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/ResultMetadataType.java b/OpenPGP-Keychain/src/com/google/zxing/ResultMetadataType.java deleted file mode 100644 index 33d69d9c5..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/ResultMetadataType.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing; - -import java.util.Hashtable; - -/** - * Represents some type of metadata about the result of the decoding that the decoder - * wishes to communicate back to the caller. - * - * @author Sean Owen - */ -public final class ResultMetadataType { - - // No, we can't use an enum here. J2ME doesn't support it. - - private static final Hashtable VALUES = new Hashtable(); - - // No, we can't use an enum here. J2ME doesn't support it. - - /** - * Unspecified, application-specific metadata. Maps to an unspecified {@link Object}. - */ - public static final ResultMetadataType OTHER = new ResultMetadataType("OTHER"); - - /** - * Denotes the likely approximate orientation of the barcode in the image. This value - * is given as degrees rotated clockwise from the normal, upright orientation. - * For example a 1D barcode which was found by reading top-to-bottom would be - * said to have orientation "90". This key maps to an {@link Integer} whose - * value is in the range [0,360). - */ - public static final ResultMetadataType ORIENTATION = new ResultMetadataType("ORIENTATION"); - - /** - *

2D barcode formats typically encode text, but allow for a sort of 'byte mode' - * which is sometimes used to encode binary data. While {@link Result} makes available - * the complete raw bytes in the barcode for these formats, it does not offer the bytes - * from the byte segments alone.

- * - *

This maps to a {@link java.util.Vector} of byte arrays corresponding to the - * raw bytes in the byte segments in the barcode, in order.

- */ - public static final ResultMetadataType BYTE_SEGMENTS = new ResultMetadataType("BYTE_SEGMENTS"); - - /** - * Error correction level used, if applicable. The value type depends on the - * format, but is typically a String. - */ - public static final ResultMetadataType ERROR_CORRECTION_LEVEL = new ResultMetadataType("ERROR_CORRECTION_LEVEL"); - - /** - * For some periodicals, indicates the issue number as an {@link Integer}. - */ - public static final ResultMetadataType ISSUE_NUMBER = new ResultMetadataType("ISSUE_NUMBER"); - - /** - * For some products, indicates the suggested retail price in the barcode as a - * formatted {@link String}. - */ - public static final ResultMetadataType SUGGESTED_PRICE = new ResultMetadataType("SUGGESTED_PRICE"); - - /** - * For some products, the possible country of manufacture as a {@link String} denoting the - * ISO country code. Some map to multiple possible countries, like "US/CA". - */ - public static final ResultMetadataType POSSIBLE_COUNTRY = new ResultMetadataType("POSSIBLE_COUNTRY"); - - private final String name; - - private ResultMetadataType(String name) { - this.name = name; - VALUES.put(name, this); - } - - public String getName() { - return name; - } - - public String toString() { - return name; - } - - public static ResultMetadataType valueOf(String name) { - if (name == null || name.length() == 0) { - throw new IllegalArgumentException(); - } - ResultMetadataType format = (ResultMetadataType) VALUES.get(name); - if (format == null) { - throw new IllegalArgumentException(); - } - return format; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/ResultPoint.java b/OpenPGP-Keychain/src/com/google/zxing/ResultPoint.java deleted file mode 100644 index 366ae3855..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/ResultPoint.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing; - -/** - *

Encapsulates a point of interest in an image containing a barcode. Typically, this - * would be the location of a finder pattern or the corner of the barcode, for example.

- * - * @author Sean Owen - */ -public class ResultPoint { - - private final float x; - private final float y; - - public ResultPoint(float x, float y) { - this.x = x; - this.y = y; - } - - public final float getX() { - return x; - } - - public final float getY() { - return y; - } - - public boolean equals(Object other) { - if (other instanceof ResultPoint) { - ResultPoint otherPoint = (ResultPoint) other; - return x == otherPoint.x && y == otherPoint.y; - } - return false; - } - - public int hashCode() { - return 31 * Float.floatToIntBits(x) + Float.floatToIntBits(y); - } - - public String toString() { - StringBuffer result = new StringBuffer(25); - result.append('('); - result.append(x); - result.append(','); - result.append(y); - result.append(')'); - return result.toString(); - } - - /** - *

Orders an array of three ResultPoints in an order [A,B,C] such that AB < AC and - * BC < AC and the angle between BC and BA is less than 180 degrees. - */ - public static void orderBestPatterns(ResultPoint[] patterns) { - - // Find distances between pattern centers - float zeroOneDistance = distance(patterns[0], patterns[1]); - float oneTwoDistance = distance(patterns[1], patterns[2]); - float zeroTwoDistance = distance(patterns[0], patterns[2]); - - ResultPoint pointA; - ResultPoint pointB; - ResultPoint pointC; - // Assume one closest to other two is B; A and C will just be guesses at first - if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) { - pointB = patterns[0]; - pointA = patterns[1]; - pointC = patterns[2]; - } else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) { - pointB = patterns[1]; - pointA = patterns[0]; - pointC = patterns[2]; - } else { - pointB = patterns[2]; - pointA = patterns[0]; - pointC = patterns[1]; - } - - // Use cross product to figure out whether A and C are correct or flipped. - // This asks whether BC x BA has a positive z component, which is the arrangement - // we want for A, B, C. If it's negative, then we've got it flipped around and - // should swap A and C. - if (crossProductZ(pointA, pointB, pointC) < 0.0f) { - ResultPoint temp = pointA; - pointA = pointC; - pointC = temp; - } - - patterns[0] = pointA; - patterns[1] = pointB; - patterns[2] = pointC; - } - - - /** - * @return distance between two points - */ - public static float distance(ResultPoint pattern1, ResultPoint pattern2) { - float xDiff = pattern1.getX() - pattern2.getX(); - float yDiff = pattern1.getY() - pattern2.getY(); - return (float) Math.sqrt((double) (xDiff * xDiff + yDiff * yDiff)); - } - - /** - * Returns the z component of the cross product between vectors BC and BA. - */ - private static float crossProductZ(ResultPoint pointA, ResultPoint pointB, ResultPoint pointC) { - float bX = pointB.x; - float bY = pointB.y; - return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX)); - } - - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/ResultPointCallback.java b/OpenPGP-Keychain/src/com/google/zxing/ResultPointCallback.java deleted file mode 100644 index 0c85410bc..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/ResultPointCallback.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * 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 com.google.zxing; - -/** - * Callback which is invoked when a possible result point (significant - * point in the barcode image such as a corner) is found. - * - * @see DecodeHintType#NEED_RESULT_POINT_CALLBACK - */ -public interface ResultPointCallback { - - void foundPossibleResultPoint(ResultPoint point); - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/Writer.java b/OpenPGP-Keychain/src/com/google/zxing/Writer.java deleted file mode 100644 index 6474ca7e2..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/Writer.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing; - -import com.google.zxing.common.BitMatrix; - -import java.util.Hashtable; - -/** - * The base class for all objects which encode/generate a barcode image. - * - * @author dswitkin@google.com (Daniel Switkin) - */ -public interface Writer { - - /** - * Encode a barcode using the default settings. - * - * @param contents The contents to encode in the barcode - * @param format The barcode format to generate - * @param width The preferred width in pixels - * @param height The preferred height in pixels - * @return The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white) - */ - BitMatrix encode(String contents, BarcodeFormat format, int width, int height) - throws WriterException; - - /** - * - * @param contents The contents to encode in the barcode - * @param format The barcode format to generate - * @param width The preferred width in pixels - * @param height The preferred height in pixels - * @param hints Additional parameters to supply to the encoder - * @return The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white) - */ - BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Hashtable hints) - throws WriterException; - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/WriterException.java b/OpenPGP-Keychain/src/com/google/zxing/WriterException.java deleted file mode 100644 index 0c19af01d..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/WriterException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing; - -/** - * A base class which covers the range of exceptions which may occur when encoding a barcode using - * the Writer framework. - * - * @author dswitkin@google.com (Daniel Switkin) - */ -public final class WriterException extends Exception { - - public WriterException() { - super(); - } - - public WriterException(String message) { - super(message); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/BitArray.java b/OpenPGP-Keychain/src/com/google/zxing/common/BitArray.java deleted file mode 100644 index 6eb0d57c6..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/BitArray.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common; - -/** - *

A simple, fast array of bits, represented compactly by an array of ints internally.

- * - * @author Sean Owen - */ -public final class BitArray { - // I have changed these members to be public so ProGuard can inline get() and set(). Ideally - // they'd be private and we'd use the -allowaccessmodification flag, but Dalvik rejects the - // resulting binary at runtime on Android. If we find a solution to this, these should be changed - // back to private. - public int[] bits; - public int size; - - public BitArray() { - this.size = 0; - this.bits = new int[1]; - } - - public BitArray(int size) { - this.size = size; - this.bits = makeArray(size); - } - - public int getSize() { - return size; - } - - public int getSizeInBytes() { - return (size + 7) >> 3; - } - - private void ensureCapacity(int size) { - if (size > bits.length << 5) { - int[] newBits = makeArray(size); - System.arraycopy(bits, 0, newBits, 0, bits.length); - this.bits = newBits; - } - } - - /** - * @param i bit to get - * @return true iff bit i is set - */ - public boolean get(int i) { - return (bits[i >> 5] & (1 << (i & 0x1F))) != 0; - } - - /** - * Sets bit i. - * - * @param i bit to set - */ - public void set(int i) { - bits[i >> 5] |= 1 << (i & 0x1F); - } - - /** - * Flips bit i. - * - * @param i bit to set - */ - public void flip(int i) { - bits[i >> 5] ^= 1 << (i & 0x1F); - } - - /** - * Sets a block of 32 bits, starting at bit i. - * - * @param i first bit to set - * @param newBits the new value of the next 32 bits. Note again that the least-significant bit - * corresponds to bit i, the next-least-significant to i+1, and so on. - */ - public void setBulk(int i, int newBits) { - bits[i >> 5] = newBits; - } - - /** - * Clears all bits (sets to false). - */ - public void clear() { - int max = bits.length; - for (int i = 0; i < max; i++) { - bits[i] = 0; - } - } - - /** - * Efficient method to check if a range of bits is set, or not set. - * - * @param start start of range, inclusive. - * @param end end of range, exclusive - * @param value if true, checks that bits in range are set, otherwise checks that they are not set - * @return true iff all bits are set or not set in range, according to value argument - * @throws IllegalArgumentException if end is less than or equal to start - */ - public boolean isRange(int start, int end, boolean value) { - if (end < start) { - throw new IllegalArgumentException(); - } - if (end == start) { - return true; // empty range matches - } - end--; // will be easier to treat this as the last actually set bit -- inclusive - int firstInt = start >> 5; - int lastInt = end >> 5; - for (int i = firstInt; i <= lastInt; i++) { - int firstBit = i > firstInt ? 0 : start & 0x1F; - int lastBit = i < lastInt ? 31 : end & 0x1F; - int mask; - if (firstBit == 0 && lastBit == 31) { - mask = -1; - } else { - mask = 0; - for (int j = firstBit; j <= lastBit; j++) { - mask |= 1 << j; - } - } - - // Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is, - // equals the mask, or we're looking for 0s and the masked portion is not all 0s - if ((bits[i] & mask) != (value ? mask : 0)) { - return false; - } - } - return true; - } - - public void appendBit(boolean bit) { - ensureCapacity(size + 1); - if (bit) { - bits[size >> 5] |= (1 << (size & 0x1F)); - } - size++; - } - - /** - * Appends the least-significant bits, from value, in order from most-significant to - * least-significant. For example, appending 6 bits from 0x000001E will append the bits - * 0, 1, 1, 1, 1, 0 in that order. - */ - public void appendBits(int value, int numBits) { - if (numBits < 0 || numBits > 32) { - throw new IllegalArgumentException("Num bits must be between 0 and 32"); - } - ensureCapacity(size + numBits); - for (int numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--) { - appendBit(((value >> (numBitsLeft - 1)) & 0x01) == 1); - } - } - - public void appendBitArray(BitArray other) { - int otherSize = other.getSize(); - ensureCapacity(size + otherSize); - for (int i = 0; i < otherSize; i++) { - appendBit(other.get(i)); - } - } - - public void xor(BitArray other) { - if (bits.length != other.bits.length) { - throw new IllegalArgumentException("Sizes don't match"); - } - for (int i = 0; i < bits.length; i++) { - // The last byte could be incomplete (i.e. not have 8 bits in - // it) but there is no problem since 0 XOR 0 == 0. - bits[i] ^= other.bits[i]; - } - } - - /** - * - * @param bitOffset first bit to start writing - * @param array array to write into. Bytes are written most-significant byte first. This is the opposite - * of the internal representation, which is exposed by {@link #getBitArray()} - * @param offset position in array to start writing - * @param numBytes how many bytes to write - */ - public void toBytes(int bitOffset, byte[] array, int offset, int numBytes) { - for (int i = 0; i < numBytes; i++) { - int theByte = 0; - for (int j = 0; j < 8; j++) { - if (get(bitOffset)) { - theByte |= 1 << (7 - j); - } - bitOffset++; - } - array[offset + i] = (byte) theByte; - } - } - - /** - * @return underlying array of ints. The first element holds the first 32 bits, and the least - * significant bit is bit 0. - */ - public int[] getBitArray() { - return bits; - } - - /** - * Reverses all bits in the array. - */ - public void reverse() { - int[] newBits = new int[bits.length]; - int size = this.size; - for (int i = 0; i < size; i++) { - if (get(size - i - 1)) { - newBits[i >> 5] |= 1 << (i & 0x1F); - } - } - bits = newBits; - } - - private static int[] makeArray(int size) { - return new int[(size + 31) >> 5]; - } - - public String toString() { - StringBuffer result = new StringBuffer(size); - for (int i = 0; i < size; i++) { - if ((i & 0x07) == 0) { - result.append(' '); - } - result.append(get(i) ? 'X' : '.'); - } - return result.toString(); - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/BitMatrix.java b/OpenPGP-Keychain/src/com/google/zxing/common/BitMatrix.java deleted file mode 100644 index 8bf75b289..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/BitMatrix.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common; - -/** - *

Represents a 2D matrix of bits. In function arguments below, and throughout the common - * module, x is the column position, and y is the row position. The ordering is always x, y. - * The origin is at the top-left.

- * - *

Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins - * with a new int. This is done intentionally so that we can copy out a row into a BitArray very - * efficiently.

- * - *

The ordering of bits is row-major. Within each int, the least significant bits are used first, - * meaning they represent lower x values. This is compatible with BitArray's implementation.

- * - * @author Sean Owen - * @author dswitkin@google.com (Daniel Switkin) - */ -public final class BitMatrix { - // Just like BitArray, these need to be public so ProGuard can inline them. - public final int width; - public final int height; - public final int rowSize; - public final int[] bits; - - // A helper to construct a square matrix. - public BitMatrix(int dimension) { - this(dimension, dimension); - } - - public BitMatrix(int width, int height) { - if (width < 1 || height < 1) { - throw new IllegalArgumentException("Both dimensions must be greater than 0"); - } - this.width = width; - this.height = height; - this.rowSize = (width + 31) >> 5; - bits = new int[rowSize * height]; - } - - /** - *

Gets the requested bit, where true means black.

- * - * @param x The horizontal component (i.e. which column) - * @param y The vertical component (i.e. which row) - * @return value of given bit in matrix - */ - public boolean get(int x, int y) { - int offset = y * rowSize + (x >> 5); - return ((bits[offset] >>> (x & 0x1f)) & 1) != 0; - } - - /** - *

Sets the given bit to true.

- * - * @param x The horizontal component (i.e. which column) - * @param y The vertical component (i.e. which row) - */ - public void set(int x, int y) { - int offset = y * rowSize + (x >> 5); - bits[offset] |= 1 << (x & 0x1f); - } - - /** - *

Flips the given bit.

- * - * @param x The horizontal component (i.e. which column) - * @param y The vertical component (i.e. which row) - */ - public void flip(int x, int y) { - int offset = y * rowSize + (x >> 5); - bits[offset] ^= 1 << (x & 0x1f); - } - - /** - * Clears all bits (sets to false). - */ - public void clear() { - int max = bits.length; - for (int i = 0; i < max; i++) { - bits[i] = 0; - } - } - - /** - *

Sets a square region of the bit matrix to true.

- * - * @param left The horizontal position to begin at (inclusive) - * @param top The vertical position to begin at (inclusive) - * @param width The width of the region - * @param height The height of the region - */ - public void setRegion(int left, int top, int width, int height) { - if (top < 0 || left < 0) { - throw new IllegalArgumentException("Left and top must be nonnegative"); - } - if (height < 1 || width < 1) { - throw new IllegalArgumentException("Height and width must be at least 1"); - } - int right = left + width; - int bottom = top + height; - if (bottom > this.height || right > this.width) { - throw new IllegalArgumentException("The region must fit inside the matrix"); - } - for (int y = top; y < bottom; y++) { - int offset = y * rowSize; - for (int x = left; x < right; x++) { - bits[offset + (x >> 5)] |= 1 << (x & 0x1f); - } - } - } - - /** - * A fast method to retrieve one row of data from the matrix as a BitArray. - * - * @param y The row to retrieve - * @param row An optional caller-allocated BitArray, will be allocated if null or too small - * @return The resulting BitArray - this reference should always be used even when passing - * your own row - */ - public BitArray getRow(int y, BitArray row) { - if (row == null || row.getSize() < width) { - row = new BitArray(width); - } - int offset = y * rowSize; - for (int x = 0; x < rowSize; x++) { - row.setBulk(x << 5, bits[offset + x]); - } - return row; - } - - /** - * This is useful in detecting a corner of a 'pure' barcode. - * - * @return {x,y} coordinate of top-left-most 1 bit, or null if it is all white - */ - public int[] getTopLeftOnBit() { - int bitsOffset = 0; - while (bitsOffset < bits.length && bits[bitsOffset] == 0) { - bitsOffset++; - } - if (bitsOffset == bits.length) { - return null; - } - int y = bitsOffset / rowSize; - int x = (bitsOffset % rowSize) << 5; - - int theBits = bits[bitsOffset]; - int bit = 0; - while ((theBits << (31-bit)) == 0) { - bit++; - } - x += bit; - return new int[] {x, y}; - } - - public int[] getBottomRightOnBit() { - int bitsOffset = bits.length - 1; - while (bitsOffset >= 0 && bits[bitsOffset] == 0) { - bitsOffset--; - } - if (bitsOffset < 0) { - return null; - } - - int y = bitsOffset / rowSize; - int x = (bitsOffset % rowSize) << 5; - - int theBits = bits[bitsOffset]; - int bit = 31; - while ((theBits >>> bit) == 0) { - bit--; - } - x += bit; - - return new int[] {x, y}; - } - - /** - * @return The width of the matrix - */ - public int getWidth() { - return width; - } - - /** - * @return The height of the matrix - */ - public int getHeight() { - return height; - } - - public boolean equals(Object o) { - if (!(o instanceof BitMatrix)) { - return false; - } - BitMatrix other = (BitMatrix) o; - if (width != other.width || height != other.height || - rowSize != other.rowSize || bits.length != other.bits.length) { - return false; - } - for (int i = 0; i < bits.length; i++) { - if (bits[i] != other.bits[i]) { - return false; - } - } - return true; - } - - public int hashCode() { - int hash = width; - hash = 31 * hash + width; - hash = 31 * hash + height; - hash = 31 * hash + rowSize; - for (int i = 0; i < bits.length; i++) { - hash = 31 * hash + bits[i]; - } - return hash; - } - - public String toString() { - StringBuffer result = new StringBuffer(height * (width + 1)); - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - result.append(get(x, y) ? "X " : " "); - } - result.append('\n'); - } - return result.toString(); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/BitSource.java b/OpenPGP-Keychain/src/com/google/zxing/common/BitSource.java deleted file mode 100644 index a61ac5105..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/BitSource.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common; - -/** - *

This provides an easy abstraction to read bits at a time from a sequence of bytes, where the - * number of bits read is not often a multiple of 8.

- * - *

This class is thread-safe but not reentrant. Unless the caller modifies the bytes array - * it passed in, in which case all bets are off.

- * - * @author Sean Owen - */ -public final class BitSource { - - private final byte[] bytes; - private int byteOffset; - private int bitOffset; - - /** - * @param bytes bytes from which this will read bits. Bits will be read from the first byte first. - * Bits are read within a byte from most-significant to least-significant bit. - */ - public BitSource(byte[] bytes) { - this.bytes = bytes; - } - - /** - * @param numBits number of bits to read - * @return int representing the bits read. The bits will appear as the least-significant - * bits of the int - * @throws IllegalArgumentException if numBits isn't in [1,32] - */ - public int readBits(int numBits) { - if (numBits < 1 || numBits > 32) { - throw new IllegalArgumentException(); - } - - int result = 0; - - // First, read remainder from current byte - if (bitOffset > 0) { - int bitsLeft = 8 - bitOffset; - int toRead = numBits < bitsLeft ? numBits : bitsLeft; - int bitsToNotRead = bitsLeft - toRead; - int mask = (0xFF >> (8 - toRead)) << bitsToNotRead; - result = (bytes[byteOffset] & mask) >> bitsToNotRead; - numBits -= toRead; - bitOffset += toRead; - if (bitOffset == 8) { - bitOffset = 0; - byteOffset++; - } - } - - // Next read whole bytes - if (numBits > 0) { - while (numBits >= 8) { - result = (result << 8) | (bytes[byteOffset] & 0xFF); - byteOffset++; - numBits -= 8; - } - - // Finally read a partial byte - if (numBits > 0) { - int bitsToNotRead = 8 - numBits; - int mask = (0xFF >> bitsToNotRead) << bitsToNotRead; - result = (result << numBits) | ((bytes[byteOffset] & mask) >> bitsToNotRead); - bitOffset += numBits; - } - } - - return result; - } - - /** - * @return number of bits that can be read successfully - */ - public int available() { - return 8 * (bytes.length - byteOffset) - bitOffset; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/CharacterSetECI.java b/OpenPGP-Keychain/src/com/google/zxing/common/CharacterSetECI.java deleted file mode 100644 index 42b7fa9f6..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/CharacterSetECI.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing.common; - -import java.util.Hashtable; - -/** - * Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1 - * of ISO 18004. - * - * @author Sean Owen - */ -public final class CharacterSetECI extends ECI { - - private static Hashtable VALUE_TO_ECI; - private static Hashtable NAME_TO_ECI; - - private static void initialize() { - VALUE_TO_ECI = new Hashtable(29); - NAME_TO_ECI = new Hashtable(29); - // TODO figure out if these values are even right! - addCharacterSet(0, "Cp437"); - addCharacterSet(1, new String[] {"ISO8859_1", "ISO-8859-1"}); - addCharacterSet(2, "Cp437"); - addCharacterSet(3, new String[] {"ISO8859_1", "ISO-8859-1"}); - addCharacterSet(4, "ISO8859_2"); - addCharacterSet(5, "ISO8859_3"); - addCharacterSet(6, "ISO8859_4"); - addCharacterSet(7, "ISO8859_5"); - addCharacterSet(8, "ISO8859_6"); - addCharacterSet(9, "ISO8859_7"); - addCharacterSet(10, "ISO8859_8"); - addCharacterSet(11, "ISO8859_9"); - addCharacterSet(12, "ISO8859_10"); - addCharacterSet(13, "ISO8859_11"); - addCharacterSet(15, "ISO8859_13"); - addCharacterSet(16, "ISO8859_14"); - addCharacterSet(17, "ISO8859_15"); - addCharacterSet(18, "ISO8859_16"); - addCharacterSet(20, new String[] {"SJIS", "Shift_JIS"}); - } - - private final String encodingName; - - private CharacterSetECI(int value, String encodingName) { - super(value); - this.encodingName = encodingName; - } - - public String getEncodingName() { - return encodingName; - } - - private static void addCharacterSet(int value, String encodingName) { - CharacterSetECI eci = new CharacterSetECI(value, encodingName); - VALUE_TO_ECI.put(new Integer(value), eci); // can't use valueOf - NAME_TO_ECI.put(encodingName, eci); - } - - private static void addCharacterSet(int value, String[] encodingNames) { - CharacterSetECI eci = new CharacterSetECI(value, encodingNames[0]); - VALUE_TO_ECI.put(new Integer(value), eci); // can't use valueOf - for (int i = 0; i < encodingNames.length; i++) { - NAME_TO_ECI.put(encodingNames[i], eci); - } - } - - /** - * @param value character set ECI value - * @return CharacterSetECI representing ECI of given value, or null if it is legal but - * unsupported - * @throws IllegalArgumentException if ECI value is invalid - */ - public static CharacterSetECI getCharacterSetECIByValue(int value) { - if (VALUE_TO_ECI == null) { - initialize(); - } - if (value < 0 || value >= 900) { - throw new IllegalArgumentException("Bad ECI value: " + value); - } - return (CharacterSetECI) VALUE_TO_ECI.get(new Integer(value)); - } - - /** - * @param name character set ECI encoding name - * @return CharacterSetECI representing ECI for character encoding, or null if it is legal - * but unsupported - */ - public static CharacterSetECI getCharacterSetECIByName(String name) { - if (NAME_TO_ECI == null) { - initialize(); - } - return (CharacterSetECI) NAME_TO_ECI.get(name); - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/Collections.java b/OpenPGP-Keychain/src/com/google/zxing/common/Collections.java deleted file mode 100644 index 319ebfe6d..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/Collections.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common; - -import java.util.Vector; - -/** - *

This is basically a substitute for java.util.Collections, which is not - * present in MIDP 2.0 / CLDC 1.1.

- * - * @author Sean Owen - */ -public final class Collections { - - private Collections() { - } - - /** - * Sorts its argument (destructively) using insert sort; in the context of this package - * insertion sort is simple and efficient given its relatively small inputs. - * - * @param vector vector to sort - * @param comparator comparator to define sort ordering - */ - public static void insertionSort(Vector vector, Comparator comparator) { - int max = vector.size(); - for (int i = 1; i < max; i++) { - Object value = vector.elementAt(i); - int j = i - 1; - Object valueB; - while (j >= 0 && comparator.compare((valueB = vector.elementAt(j)), value) > 0) { - vector.setElementAt(valueB, j + 1); - j--; - } - vector.setElementAt(value, j + 1); - } - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/Comparator.java b/OpenPGP-Keychain/src/com/google/zxing/common/Comparator.java deleted file mode 100644 index e1be15e31..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/Comparator.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common; - -/** - * This is merely a clone of Comparator since it is not available in - * CLDC 1.1 / MIDP 2.0. - */ -public interface Comparator { - - int compare(Object o1, Object o2); - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/DecoderResult.java b/OpenPGP-Keychain/src/com/google/zxing/common/DecoderResult.java deleted file mode 100644 index 7e0855333..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/DecoderResult.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common; - -import java.util.Vector; - -/** - *

Encapsulates the result of decoding a matrix of bits. This typically - * applies to 2D barcode formats. For now it contains the raw bytes obtained, - * as well as a String interpretation of those bytes, if applicable.

- * - * @author Sean Owen - */ -public final class DecoderResult { - - private final byte[] rawBytes; - private final String text; - private final Vector byteSegments; - private final String ecLevel; - - public DecoderResult(byte[] rawBytes, String text, Vector byteSegments, String ecLevel) { - if (rawBytes == null && text == null) { - throw new IllegalArgumentException(); - } - this.rawBytes = rawBytes; - this.text = text; - this.byteSegments = byteSegments; - this.ecLevel = ecLevel; - } - - public byte[] getRawBytes() { - return rawBytes; - } - - public String getText() { - return text; - } - - public Vector getByteSegments() { - return byteSegments; - } - - public String getECLevel() { - return ecLevel; - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/DefaultGridSampler.java b/OpenPGP-Keychain/src/com/google/zxing/common/DefaultGridSampler.java deleted file mode 100644 index 74c9e7c6b..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/DefaultGridSampler.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common; - -import com.google.zxing.NotFoundException; - -/** - * @author Sean Owen - */ -public final class DefaultGridSampler extends GridSampler { - - public BitMatrix sampleGrid(BitMatrix image, - int dimensionX, - int dimensionY, - float p1ToX, float p1ToY, - float p2ToX, float p2ToY, - float p3ToX, float p3ToY, - float p4ToX, float p4ToY, - float p1FromX, float p1FromY, - float p2FromX, float p2FromY, - float p3FromX, float p3FromY, - float p4FromX, float p4FromY) throws NotFoundException { - - PerspectiveTransform transform = PerspectiveTransform.quadrilateralToQuadrilateral( - p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, - p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY); - - return sampleGrid(image, dimensionX, dimensionY, transform); - } - - public BitMatrix sampleGrid(BitMatrix image, - int dimensionX, - int dimensionY, - PerspectiveTransform transform) throws NotFoundException { - if (dimensionX <= 0 || dimensionY <= 0) { - throw NotFoundException.getNotFoundInstance(); - } - BitMatrix bits = new BitMatrix(dimensionX, dimensionY); - float[] points = new float[dimensionX << 1]; - for (int y = 0; y < dimensionY; y++) { - int max = points.length; - float iValue = (float) y + 0.5f; - for (int x = 0; x < max; x += 2) { - points[x] = (float) (x >> 1) + 0.5f; - points[x + 1] = iValue; - } - transform.transformPoints(points); - // Quick check to see if points transformed to something inside the image; - // sufficient to check the endpoints - checkAndNudgePoints(image, points); - try { - for (int x = 0; x < max; x += 2) { - if (image.get((int) points[x], (int) points[x + 1])) { - // Black(-ish) pixel - bits.set(x >> 1, y); - } - } - } catch (ArrayIndexOutOfBoundsException aioobe) { - // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting - // transform gets "twisted" such that it maps a straight line of points to a set of points - // whose endpoints are in bounds, but others are not. There is probably some mathematical - // way to detect this about the transformation that I don't know yet. - // This results in an ugly runtime exception despite our clever checks above -- can't have - // that. We could check each point's coordinates but that feels duplicative. We settle for - // catching and wrapping ArrayIndexOutOfBoundsException. - throw NotFoundException.getNotFoundInstance(); - } - } - return bits; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/DetectorResult.java b/OpenPGP-Keychain/src/com/google/zxing/common/DetectorResult.java deleted file mode 100644 index ea4794d17..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/DetectorResult.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common; - -import com.google.zxing.ResultPoint; - -/** - *

Encapsulates the result of detecting a barcode in an image. This includes the raw - * matrix of black/white pixels corresponding to the barcode, and possibly points of interest - * in the image, like the location of finder patterns or corners of the barcode in the image.

- * - * @author Sean Owen - */ -public class DetectorResult { - - private final BitMatrix bits; - private final ResultPoint[] points; - - public DetectorResult(BitMatrix bits, ResultPoint[] points) { - this.bits = bits; - this.points = points; - } - - public BitMatrix getBits() { - return bits; - } - - public ResultPoint[] getPoints() { - return points; - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/ECI.java b/OpenPGP-Keychain/src/com/google/zxing/common/ECI.java deleted file mode 100644 index 444c779c2..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/ECI.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing.common; - -/** - * Superclass of classes encapsulating types ECIs, according to "Extended Channel Interpretations" - * 5.3 of ISO 18004. - * - * @author Sean Owen - */ -public abstract class ECI { - - private final int value; - - ECI(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - - /** - * @param value ECI value - * @return ECI representing ECI of given value, or null if it is legal but unsupported - * @throws IllegalArgumentException if ECI value is invalid - */ - public static ECI getECIByValue(int value) { - if (value < 0 || value > 999999) { - throw new IllegalArgumentException("Bad ECI value: " + value); - } - if (value < 900) { // Character set ECIs use 000000 - 000899 - return CharacterSetECI.getCharacterSetECIByValue(value); - } - return null; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/GlobalHistogramBinarizer.java b/OpenPGP-Keychain/src/com/google/zxing/common/GlobalHistogramBinarizer.java deleted file mode 100644 index 4fa2a887b..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/GlobalHistogramBinarizer.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * 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 com.google.zxing.common; - -import com.google.zxing.Binarizer; -import com.google.zxing.LuminanceSource; -import com.google.zxing.NotFoundException; - -/** - * This Binarizer implementation uses the old ZXing global histogram approach. It is suitable - * for low-end mobile devices which don't have enough CPU or memory to use a local thresholding - * algorithm. However, because it picks a global black point, it cannot handle difficult shadows - * and gradients. - * - * Faster mobile devices and all desktop applications should probably use HybridBinarizer instead. - * - * @author dswitkin@google.com (Daniel Switkin) - * @author Sean Owen - */ -public class GlobalHistogramBinarizer extends Binarizer { - - private static final int LUMINANCE_BITS = 5; - private static final int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS; - private static final int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS; - - private byte[] luminances = null; - private int[] buckets = null; - - public GlobalHistogramBinarizer(LuminanceSource source) { - super(source); - } - - // Applies simple sharpening to the row data to improve performance of the 1D Readers. - public BitArray getBlackRow(int y, BitArray row) throws NotFoundException { - LuminanceSource source = getLuminanceSource(); - int width = source.getWidth(); - if (row == null || row.getSize() < width) { - row = new BitArray(width); - } else { - row.clear(); - } - - initArrays(width); - byte[] localLuminances = source.getRow(y, luminances); - int[] localBuckets = buckets; - for (int x = 0; x < width; x++) { - int pixel = localLuminances[x] & 0xff; - localBuckets[pixel >> LUMINANCE_SHIFT]++; - } - int blackPoint = estimateBlackPoint(localBuckets); - - int left = localLuminances[0] & 0xff; - int center = localLuminances[1] & 0xff; - for (int x = 1; x < width - 1; x++) { - int right = localLuminances[x + 1] & 0xff; - // A simple -1 4 -1 box filter with a weight of 2. - int luminance = ((center << 2) - left - right) >> 1; - if (luminance < blackPoint) { - row.set(x); - } - left = center; - center = right; - } - return row; - } - - // Does not sharpen the data, as this call is intended to only be used by 2D Readers. - public BitMatrix getBlackMatrix() throws NotFoundException { - LuminanceSource source = getLuminanceSource(); - int width = source.getWidth(); - int height = source.getHeight(); - BitMatrix matrix = new BitMatrix(width, height); - - // Quickly calculates the histogram by sampling four rows from the image. This proved to be - // more robust on the blackbox tests than sampling a diagonal as we used to do. - initArrays(width); - int[] localBuckets = buckets; - for (int y = 1; y < 5; y++) { - int row = height * y / 5; - byte[] localLuminances = source.getRow(row, luminances); - int right = (width << 2) / 5; - for (int x = width / 5; x < right; x++) { - int pixel = localLuminances[x] & 0xff; - localBuckets[pixel >> LUMINANCE_SHIFT]++; - } - } - int blackPoint = estimateBlackPoint(localBuckets); - - // We delay reading the entire image luminance until the black point estimation succeeds. - // Although we end up reading four rows twice, it is consistent with our motto of - // "fail quickly" which is necessary for continuous scanning. - byte[] localLuminances = source.getMatrix(); - for (int y = 0; y < height; y++) { - int offset = y * width; - for (int x = 0; x< width; x++) { - int pixel = localLuminances[offset + x] & 0xff; - if (pixel < blackPoint) { - matrix.set(x, y); - } - } - } - - return matrix; - } - - public Binarizer createBinarizer(LuminanceSource source) { - return new GlobalHistogramBinarizer(source); - } - - private void initArrays(int luminanceSize) { - if (luminances == null || luminances.length < luminanceSize) { - luminances = new byte[luminanceSize]; - } - if (buckets == null) { - buckets = new int[LUMINANCE_BUCKETS]; - } else { - for (int x = 0; x < LUMINANCE_BUCKETS; x++) { - buckets[x] = 0; - } - } - } - - private static int estimateBlackPoint(int[] buckets) throws NotFoundException { - // Find the tallest peak in the histogram. - int numBuckets = buckets.length; - int maxBucketCount = 0; - int firstPeak = 0; - int firstPeakSize = 0; - for (int x = 0; x < numBuckets; x++) { - if (buckets[x] > firstPeakSize) { - firstPeak = x; - firstPeakSize = buckets[x]; - } - if (buckets[x] > maxBucketCount) { - maxBucketCount = buckets[x]; - } - } - - // Find the second-tallest peak which is somewhat far from the tallest peak. - int secondPeak = 0; - int secondPeakScore = 0; - for (int x = 0; x < numBuckets; x++) { - int distanceToBiggest = x - firstPeak; - // Encourage more distant second peaks by multiplying by square of distance. - int score = buckets[x] * distanceToBiggest * distanceToBiggest; - if (score > secondPeakScore) { - secondPeak = x; - secondPeakScore = score; - } - } - - // Make sure firstPeak corresponds to the black peak. - if (firstPeak > secondPeak) { - int temp = firstPeak; - firstPeak = secondPeak; - secondPeak = temp; - } - - // If there is too little contrast in the image to pick a meaningful black point, throw rather - // than waste time trying to decode the image, and risk false positives. - if (secondPeak - firstPeak <= numBuckets >> 4) { - throw NotFoundException.getNotFoundInstance(); - } - - // Find a valley between them that is low and closer to the white peak. - int bestValley = secondPeak - 1; - int bestValleyScore = -1; - for (int x = secondPeak - 1; x > firstPeak; x--) { - int fromFirst = x - firstPeak; - int score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets[x]); - if (score > bestValleyScore) { - bestValley = x; - bestValleyScore = score; - } - } - - return bestValley << LUMINANCE_SHIFT; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/GridSampler.java b/OpenPGP-Keychain/src/com/google/zxing/common/GridSampler.java deleted file mode 100644 index 7f26c264e..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/GridSampler.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common; - -import com.google.zxing.NotFoundException; - -/** - * Implementations of this class can, given locations of finder patterns for a QR code in an - * image, sample the right points in the image to reconstruct the QR code, accounting for - * perspective distortion. It is abstracted since it is relatively expensive and should be allowed - * to take advantage of platform-specific optimized implementations, like Sun's Java Advanced - * Imaging library, but which may not be available in other environments such as J2ME, and vice - * versa. - * - * The implementation used can be controlled by calling {@link #setGridSampler(GridSampler)} - * with an instance of a class which implements this interface. - * - * @author Sean Owen - */ -public abstract class GridSampler { - - private static GridSampler gridSampler = new DefaultGridSampler(); - - /** - * Sets the implementation of GridSampler used by the library. One global - * instance is stored, which may sound problematic. But, the implementation provided - * ought to be appropriate for the entire platform, and all uses of this library - * in the whole lifetime of the JVM. For instance, an Android activity can swap in - * an implementation that takes advantage of native platform libraries. - * - * @param newGridSampler The platform-specific object to install. - */ - public static void setGridSampler(GridSampler newGridSampler) { - if (newGridSampler == null) { - throw new IllegalArgumentException(); - } - gridSampler = newGridSampler; - } - - /** - * @return the current implementation of GridSampler - */ - public static GridSampler getInstance() { - return gridSampler; - } - - /** - * Samples an image for a rectangular matrix of bits of the given dimension. - * @param image image to sample - * @param dimensionX width of {@link BitMatrix} to sample from image - * @param dimensionY height of {@link BitMatrix} to sample from image - * @return {@link BitMatrix} representing a grid of points sampled from the image within a region - * defined by the "from" parameters - * @throws NotFoundException if image can't be sampled, for example, if the transformation defined - * by the given points is invalid or results in sampling outside the image boundaries - */ - public abstract BitMatrix sampleGrid(BitMatrix image, - int dimensionX, - int dimensionY, - float p1ToX, float p1ToY, - float p2ToX, float p2ToY, - float p3ToX, float p3ToY, - float p4ToX, float p4ToY, - float p1FromX, float p1FromY, - float p2FromX, float p2FromY, - float p3FromX, float p3FromY, - float p4FromX, float p4FromY) throws NotFoundException; - - public abstract BitMatrix sampleGrid(BitMatrix image, - int dimensionX, - int dimensionY, - PerspectiveTransform transform) throws NotFoundException; - - /** - *

Checks a set of points that have been transformed to sample points on an image against - * the image's dimensions to see if the point are even within the image.

- * - *

This method will actually "nudge" the endpoints back onto the image if they are found to be - * barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder - * patterns in an image where the QR Code runs all the way to the image border.

- * - *

For efficiency, the method will check points from either end of the line until one is found - * to be within the image. Because the set of points are assumed to be linear, this is valid.

- * - * @param image image into which the points should map - * @param points actual points in x1,y1,...,xn,yn form - * @throws NotFoundException if an endpoint is lies outside the image boundaries - */ - protected static void checkAndNudgePoints(BitMatrix image, float[] points) throws NotFoundException { - int width = image.getWidth(); - int height = image.getHeight(); - // Check and nudge points from start until we see some that are OK: - boolean nudged = true; - for (int offset = 0; offset < points.length && nudged; offset += 2) { - int x = (int) points[offset]; - int y = (int) points[offset + 1]; - if (x < -1 || x > width || y < -1 || y > height) { - throw NotFoundException.getNotFoundInstance(); - } - nudged = false; - if (x == -1) { - points[offset] = 0.0f; - nudged = true; - } else if (x == width) { - points[offset] = width - 1; - nudged = true; - } - if (y == -1) { - points[offset + 1] = 0.0f; - nudged = true; - } else if (y == height) { - points[offset + 1] = height - 1; - nudged = true; - } - } - // Check and nudge points from end: - nudged = true; - for (int offset = points.length - 2; offset >= 0 && nudged; offset -= 2) { - int x = (int) points[offset]; - int y = (int) points[offset + 1]; - if (x < -1 || x > width || y < -1 || y > height) { - throw NotFoundException.getNotFoundInstance(); - } - nudged = false; - if (x == -1) { - points[offset] = 0.0f; - nudged = true; - } else if (x == width) { - points[offset] = width - 1; - nudged = true; - } - if (y == -1) { - points[offset + 1] = 0.0f; - nudged = true; - } else if (y == height) { - points[offset + 1] = height - 1; - nudged = true; - } - } - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/HybridBinarizer.java b/OpenPGP-Keychain/src/com/google/zxing/common/HybridBinarizer.java deleted file mode 100644 index b482c1a22..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/HybridBinarizer.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * 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 com.google.zxing.common; - -import com.google.zxing.Binarizer; -import com.google.zxing.LuminanceSource; -import com.google.zxing.NotFoundException; - -/** - * This class implements a local thresholding algorithm, which while slower than the - * GlobalHistogramBinarizer, is fairly efficient for what it does. It is designed for - * high frequency images of barcodes with black data on white backgrounds. For this application, - * it does a much better job than a global blackpoint with severe shadows and gradients. - * However it tends to produce artifacts on lower frequency images and is therefore not - * a good general purpose binarizer for uses outside ZXing. - * - * This class extends GlobalHistogramBinarizer, using the older histogram approach for 1D readers, - * and the newer local approach for 2D readers. 1D decoding using a per-row histogram is already - * inherently local, and only fails for horizontal gradients. We can revisit that problem later, - * but for now it was not a win to use local blocks for 1D. - * - * This Binarizer is the default for the unit tests and the recommended class for library users. - * - * @author dswitkin@google.com (Daniel Switkin) - */ -public final class HybridBinarizer extends GlobalHistogramBinarizer { - - // This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels. - // So this is the smallest dimension in each axis we can accept. - private static final int MINIMUM_DIMENSION = 40; - - private BitMatrix matrix = null; - - public HybridBinarizer(LuminanceSource source) { - super(source); - } - - public BitMatrix getBlackMatrix() throws NotFoundException { - binarizeEntireImage(); - return matrix; - } - - public Binarizer createBinarizer(LuminanceSource source) { - return new HybridBinarizer(source); - } - - // Calculates the final BitMatrix once for all requests. This could be called once from the - // constructor instead, but there are some advantages to doing it lazily, such as making - // profiling easier, and not doing heavy lifting when callers don't expect it. - private void binarizeEntireImage() throws NotFoundException { - if (matrix == null) { - LuminanceSource source = getLuminanceSource(); - if (source.getWidth() >= MINIMUM_DIMENSION && source.getHeight() >= MINIMUM_DIMENSION) { - byte[] luminances = source.getMatrix(); - int width = source.getWidth(); - int height = source.getHeight(); - int subWidth = width >> 3; - if ((width & 0x07) != 0) { - subWidth++; - } - int subHeight = height >> 3; - if ((height & 0x07) != 0) { - subHeight++; - } - int[][] blackPoints = calculateBlackPoints(luminances, subWidth, subHeight, width, height); - - matrix = new BitMatrix(width, height); - calculateThresholdForBlock(luminances, subWidth, subHeight, width, height, blackPoints, matrix); - } else { - // If the image is too small, fall back to the global histogram approach. - matrix = super.getBlackMatrix(); - } - } - } - - // For each 8x8 block in the image, calculate the average black point using a 5x5 grid - // of the blocks around it. Also handles the corner cases (fractional blocks are computed based - // on the last 8 pixels in the row/column which are also used in the previous block). - private static void calculateThresholdForBlock(byte[] luminances, int subWidth, int subHeight, - int width, int height, int[][] blackPoints, BitMatrix matrix) { - for (int y = 0; y < subHeight; y++) { - int yoffset = y << 3; - if ((yoffset + 8) >= height) { - yoffset = height - 8; - } - for (int x = 0; x < subWidth; x++) { - int xoffset = x << 3; - if ((xoffset + 8) >= width) { - xoffset = width - 8; - } - int left = x > 1 ? x : 2; - left = left < subWidth - 2 ? left : subWidth - 3; - int top = y > 1 ? y : 2; - top = top < subHeight - 2 ? top : subHeight - 3; - int sum = 0; - for (int z = -2; z <= 2; z++) { - int[] blackRow = blackPoints[top + z]; - sum += blackRow[left - 2]; - sum += blackRow[left - 1]; - sum += blackRow[left]; - sum += blackRow[left + 1]; - sum += blackRow[left + 2]; - } - int average = sum / 25; - threshold8x8Block(luminances, xoffset, yoffset, average, width, matrix); - } - } - } - - // Applies a single threshold to an 8x8 block of pixels. - private static void threshold8x8Block(byte[] luminances, int xoffset, int yoffset, int threshold, - int stride, BitMatrix matrix) { - for (int y = 0; y < 8; y++) { - int offset = (yoffset + y) * stride + xoffset; - for (int x = 0; x < 8; x++) { - int pixel = luminances[offset + x] & 0xff; - if (pixel < threshold) { - matrix.set(xoffset + x, yoffset + y); - } - } - } - } - - // Calculates a single black point for each 8x8 block of pixels and saves it away. - private static int[][] calculateBlackPoints(byte[] luminances, int subWidth, int subHeight, - int width, int height) { - int[][] blackPoints = new int[subHeight][subWidth]; - for (int y = 0; y < subHeight; y++) { - int yoffset = y << 3; - if ((yoffset + 8) >= height) { - yoffset = height - 8; - } - for (int x = 0; x < subWidth; x++) { - int xoffset = x << 3; - if ((xoffset + 8) >= width) { - xoffset = width - 8; - } - int sum = 0; - int min = 255; - int max = 0; - for (int yy = 0; yy < 8; yy++) { - int offset = (yoffset + yy) * width + xoffset; - for (int xx = 0; xx < 8; xx++) { - int pixel = luminances[offset + xx] & 0xff; - sum += pixel; - if (pixel < min) { - min = pixel; - } - if (pixel > max) { - max = pixel; - } - } - } - - // If the contrast is inadequate, use half the minimum, so that this block will be - // treated as part of the white background, but won't drag down neighboring blocks - // too much. - int average; - if (max - min > 24) { - average = sum >> 6; - } else { - // When min == max == 0, let average be 1 so all is black - average = max == 0 ? 1 : min >> 1; - } - blackPoints[y][x] = average; - } - } - return blackPoints; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/PerspectiveTransform.java b/OpenPGP-Keychain/src/com/google/zxing/common/PerspectiveTransform.java deleted file mode 100644 index 9e65baff1..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/PerspectiveTransform.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common; - -/** - *

This class implements a perspective transform in two dimensions. Given four source and four - * destination points, it will compute the transformation implied between them. The code is based - * directly upon section 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.

- * - * @author Sean Owen - */ -public final class PerspectiveTransform { - - private final float a11, a12, a13, a21, a22, a23, a31, a32, a33; - - private PerspectiveTransform(float a11, float a21, float a31, - float a12, float a22, float a32, - float a13, float a23, float a33) { - this.a11 = a11; - this.a12 = a12; - this.a13 = a13; - this.a21 = a21; - this.a22 = a22; - this.a23 = a23; - this.a31 = a31; - this.a32 = a32; - this.a33 = a33; - } - - public static PerspectiveTransform quadrilateralToQuadrilateral(float x0, float y0, - float x1, float y1, - float x2, float y2, - float x3, float y3, - float x0p, float y0p, - float x1p, float y1p, - float x2p, float y2p, - float x3p, float y3p) { - - PerspectiveTransform qToS = quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3); - PerspectiveTransform sToQ = squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); - return sToQ.times(qToS); - } - - public void transformPoints(float[] points) { - int max = points.length; - float a11 = this.a11; - float a12 = this.a12; - float a13 = this.a13; - float a21 = this.a21; - float a22 = this.a22; - float a23 = this.a23; - float a31 = this.a31; - float a32 = this.a32; - float a33 = this.a33; - for (int i = 0; i < max; i += 2) { - float x = points[i]; - float y = points[i + 1]; - float denominator = a13 * x + a23 * y + a33; - points[i] = (a11 * x + a21 * y + a31) / denominator; - points[i + 1] = (a12 * x + a22 * y + a32) / denominator; - } - } - - /** Convenience method, not optimized for performance. */ - public void transformPoints(float[] xValues, float[] yValues) { - int n = xValues.length; - for (int i = 0; i < n; i ++) { - float x = xValues[i]; - float y = yValues[i]; - float denominator = a13 * x + a23 * y + a33; - xValues[i] = (a11 * x + a21 * y + a31) / denominator; - yValues[i] = (a12 * x + a22 * y + a32) / denominator; - } - } - - public static PerspectiveTransform squareToQuadrilateral(float x0, float y0, - float x1, float y1, - float x2, float y2, - float x3, float y3) { - float dy2 = y3 - y2; - float dy3 = y0 - y1 + y2 - y3; - if (dy2 == 0.0f && dy3 == 0.0f) { - return new PerspectiveTransform(x1 - x0, x2 - x1, x0, - y1 - y0, y2 - y1, y0, - 0.0f, 0.0f, 1.0f); - } else { - float dx1 = x1 - x2; - float dx2 = x3 - x2; - float dx3 = x0 - x1 + x2 - x3; - float dy1 = y1 - y2; - float denominator = dx1 * dy2 - dx2 * dy1; - float a13 = (dx3 * dy2 - dx2 * dy3) / denominator; - float a23 = (dx1 * dy3 - dx3 * dy1) / denominator; - return new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, - y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0, - a13, a23, 1.0f); - } - } - - public static PerspectiveTransform quadrilateralToSquare(float x0, float y0, - float x1, float y1, - float x2, float y2, - float x3, float y3) { - // Here, the adjoint serves as the inverse: - return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint(); - } - - PerspectiveTransform buildAdjoint() { - // Adjoint is the transpose of the cofactor matrix: - return new PerspectiveTransform(a22 * a33 - a23 * a32, - a23 * a31 - a21 * a33, - a21 * a32 - a22 * a31, - a13 * a32 - a12 * a33, - a11 * a33 - a13 * a31, - a12 * a31 - a11 * a32, - a12 * a23 - a13 * a22, - a13 * a21 - a11 * a23, - a11 * a22 - a12 * a21); - } - - PerspectiveTransform times(PerspectiveTransform other) { - return new PerspectiveTransform(a11 * other.a11 + a21 * other.a12 + a31 * other.a13, - a11 * other.a21 + a21 * other.a22 + a31 * other.a23, - a11 * other.a31 + a21 * other.a32 + a31 * other.a33, - a12 * other.a11 + a22 * other.a12 + a32 * other.a13, - a12 * other.a21 + a22 * other.a22 + a32 * other.a23, - a12 * other.a31 + a22 * other.a32 + a32 * other.a33, - a13 * other.a11 + a23 * other.a12 + a33 * other.a13, - a13 * other.a21 + a23 * other.a22 + a33 * other.a23, - a13 * other.a31 + a23 * other.a32 + a33 * other.a33); - - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/StringUtils.java b/OpenPGP-Keychain/src/com/google/zxing/common/StringUtils.java deleted file mode 100644 index 97999f997..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/StringUtils.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * 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 com.google.zxing.common; - -import java.util.Hashtable; - -import com.google.zxing.DecodeHintType; - -/** - * Common string-related functions. - * - * @author Sean Owen - */ -public final class StringUtils { - - private static final String PLATFORM_DEFAULT_ENCODING = - System.getProperty("file.encoding"); - public static final String SHIFT_JIS = "SJIS"; - public static final String GB2312 = "GB2312"; - private static final String EUC_JP = "EUC_JP"; - private static final String UTF8 = "UTF8"; - private static final String ISO88591 = "ISO8859_1"; - private static final boolean ASSUME_SHIFT_JIS = - SHIFT_JIS.equalsIgnoreCase(PLATFORM_DEFAULT_ENCODING) || - EUC_JP.equalsIgnoreCase(PLATFORM_DEFAULT_ENCODING); - - private StringUtils() {} - - /** - * @param bytes bytes encoding a string, whose encoding should be guessed - * @param hints decode hints if applicable - * @return name of guessed encoding; at the moment will only guess one of: - * {@link #SHIFT_JIS}, {@link #UTF8}, {@link #ISO88591}, or the platform - * default encoding if none of these can possibly be correct - */ - public static String guessEncoding(byte[] bytes, Hashtable hints) { - if (hints != null) { - String characterSet = (String) hints.get(DecodeHintType.CHARACTER_SET); - if (characterSet != null) { - return characterSet; - } - } - // Does it start with the UTF-8 byte order mark? then guess it's UTF-8 - if (bytes.length > 3 && - bytes[0] == (byte) 0xEF && - bytes[1] == (byte) 0xBB && - bytes[2] == (byte) 0xBF) { - return UTF8; - } - // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS, - // which should be by far the most common encodings. ISO-8859-1 - // should not have bytes in the 0x80 - 0x9F range, while Shift_JIS - // uses this as a first byte of a two-byte character. If we see this - // followed by a valid second byte in Shift_JIS, assume it is Shift_JIS. - // If we see something else in that second byte, we'll make the risky guess - // that it's UTF-8. - int length = bytes.length; - boolean canBeISO88591 = true; - boolean canBeShiftJIS = true; - boolean canBeUTF8 = true; - int utf8BytesLeft = 0; - int maybeDoubleByteCount = 0; - int maybeSingleByteKatakanaCount = 0; - boolean sawLatin1Supplement = false; - boolean sawUTF8Start = false; - boolean lastWasPossibleDoubleByteStart = false; - - for (int i = 0; - i < length && (canBeISO88591 || canBeShiftJIS || canBeUTF8); - i++) { - - int value = bytes[i] & 0xFF; - - // UTF-8 stuff - if (value >= 0x80 && value <= 0xBF) { - if (utf8BytesLeft > 0) { - utf8BytesLeft--; - } - } else { - if (utf8BytesLeft > 0) { - canBeUTF8 = false; - } - if (value >= 0xC0 && value <= 0xFD) { - sawUTF8Start = true; - int valueCopy = value; - while ((valueCopy & 0x40) != 0) { - utf8BytesLeft++; - valueCopy <<= 1; - } - } - } - - // ISO-8859-1 stuff - - if ((value == 0xC2 || value == 0xC3) && i < length - 1) { - // This is really a poor hack. The slightly more exotic characters people might want to put in - // a QR Code, by which I mean the Latin-1 supplement characters (e.g. u-umlaut) have encodings - // that start with 0xC2 followed by [0xA0,0xBF], or start with 0xC3 followed by [0x80,0xBF]. - int nextValue = bytes[i + 1] & 0xFF; - if (nextValue <= 0xBF && - ((value == 0xC2 && nextValue >= 0xA0) || (value == 0xC3 && nextValue >= 0x80))) { - sawLatin1Supplement = true; - } - } - if (value >= 0x7F && value <= 0x9F) { - canBeISO88591 = false; - } - - // Shift_JIS stuff - - if (value >= 0xA1 && value <= 0xDF) { - // count the number of characters that might be a Shift_JIS single-byte Katakana character - if (!lastWasPossibleDoubleByteStart) { - maybeSingleByteKatakanaCount++; - } - } - if (!lastWasPossibleDoubleByteStart && - ((value >= 0xF0 && value <= 0xFF) || value == 0x80 || value == 0xA0)) { - canBeShiftJIS = false; - } - if ((value >= 0x81 && value <= 0x9F) || (value >= 0xE0 && value <= 0xEF)) { - // These start double-byte characters in Shift_JIS. Let's see if it's followed by a valid - // second byte. - if (lastWasPossibleDoubleByteStart) { - // If we just checked this and the last byte for being a valid double-byte - // char, don't check starting on this byte. If this and the last byte - // formed a valid pair, then this shouldn't be checked to see if it starts - // a double byte pair of course. - lastWasPossibleDoubleByteStart = false; - } else { - // ... otherwise do check to see if this plus the next byte form a valid - // double byte pair encoding a character. - lastWasPossibleDoubleByteStart = true; - if (i >= bytes.length - 1) { - canBeShiftJIS = false; - } else { - int nextValue = bytes[i + 1] & 0xFF; - if (nextValue < 0x40 || nextValue > 0xFC) { - canBeShiftJIS = false; - } else { - maybeDoubleByteCount++; - } - // There is some conflicting information out there about which bytes can follow which in - // double-byte Shift_JIS characters. The rule above seems to be the one that matches practice. - } - } - } else { - lastWasPossibleDoubleByteStart = false; - } - } - if (utf8BytesLeft > 0) { - canBeUTF8 = false; - } - - // Easy -- if assuming Shift_JIS and no evidence it can't be, done - if (canBeShiftJIS && ASSUME_SHIFT_JIS) { - return SHIFT_JIS; - } - if (canBeUTF8 && sawUTF8Start) { - return UTF8; - } - // Distinguishing Shift_JIS and ISO-8859-1 can be a little tough. The crude heuristic is: - // - If we saw - // - at least 3 bytes that starts a double-byte value (bytes that are rare in ISO-8859-1), or - // - over 5% of bytes could be single-byte Katakana (also rare in ISO-8859-1), - // - and, saw no sequences that are invalid in Shift_JIS, then we conclude Shift_JIS - if (canBeShiftJIS && (maybeDoubleByteCount >= 3 || 20 * maybeSingleByteKatakanaCount > length)) { - return SHIFT_JIS; - } - // Otherwise, we default to ISO-8859-1 unless we know it can't be - if (!sawLatin1Supplement && canBeISO88591) { - return ISO88591; - } - // Otherwise, we take a wild guess with platform encoding - return PLATFORM_DEFAULT_ENCODING; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/detector/MonochromeRectangleDetector.java b/OpenPGP-Keychain/src/com/google/zxing/common/detector/MonochromeRectangleDetector.java deleted file mode 100644 index 950a22364..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/detector/MonochromeRectangleDetector.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * 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 com.google.zxing.common.detector; - -import com.google.zxing.NotFoundException; -import com.google.zxing.ResultPoint; -import com.google.zxing.common.BitMatrix; - -/** - *

A somewhat generic detector that looks for a barcode-like rectangular region within an image. - * It looks within a mostly white region of an image for a region of black and white, but mostly - * black. It returns the four corners of the region, as best it can determine.

- * - * @author Sean Owen - */ -public final class MonochromeRectangleDetector { - - private static final int MAX_MODULES = 32; - - private final BitMatrix image; - - public MonochromeRectangleDetector(BitMatrix image) { - this.image = image; - } - - /** - *

Detects a rectangular region of black and white -- mostly black -- with a region of mostly - * white, in an image.

- * - * @return {@link ResultPoint}[] describing the corners of the rectangular region. The first and - * last points are opposed on the diagonal, as are the second and third. The first point will be - * the topmost point and the last, the bottommost. The second point will be leftmost and the - * third, the rightmost - * @throws NotFoundException if no Data Matrix Code can be found - */ - public ResultPoint[] detect() throws NotFoundException { - int height = image.getHeight(); - int width = image.getWidth(); - int halfHeight = height >> 1; - int halfWidth = width >> 1; - int deltaY = Math.max(1, height / (MAX_MODULES << 3)); - int deltaX = Math.max(1, width / (MAX_MODULES << 3)); - - int top = 0; - int bottom = height; - int left = 0; - int right = width; - ResultPoint pointA = findCornerFromCenter(halfWidth, 0, left, right, - halfHeight, -deltaY, top, bottom, halfWidth >> 1); - top = (int) pointA.getY() - 1; - ResultPoint pointB = findCornerFromCenter(halfWidth, -deltaX, left, right, - halfHeight, 0, top, bottom, halfHeight >> 1); - left = (int) pointB.getX() - 1; - ResultPoint pointC = findCornerFromCenter(halfWidth, deltaX, left, right, - halfHeight, 0, top, bottom, halfHeight >> 1); - right = (int) pointC.getX() + 1; - ResultPoint pointD = findCornerFromCenter(halfWidth, 0, left, right, - halfHeight, deltaY, top, bottom, halfWidth >> 1); - bottom = (int) pointD.getY() + 1; - - // Go try to find point A again with better information -- might have been off at first. - pointA = findCornerFromCenter(halfWidth, 0, left, right, - halfHeight, -deltaY, top, bottom, halfWidth >> 2); - - return new ResultPoint[] { pointA, pointB, pointC, pointD }; - } - - /** - * Attempts to locate a corner of the barcode by scanning up, down, left or right from a center - * point which should be within the barcode. - * - * @param centerX center's x component (horizontal) - * @param deltaX same as deltaY but change in x per step instead - * @param left minimum value of x - * @param right maximum value of x - * @param centerY center's y component (vertical) - * @param deltaY change in y per step. If scanning up this is negative; down, positive; - * left or right, 0 - * @param top minimum value of y to search through (meaningless when di == 0) - * @param bottom maximum value of y - * @param maxWhiteRun maximum run of white pixels that can still be considered to be within - * the barcode - * @return a {@link com.google.zxing.ResultPoint} encapsulating the corner that was found - * @throws NotFoundException if such a point cannot be found - */ - private ResultPoint findCornerFromCenter(int centerX, int deltaX, int left, int right, - int centerY, int deltaY, int top, int bottom, int maxWhiteRun) throws NotFoundException { - int[] lastRange = null; - for (int y = centerY, x = centerX; - y < bottom && y >= top && x < right && x >= left; - y += deltaY, x += deltaX) { - int[] range; - if (deltaX == 0) { - // horizontal slices, up and down - range = blackWhiteRange(y, maxWhiteRun, left, right, true); - } else { - // vertical slices, left and right - range = blackWhiteRange(x, maxWhiteRun, top, bottom, false); - } - if (range == null) { - if (lastRange == null) { - throw NotFoundException.getNotFoundInstance(); - } - // lastRange was found - if (deltaX == 0) { - int lastY = y - deltaY; - if (lastRange[0] < centerX) { - if (lastRange[1] > centerX) { - // straddle, choose one or the other based on direction - return new ResultPoint(deltaY > 0 ? lastRange[0] : lastRange[1], lastY); - } - return new ResultPoint(lastRange[0], lastY); - } else { - return new ResultPoint(lastRange[1], lastY); - } - } else { - int lastX = x - deltaX; - if (lastRange[0] < centerY) { - if (lastRange[1] > centerY) { - return new ResultPoint(lastX, deltaX < 0 ? lastRange[0] : lastRange[1]); - } - return new ResultPoint(lastX, lastRange[0]); - } else { - return new ResultPoint(lastX, lastRange[1]); - } - } - } - lastRange = range; - } - throw NotFoundException.getNotFoundInstance(); - } - - /** - * Computes the start and end of a region of pixels, either horizontally or vertically, that could - * be part of a Data Matrix barcode. - * - * @param fixedDimension if scanning horizontally, this is the row (the fixed vertical location) - * where we are scanning. If scanning vertically it's the column, the fixed horizontal location - * @param maxWhiteRun largest run of white pixels that can still be considered part of the - * barcode region - * @param minDim minimum pixel location, horizontally or vertically, to consider - * @param maxDim maximum pixel location, horizontally or vertically, to consider - * @param horizontal if true, we're scanning left-right, instead of up-down - * @return int[] with start and end of found range, or null if no such range is found - * (e.g. only white was found) - */ - private int[] blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim, - boolean horizontal) { - - int center = (minDim + maxDim) >> 1; - - // Scan left/up first - int start = center; - while (start >= minDim) { - if (horizontal ? image.get(start, fixedDimension) : image.get(fixedDimension, start)) { - start--; - } else { - int whiteRunStart = start; - do { - start--; - } while (start >= minDim && !(horizontal ? image.get(start, fixedDimension) : - image.get(fixedDimension, start))); - int whiteRunSize = whiteRunStart - start; - if (start < minDim || whiteRunSize > maxWhiteRun) { - start = whiteRunStart; - break; - } - } - } - start++; - - // Then try right/down - int end = center; - while (end < maxDim) { - if (horizontal ? image.get(end, fixedDimension) : image.get(fixedDimension, end)) { - end++; - } else { - int whiteRunStart = end; - do { - end++; - } while (end < maxDim && !(horizontal ? image.get(end, fixedDimension) : - image.get(fixedDimension, end))); - int whiteRunSize = end - whiteRunStart; - if (end >= maxDim || whiteRunSize > maxWhiteRun) { - end = whiteRunStart; - break; - } - } - } - end--; - - return end > start ? new int[]{start, end} : null; - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/detector/WhiteRectangleDetector.java b/OpenPGP-Keychain/src/com/google/zxing/common/detector/WhiteRectangleDetector.java deleted file mode 100644 index 31d87e9d0..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/detector/WhiteRectangleDetector.java +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright 2010 ZXing authors - * - * 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 com.google.zxing.common.detector; - -import com.google.zxing.NotFoundException; -import com.google.zxing.ResultPoint; -import com.google.zxing.common.BitMatrix; - -/** - *

- * Detects a candidate barcode-like rectangular region within an image. It - * starts around the center of the image, increases the size of the candidate - * region until it finds a white rectangular region. By keeping track of the - * last black points it encountered, it determines the corners of the barcode. - *

- * - * @author David Olivier - */ -public final class WhiteRectangleDetector { - - private static final int INIT_SIZE = 30; - private static final int CORR = 1; - - private final BitMatrix image; - private final int height; - private final int width; - private final int leftInit; - private final int rightInit; - private final int downInit; - private final int upInit; - - /** - * @throws NotFoundException if image is too small - */ - public WhiteRectangleDetector(BitMatrix image) throws NotFoundException { - this.image = image; - height = image.getHeight(); - width = image.getWidth(); - leftInit = (width - INIT_SIZE) >> 1; - rightInit = (width + INIT_SIZE) >> 1; - upInit = (height - INIT_SIZE) >> 1; - downInit = (height + INIT_SIZE) >> 1; - if (upInit < 0 || leftInit < 0 || downInit >= height || rightInit >= width) { - throw NotFoundException.getNotFoundInstance(); - } - } - - /** - * @throws NotFoundException if image is too small - */ - public WhiteRectangleDetector(BitMatrix image, int initSize, int x, int y) throws NotFoundException { - this.image = image; - height = image.getHeight(); - width = image.getWidth(); - int halfsize = initSize >> 1; - leftInit = x - halfsize; - rightInit = x + halfsize; - upInit = y - halfsize; - downInit = y + halfsize; - if (upInit < 0 || leftInit < 0 || downInit >= height || rightInit >= width) { - throw NotFoundException.getNotFoundInstance(); - } - } - - /** - *

- * Detects a candidate barcode-like rectangular region within an image. It - * starts around the center of the image, increases the size of the candidate - * region until it finds a white rectangular region. - *

- * - * @return {@link ResultPoint[]} describing the corners of the rectangular - * region. The first and last points are opposed on the diagonal, as - * are the second and third. The first point will be the topmost - * point and the last, the bottommost. The second point will be - * leftmost and the third, the rightmost - * @throws NotFoundException if no Data Matrix Code can be found - */ - public ResultPoint[] detect() throws NotFoundException { - - int left = leftInit; - int right = rightInit; - int up = upInit; - int down = downInit; - boolean sizeExceeded = false; - boolean aBlackPointFoundOnBorder = true; - boolean atLeastOneBlackPointFoundOnBorder = false; - - while (aBlackPointFoundOnBorder) { - - aBlackPointFoundOnBorder = false; - - // ..... - // . | - // ..... - boolean rightBorderNotWhite = true; - while (rightBorderNotWhite && right < width) { - rightBorderNotWhite = containsBlackPoint(up, down, right, false); - if (rightBorderNotWhite) { - right++; - aBlackPointFoundOnBorder = true; - } - } - - if (right >= width) { - sizeExceeded = true; - break; - } - - // ..... - // . . - // .___. - boolean bottomBorderNotWhite = true; - while (bottomBorderNotWhite && down < height) { - bottomBorderNotWhite = containsBlackPoint(left, right, down, true); - if (bottomBorderNotWhite) { - down++; - aBlackPointFoundOnBorder = true; - } - } - - if (down >= height) { - sizeExceeded = true; - break; - } - - // ..... - // | . - // ..... - boolean leftBorderNotWhite = true; - while (leftBorderNotWhite && left >= 0) { - leftBorderNotWhite = containsBlackPoint(up, down, left, false); - if (leftBorderNotWhite) { - left--; - aBlackPointFoundOnBorder = true; - } - } - - if (left < 0) { - sizeExceeded = true; - break; - } - - // .___. - // . . - // ..... - boolean topBorderNotWhite = true; - while (topBorderNotWhite && up >= 0) { - topBorderNotWhite = containsBlackPoint(left, right, up, true); - if (topBorderNotWhite) { - up--; - aBlackPointFoundOnBorder = true; - } - } - - if (up < 0) { - sizeExceeded = true; - break; - } - - if (aBlackPointFoundOnBorder) { - atLeastOneBlackPointFoundOnBorder = true; - } - - } - - if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) { - - int maxSize = right - left; - - ResultPoint z = null; - for (int i = 1; i < maxSize; i++) { - z = getBlackPointOnSegment(left, down - i, left + i, down); - if (z != null) { - break; - } - } - - if (z == null) { - throw NotFoundException.getNotFoundInstance(); - } - - ResultPoint t = null; - //go down right - for (int i = 1; i < maxSize; i++) { - t = getBlackPointOnSegment(left, up + i, left + i, up); - if (t != null) { - break; - } - } - - if (t == null) { - throw NotFoundException.getNotFoundInstance(); - } - - ResultPoint x = null; - //go down left - for (int i = 1; i < maxSize; i++) { - x = getBlackPointOnSegment(right, up + i, right - i, up); - if (x != null) { - break; - } - } - - if (x == null) { - throw NotFoundException.getNotFoundInstance(); - } - - ResultPoint y = null; - //go up left - for (int i = 1; i < maxSize; i++) { - y = getBlackPointOnSegment(right, down - i, right - i, down); - if (y != null) { - break; - } - } - - if (y == null) { - throw NotFoundException.getNotFoundInstance(); - } - - return centerEdges(y, z, x, t); - - } else { - throw NotFoundException.getNotFoundInstance(); - } - } - - /** - * Ends up being a bit faster than Math.round(). This merely rounds its - * argument to the nearest int, where x.5 rounds up. - */ - private static int round(float d) { - return (int) (d + 0.5f); - } - - private ResultPoint getBlackPointOnSegment(float aX, float aY, float bX, float bY) { - int dist = distanceL2(aX, aY, bX, bY); - float xStep = (bX - aX) / dist; - float yStep = (bY - aY) / dist; - - for (int i = 0; i < dist; i++) { - int x = round(aX + i * xStep); - int y = round(aY + i * yStep); - if (image.get(x, y)) { - return new ResultPoint(x, y); - } - } - return null; - } - - private static int distanceL2(float aX, float aY, float bX, float bY) { - float xDiff = aX - bX; - float yDiff = aY - bY; - return round((float) Math.sqrt(xDiff * xDiff + yDiff * yDiff)); - } - - /** - * recenters the points of a constant distance towards the center - * - * @param y bottom most point - * @param z left most point - * @param x right most point - * @param t top most point - * @return {@link ResultPoint}[] describing the corners of the rectangular - * region. The first and last points are opposed on the diagonal, as - * are the second and third. The first point will be the topmost - * point and the last, the bottommost. The second point will be - * leftmost and the third, the rightmost - */ - private ResultPoint[] centerEdges(ResultPoint y, ResultPoint z, - ResultPoint x, ResultPoint t) { - - // - // t t - // z x - // x OR z - // y y - // - - float yi = y.getX(); - float yj = y.getY(); - float zi = z.getX(); - float zj = z.getY(); - float xi = x.getX(); - float xj = x.getY(); - float ti = t.getX(); - float tj = t.getY(); - - if (yi < width / 2) { - return new ResultPoint[]{ - new ResultPoint(ti - CORR, tj + CORR), - new ResultPoint(zi + CORR, zj + CORR), - new ResultPoint(xi - CORR, xj - CORR), - new ResultPoint(yi + CORR, yj - CORR)}; - } else { - return new ResultPoint[]{ - new ResultPoint(ti + CORR, tj + CORR), - new ResultPoint(zi + CORR, zj - CORR), - new ResultPoint(xi - CORR, xj + CORR), - new ResultPoint(yi - CORR, yj - CORR)}; - } - } - - /** - * Determines whether a segment contains a black point - * - * @param a min value of the scanned coordinate - * @param b max value of the scanned coordinate - * @param fixed value of fixed coordinate - * @param horizontal set to true if scan must be horizontal, false if vertical - * @return true if a black point has been found, else false. - */ - private boolean containsBlackPoint(int a, int b, int fixed, boolean horizontal) { - - if (horizontal) { - for (int x = a; x <= b; x++) { - if (image.get(x, fixed)) { - return true; - } - } - } else { - for (int y = a; y <= b; y++) { - if (image.get(fixed, y)) { - return true; - } - } - } - - return false; - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/GenericGF.java b/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/GenericGF.java deleted file mode 100644 index 859c379ee..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/GenericGF.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common.reedsolomon; - -/** - *

This class contains utility methods for performing mathematical operations over - * the Galois Fields. Operations use a given primitive polynomial in calculations.

- * - *

Throughout this package, elements of the GF are represented as an int - * for convenience and speed (but at the cost of memory). - *

- * - * @author Sean Owen - * @author David Olivier - */ -public final class GenericGF { - - public static final GenericGF AZTEC_DATA_12 = new GenericGF(0x1069, 4096); // x^12 + x^6 + x^5 + x^3 + 1 - public static final GenericGF AZTEC_DATA_10 = new GenericGF(0x409, 1024); // x^10 + x^3 + 1 - public static final GenericGF AZTEC_DATA_6 = new GenericGF(0x43, 64); // x^6 + x + 1 - public static final GenericGF AZTEC_PARAM = new GenericGF(0x13, 16); // x^4 + x + 1 - public static final GenericGF QR_CODE_FIELD_256 = new GenericGF(0x011D, 256); // x^8 + x^4 + x^3 + x^2 + 1 - public static final GenericGF DATA_MATRIX_FIELD_256 = new GenericGF(0x012D, 256); // x^8 + x^5 + x^3 + x^2 + 1 - public static final GenericGF AZTEC_DATA_8 = DATA_MATRIX_FIELD_256; - - private static final int INITIALIZATION_THRESHOLD = 0; - - private int[] expTable; - private int[] logTable; - private GenericGFPoly zero; - private GenericGFPoly one; - private final int size; - private final int primitive; - private boolean initialized = false; - - /** - * Create a representation of GF(size) using the given primitive polynomial. - * - * @param primitive irreducible polynomial whose coefficients are represented by - * the bits of an int, where the least-significant bit represents the constant - * coefficient - */ - public GenericGF(int primitive, int size) { - this.primitive = primitive; - this.size = size; - - if (size <= INITIALIZATION_THRESHOLD){ - initialize(); - } - } - - private void initialize(){ - expTable = new int[size]; - logTable = new int[size]; - int x = 1; - for (int i = 0; i < size; i++) { - expTable[i] = x; - x <<= 1; // x = x * 2; we're assuming the generator alpha is 2 - if (x >= size) { - x ^= primitive; - x &= size-1; - } - } - for (int i = 0; i < size-1; i++) { - logTable[expTable[i]] = i; - } - // logTable[0] == 0 but this should never be used - zero = new GenericGFPoly(this, new int[]{0}); - one = new GenericGFPoly(this, new int[]{1}); - initialized = true; - } - - private void checkInit(){ - if (!initialized) { - initialize(); - } - } - - GenericGFPoly getZero() { - checkInit(); - - return zero; - } - - GenericGFPoly getOne() { - checkInit(); - - return one; - } - - /** - * @return the monomial representing coefficient * x^degree - */ - GenericGFPoly buildMonomial(int degree, int coefficient) { - checkInit(); - - if (degree < 0) { - throw new IllegalArgumentException(); - } - if (coefficient == 0) { - return zero; - } - int[] coefficients = new int[degree + 1]; - coefficients[0] = coefficient; - return new GenericGFPoly(this, coefficients); - } - - /** - * Implements both addition and subtraction -- they are the same in GF(size). - * - * @return sum/difference of a and b - */ - static int addOrSubtract(int a, int b) { - return a ^ b; - } - - /** - * @return 2 to the power of a in GF(size) - */ - int exp(int a) { - checkInit(); - - return expTable[a]; - } - - /** - * @return base 2 log of a in GF(size) - */ - int log(int a) { - checkInit(); - - if (a == 0) { - throw new IllegalArgumentException(); - } - return logTable[a]; - } - - /** - * @return multiplicative inverse of a - */ - int inverse(int a) { - checkInit(); - - if (a == 0) { - throw new ArithmeticException(); - } - return expTable[size - logTable[a] - 1]; - } - - /** - * @param a - * @param b - * @return product of a and b in GF(size) - */ - int multiply(int a, int b) { - checkInit(); - - if (a == 0 || b == 0) { - return 0; - } - - if (a<0 || b <0 || a>=size || b >=size){ - a++; - } - - int logSum = logTable[a] + logTable[b]; - return expTable[(logSum % size) + logSum / size]; - } - - public int getSize(){ - return size; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/GenericGFPoly.java b/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/GenericGFPoly.java deleted file mode 100644 index 056802287..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/GenericGFPoly.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common.reedsolomon; - -/** - *

Represents a polynomial whose coefficients are elements of a GF. - * Instances of this class are immutable.

- * - *

Much credit is due to William Rucklidge since portions of this code are an indirect - * port of his C++ Reed-Solomon implementation.

- * - * @author Sean Owen - */ -final class GenericGFPoly { - - private final GenericGF field; - private final int[] coefficients; - - /** - * @param field the {@link GenericGF} instance representing the field to use - * to perform computations - * @param coefficients coefficients as ints representing elements of GF(size), arranged - * from most significant (highest-power term) coefficient to least significant - * @throws IllegalArgumentException if argument is null or empty, - * or if leading coefficient is 0 and this is not a - * constant polynomial (that is, it is not the monomial "0") - */ - GenericGFPoly(GenericGF field, int[] coefficients) { - if (coefficients == null || coefficients.length == 0) { - throw new IllegalArgumentException(); - } - this.field = field; - int coefficientsLength = coefficients.length; - if (coefficientsLength > 1 && coefficients[0] == 0) { - // Leading term must be non-zero for anything except the constant polynomial "0" - int firstNonZero = 1; - while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) { - firstNonZero++; - } - if (firstNonZero == coefficientsLength) { - this.coefficients = field.getZero().coefficients; - } else { - this.coefficients = new int[coefficientsLength - firstNonZero]; - System.arraycopy(coefficients, - firstNonZero, - this.coefficients, - 0, - this.coefficients.length); - } - } else { - this.coefficients = coefficients; - } - } - - int[] getCoefficients() { - return coefficients; - } - - /** - * @return degree of this polynomial - */ - int getDegree() { - return coefficients.length - 1; - } - - /** - * @return true iff this polynomial is the monomial "0" - */ - boolean isZero() { - return coefficients[0] == 0; - } - - /** - * @return coefficient of x^degree term in this polynomial - */ - int getCoefficient(int degree) { - return coefficients[coefficients.length - 1 - degree]; - } - - /** - * @return evaluation of this polynomial at a given point - */ - int evaluateAt(int a) { - if (a == 0) { - // Just return the x^0 coefficient - return getCoefficient(0); - } - int size = coefficients.length; - if (a == 1) { - // Just the sum of the coefficients - int result = 0; - for (int i = 0; i < size; i++) { - result = GenericGF.addOrSubtract(result, coefficients[i]); - } - return result; - } - int result = coefficients[0]; - for (int i = 1; i < size; i++) { - result = GenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]); - } - return result; - } - - GenericGFPoly addOrSubtract(GenericGFPoly other) { - if (!field.equals(other.field)) { - throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field"); - } - if (isZero()) { - return other; - } - if (other.isZero()) { - return this; - } - - int[] smallerCoefficients = this.coefficients; - int[] largerCoefficients = other.coefficients; - if (smallerCoefficients.length > largerCoefficients.length) { - int[] temp = smallerCoefficients; - smallerCoefficients = largerCoefficients; - largerCoefficients = temp; - } - int[] sumDiff = new int[largerCoefficients.length]; - int lengthDiff = largerCoefficients.length - smallerCoefficients.length; - // Copy high-order terms only found in higher-degree polynomial's coefficients - System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff); - - for (int i = lengthDiff; i < largerCoefficients.length; i++) { - sumDiff[i] = GenericGF.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); - } - - return new GenericGFPoly(field, sumDiff); - } - - GenericGFPoly multiply(GenericGFPoly other) { - if (!field.equals(other.field)) { - throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field"); - } - if (isZero() || other.isZero()) { - return field.getZero(); - } - int[] aCoefficients = this.coefficients; - int aLength = aCoefficients.length; - int[] bCoefficients = other.coefficients; - int bLength = bCoefficients.length; - int[] product = new int[aLength + bLength - 1]; - for (int i = 0; i < aLength; i++) { - int aCoeff = aCoefficients[i]; - for (int j = 0; j < bLength; j++) { - product[i + j] = GenericGF.addOrSubtract(product[i + j], - field.multiply(aCoeff, bCoefficients[j])); - } - } - return new GenericGFPoly(field, product); - } - - GenericGFPoly multiply(int scalar) { - if (scalar == 0) { - return field.getZero(); - } - if (scalar == 1) { - return this; - } - int size = coefficients.length; - int[] product = new int[size]; - for (int i = 0; i < size; i++) { - product[i] = field.multiply(coefficients[i], scalar); - } - return new GenericGFPoly(field, product); - } - - GenericGFPoly multiplyByMonomial(int degree, int coefficient) { - if (degree < 0) { - throw new IllegalArgumentException(); - } - if (coefficient == 0) { - return field.getZero(); - } - int size = coefficients.length; - int[] product = new int[size + degree]; - for (int i = 0; i < size; i++) { - product[i] = field.multiply(coefficients[i], coefficient); - } - return new GenericGFPoly(field, product); - } - - GenericGFPoly[] divide(GenericGFPoly other) { - if (!field.equals(other.field)) { - throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field"); - } - if (other.isZero()) { - throw new IllegalArgumentException("Divide by 0"); - } - - GenericGFPoly quotient = field.getZero(); - GenericGFPoly remainder = this; - - int denominatorLeadingTerm = other.getCoefficient(other.getDegree()); - int inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm); - - while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) { - int degreeDifference = remainder.getDegree() - other.getDegree(); - int scale = field.multiply(remainder.getCoefficient(remainder.getDegree()), inverseDenominatorLeadingTerm); - GenericGFPoly term = other.multiplyByMonomial(degreeDifference, scale); - GenericGFPoly iterationQuotient = field.buildMonomial(degreeDifference, scale); - quotient = quotient.addOrSubtract(iterationQuotient); - remainder = remainder.addOrSubtract(term); - } - - return new GenericGFPoly[] { quotient, remainder }; - } - - public String toString() { - StringBuffer result = new StringBuffer(8 * getDegree()); - for (int degree = getDegree(); degree >= 0; degree--) { - int coefficient = getCoefficient(degree); - if (coefficient != 0) { - if (coefficient < 0) { - result.append(" - "); - coefficient = -coefficient; - } else { - if (result.length() > 0) { - result.append(" + "); - } - } - if (degree == 0 || coefficient != 1) { - int alphaPower = field.log(coefficient); - if (alphaPower == 0) { - result.append('1'); - } else if (alphaPower == 1) { - result.append('a'); - } else { - result.append("a^"); - result.append(alphaPower); - } - } - if (degree != 0) { - if (degree == 1) { - result.append('x'); - } else { - result.append("x^"); - result.append(degree); - } - } - } - } - return result.toString(); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/ReedSolomonDecoder.java b/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/ReedSolomonDecoder.java deleted file mode 100644 index b523fd34b..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/ReedSolomonDecoder.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common.reedsolomon; - -/** - *

Implements Reed-Solomon decoding, as the name implies.

- * - *

The algorithm will not be explained here, but the following references were helpful - * in creating this implementation:

- * - * - * - *

Much credit is due to William Rucklidge since portions of this code are an indirect - * port of his C++ Reed-Solomon implementation.

- * - * @author Sean Owen - * @author William Rucklidge - * @author sanfordsquires - */ -public final class ReedSolomonDecoder { - - private final GenericGF field; - - public ReedSolomonDecoder(GenericGF field) { - this.field = field; - } - - /** - *

Decodes given set of received codewords, which include both data and error-correction - * codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place, - * in the input.

- * - * @param received data and error-correction codewords - * @param twoS number of error-correction codewords available - * @throws ReedSolomonException if decoding fails for any reason - */ - public void decode(int[] received, int twoS) throws ReedSolomonException { - GenericGFPoly poly = new GenericGFPoly(field, received); - int[] syndromeCoefficients = new int[twoS]; - boolean dataMatrix = field.equals(GenericGF.DATA_MATRIX_FIELD_256); - boolean noError = true; - for (int i = 0; i < twoS; i++) { - // Thanks to sanfordsquires for this fix: - int eval = poly.evaluateAt(field.exp(dataMatrix ? i + 1 : i)); - syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval; - if (eval != 0) { - noError = false; - } - } - if (noError) { - return; - } - GenericGFPoly syndrome = new GenericGFPoly(field, syndromeCoefficients); - GenericGFPoly[] sigmaOmega = - runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS); - GenericGFPoly sigma = sigmaOmega[0]; - GenericGFPoly omega = sigmaOmega[1]; - int[] errorLocations = findErrorLocations(sigma); - int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations, dataMatrix); - for (int i = 0; i < errorLocations.length; i++) { - int position = received.length - 1 - field.log(errorLocations[i]); - if (position < 0) { - throw new ReedSolomonException("Bad error location"); - } - received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]); - } - } - - private GenericGFPoly[] runEuclideanAlgorithm(GenericGFPoly a, GenericGFPoly b, int R) - throws ReedSolomonException { - // Assume a's degree is >= b's - if (a.getDegree() < b.getDegree()) { - GenericGFPoly temp = a; - a = b; - b = temp; - } - - GenericGFPoly rLast = a; - GenericGFPoly r = b; - GenericGFPoly sLast = field.getOne(); - GenericGFPoly s = field.getZero(); - GenericGFPoly tLast = field.getZero(); - GenericGFPoly t = field.getOne(); - - // Run Euclidean algorithm until r's degree is less than R/2 - while (r.getDegree() >= R / 2) { - GenericGFPoly rLastLast = rLast; - GenericGFPoly sLastLast = sLast; - GenericGFPoly tLastLast = tLast; - rLast = r; - sLast = s; - tLast = t; - - // Divide rLastLast by rLast, with quotient in q and remainder in r - if (rLast.isZero()) { - // Oops, Euclidean algorithm already terminated? - throw new ReedSolomonException("r_{i-1} was zero"); - } - r = rLastLast; - GenericGFPoly q = field.getZero(); - int denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree()); - int dltInverse = field.inverse(denominatorLeadingTerm); - while (r.getDegree() >= rLast.getDegree() && !r.isZero()) { - int degreeDiff = r.getDegree() - rLast.getDegree(); - int scale = field.multiply(r.getCoefficient(r.getDegree()), dltInverse); - q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale)); - r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale)); - } - - s = q.multiply(sLast).addOrSubtract(sLastLast); - t = q.multiply(tLast).addOrSubtract(tLastLast); - } - - int sigmaTildeAtZero = t.getCoefficient(0); - if (sigmaTildeAtZero == 0) { - throw new ReedSolomonException("sigmaTilde(0) was zero"); - } - - int inverse = field.inverse(sigmaTildeAtZero); - GenericGFPoly sigma = t.multiply(inverse); - GenericGFPoly omega = r.multiply(inverse); - return new GenericGFPoly[]{sigma, omega}; - } - - private int[] findErrorLocations(GenericGFPoly errorLocator) throws ReedSolomonException { - // This is a direct application of Chien's search - int numErrors = errorLocator.getDegree(); - if (numErrors == 1) { // shortcut - return new int[] { errorLocator.getCoefficient(1) }; - } - int[] result = new int[numErrors]; - int e = 0; - for (int i = 1; i < field.getSize() && e < numErrors; i++) { - if (errorLocator.evaluateAt(i) == 0) { - result[e] = field.inverse(i); - e++; - } - } - if (e != numErrors) { - throw new ReedSolomonException("Error locator degree does not match number of roots"); - } - return result; - } - - private int[] findErrorMagnitudes(GenericGFPoly errorEvaluator, int[] errorLocations, boolean dataMatrix) { - // This is directly applying Forney's Formula - int s = errorLocations.length; - int[] result = new int[s]; - for (int i = 0; i < s; i++) { - int xiInverse = field.inverse(errorLocations[i]); - int denominator = 1; - for (int j = 0; j < s; j++) { - if (i != j) { - //denominator = field.multiply(denominator, - // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); - // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug. - // Below is a funny-looking workaround from Steven Parkes - int term = field.multiply(errorLocations[j], xiInverse); - int termPlus1 = (term & 0x1) == 0 ? term | 1 : term & ~1; - denominator = field.multiply(denominator, termPlus1); - } - } - result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), - field.inverse(denominator)); - // Thanks to sanfordsquires for this fix: - if (dataMatrix) { - result[i] = field.multiply(result[i], xiInverse); - } - } - return result; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/ReedSolomonEncoder.java b/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/ReedSolomonEncoder.java deleted file mode 100644 index 05e2ae03a..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/ReedSolomonEncoder.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing.common.reedsolomon; - -import java.util.Vector; - -/** - *

Implements Reed-Solomon enbcoding, as the name implies.

- * - * @author Sean Owen - * @author William Rucklidge - */ -public final class ReedSolomonEncoder { - - private final GenericGF field; - private final Vector cachedGenerators; - - public ReedSolomonEncoder(GenericGF field) { - if (!GenericGF.QR_CODE_FIELD_256.equals(field)) { - throw new IllegalArgumentException("Only QR Code is supported at this time"); - } - this.field = field; - this.cachedGenerators = new Vector(); - cachedGenerators.addElement(new GenericGFPoly(field, new int[] { 1 })); - } - - private GenericGFPoly buildGenerator(int degree) { - if (degree >= cachedGenerators.size()) { - GenericGFPoly lastGenerator = (GenericGFPoly) cachedGenerators.elementAt(cachedGenerators.size() - 1); - for (int d = cachedGenerators.size(); d <= degree; d++) { - GenericGFPoly nextGenerator = lastGenerator.multiply(new GenericGFPoly(field, new int[] { 1, field.exp(d - 1) })); - cachedGenerators.addElement(nextGenerator); - lastGenerator = nextGenerator; - } - } - return (GenericGFPoly) cachedGenerators.elementAt(degree); - } - - public void encode(int[] toEncode, int ecBytes) { - if (ecBytes == 0) { - throw new IllegalArgumentException("No error correction bytes"); - } - int dataBytes = toEncode.length - ecBytes; - if (dataBytes <= 0) { - throw new IllegalArgumentException("No data bytes provided"); - } - GenericGFPoly generator = buildGenerator(ecBytes); - int[] infoCoefficients = new int[dataBytes]; - System.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes); - GenericGFPoly info = new GenericGFPoly(field, infoCoefficients); - info = info.multiplyByMonomial(ecBytes, 1); - GenericGFPoly remainder = info.divide(generator)[1]; - int[] coefficients = remainder.getCoefficients(); - int numZeroCoefficients = ecBytes - coefficients.length; - for (int i = 0; i < numZeroCoefficients; i++) { - toEncode[dataBytes + i] = 0; - } - System.arraycopy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/ReedSolomonException.java b/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/ReedSolomonException.java deleted file mode 100644 index d5b45a612..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/common/reedsolomon/ReedSolomonException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.common.reedsolomon; - -/** - *

Thrown when an exception occurs during Reed-Solomon decoding, such as when - * there are too many errors to correct.

- * - * @author Sean Owen - */ -public final class ReedSolomonException extends Exception { - - public ReedSolomonException(String message) { - super(message); - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/multi/ByQuadrantReader.java b/OpenPGP-Keychain/src/com/google/zxing/multi/ByQuadrantReader.java deleted file mode 100644 index 35904d364..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/multi/ByQuadrantReader.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * 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 com.google.zxing.multi; - -import com.google.zxing.BinaryBitmap; -import com.google.zxing.ChecksumException; -import com.google.zxing.FormatException; -import com.google.zxing.NotFoundException; -import com.google.zxing.Reader; -import com.google.zxing.Result; - -import java.util.Hashtable; - -/** - * This class attempts to decode a barcode from an image, not by scanning the whole image, - * but by scanning subsets of the image. This is important when there may be multiple barcodes in - * an image, and detecting a barcode may find parts of multiple barcode and fail to decode - * (e.g. QR Codes). Instead this scans the four quadrants of the image -- and also the center - * 'quadrant' to cover the case where a barcode is found in the center. - * - * @see GenericMultipleBarcodeReader - */ -public final class ByQuadrantReader implements Reader { - - private final Reader delegate; - - public ByQuadrantReader(Reader delegate) { - this.delegate = delegate; - } - - public Result decode(BinaryBitmap image) - throws NotFoundException, ChecksumException, FormatException { - return decode(image, null); - } - - public Result decode(BinaryBitmap image, Hashtable hints) - throws NotFoundException, ChecksumException, FormatException { - - int width = image.getWidth(); - int height = image.getHeight(); - int halfWidth = width / 2; - int halfHeight = height / 2; - - BinaryBitmap topLeft = image.crop(0, 0, halfWidth, halfHeight); - try { - return delegate.decode(topLeft, hints); - } catch (NotFoundException re) { - // continue - } - - BinaryBitmap topRight = image.crop(halfWidth, 0, halfWidth, halfHeight); - try { - return delegate.decode(topRight, hints); - } catch (NotFoundException re) { - // continue - } - - BinaryBitmap bottomLeft = image.crop(0, halfHeight, halfWidth, halfHeight); - try { - return delegate.decode(bottomLeft, hints); - } catch (NotFoundException re) { - // continue - } - - BinaryBitmap bottomRight = image.crop(halfWidth, halfHeight, halfWidth, halfHeight); - try { - return delegate.decode(bottomRight, hints); - } catch (NotFoundException re) { - // continue - } - - int quarterWidth = halfWidth / 2; - int quarterHeight = halfHeight / 2; - BinaryBitmap center = image.crop(quarterWidth, quarterHeight, halfWidth, halfHeight); - return delegate.decode(center, hints); - } - - public void reset() { - delegate.reset(); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/multi/GenericMultipleBarcodeReader.java b/OpenPGP-Keychain/src/com/google/zxing/multi/GenericMultipleBarcodeReader.java deleted file mode 100644 index 70d454251..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/multi/GenericMultipleBarcodeReader.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * 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 com.google.zxing.multi; - -import com.google.zxing.BinaryBitmap; -import com.google.zxing.NotFoundException; -import com.google.zxing.Reader; -import com.google.zxing.ReaderException; -import com.google.zxing.Result; -import com.google.zxing.ResultPoint; - -import java.util.Hashtable; -import java.util.Vector; - -/** - *

Attempts to locate multiple barcodes in an image by repeatedly decoding portion of the image. - * After one barcode is found, the areas left, above, right and below the barcode's - * {@link com.google.zxing.ResultPoint}s are scanned, recursively.

- * - *

A caller may want to also employ {@link ByQuadrantReader} when attempting to find multiple - * 2D barcodes, like QR Codes, in an image, where the presence of multiple barcodes might prevent - * detecting any one of them.

- * - *

That is, instead of passing a {@link Reader} a caller might pass - * new ByQuadrantReader(reader).

- * - * @author Sean Owen - */ -public final class GenericMultipleBarcodeReader implements MultipleBarcodeReader { - - private static final int MIN_DIMENSION_TO_RECUR = 100; - - private final Reader delegate; - - public GenericMultipleBarcodeReader(Reader delegate) { - this.delegate = delegate; - } - - public Result[] decodeMultiple(BinaryBitmap image) throws NotFoundException { - return decodeMultiple(image, null); - } - - public Result[] decodeMultiple(BinaryBitmap image, Hashtable hints) - throws NotFoundException { - Vector results = new Vector(); - doDecodeMultiple(image, hints, results, 0, 0); - if (results.isEmpty()) { - throw NotFoundException.getNotFoundInstance(); - } - int numResults = results.size(); - Result[] resultArray = new Result[numResults]; - for (int i = 0; i < numResults; i++) { - resultArray[i] = (Result) results.elementAt(i); - } - return resultArray; - } - - private void doDecodeMultiple(BinaryBitmap image, - Hashtable hints, - Vector results, - int xOffset, - int yOffset) { - Result result; - try { - result = delegate.decode(image, hints); - } catch (ReaderException re) { - return; - } - boolean alreadyFound = false; - for (int i = 0; i < results.size(); i++) { - Result existingResult = (Result) results.elementAt(i); - if (existingResult.getText().equals(result.getText())) { - alreadyFound = true; - break; - } - } - if (alreadyFound) { - return; - } - results.addElement(translateResultPoints(result, xOffset, yOffset)); - ResultPoint[] resultPoints = result.getResultPoints(); - if (resultPoints == null || resultPoints.length == 0) { - return; - } - int width = image.getWidth(); - int height = image.getHeight(); - float minX = width; - float minY = height; - float maxX = 0.0f; - float maxY = 0.0f; - for (int i = 0; i < resultPoints.length; i++) { - ResultPoint point = resultPoints[i]; - float x = point.getX(); - float y = point.getY(); - if (x < minX) { - minX = x; - } - if (y < minY) { - minY = y; - } - if (x > maxX) { - maxX = x; - } - if (y > maxY) { - maxY = y; - } - } - - // Decode left of barcode - if (minX > MIN_DIMENSION_TO_RECUR) { - doDecodeMultiple(image.crop(0, 0, (int) minX, height), - hints, results, xOffset, yOffset); - } - // Decode above barcode - if (minY > MIN_DIMENSION_TO_RECUR) { - doDecodeMultiple(image.crop(0, 0, width, (int) minY), - hints, results, xOffset, yOffset); - } - // Decode right of barcode - if (maxX < width - MIN_DIMENSION_TO_RECUR) { - doDecodeMultiple(image.crop((int) maxX, 0, width - (int) maxX, height), - hints, results, xOffset + (int) maxX, yOffset); - } - // Decode below barcode - if (maxY < height - MIN_DIMENSION_TO_RECUR) { - doDecodeMultiple(image.crop(0, (int) maxY, width, height - (int) maxY), - hints, results, xOffset, yOffset + (int) maxY); - } - } - - private static Result translateResultPoints(Result result, int xOffset, int yOffset) { - ResultPoint[] oldResultPoints = result.getResultPoints(); - ResultPoint[] newResultPoints = new ResultPoint[oldResultPoints.length]; - for (int i = 0; i < oldResultPoints.length; i++) { - ResultPoint oldPoint = oldResultPoints[i]; - newResultPoints[i] = new ResultPoint(oldPoint.getX() + xOffset, oldPoint.getY() + yOffset); - } - return new Result(result.getText(), result.getRawBytes(), newResultPoints, - result.getBarcodeFormat()); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/multi/MultipleBarcodeReader.java b/OpenPGP-Keychain/src/com/google/zxing/multi/MultipleBarcodeReader.java deleted file mode 100644 index 5f0c7eb5d..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/multi/MultipleBarcodeReader.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * 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 com.google.zxing.multi; - -import com.google.zxing.BinaryBitmap; -import com.google.zxing.NotFoundException; -import com.google.zxing.Result; - -import java.util.Hashtable; - -/** - * Implementation of this interface attempt to read several barcodes from one image. - * - * @see com.google.zxing.Reader - * @author Sean Owen - */ -public interface MultipleBarcodeReader { - - Result[] decodeMultiple(BinaryBitmap image) throws NotFoundException; - - Result[] decodeMultiple(BinaryBitmap image, Hashtable hints) throws NotFoundException; - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/multi/qrcode/detector/MultiDetector.java b/OpenPGP-Keychain/src/com/google/zxing/multi/qrcode/detector/MultiDetector.java deleted file mode 100644 index 584c41404..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/multi/qrcode/detector/MultiDetector.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * 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 com.google.zxing.multi.qrcode.detector; - -import com.google.zxing.NotFoundException; -import com.google.zxing.ReaderException; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.DetectorResult; -import com.google.zxing.qrcode.detector.Detector; -import com.google.zxing.qrcode.detector.FinderPatternInfo; - -import java.util.Hashtable; -import java.util.Vector; - -/** - *

Encapsulates logic that can detect one or more QR Codes in an image, even if the QR Code - * is rotated or skewed, or partially obscured.

- * - * @author Sean Owen - * @author Hannes Erven - */ -public final class MultiDetector extends Detector { - - private static final DetectorResult[] EMPTY_DETECTOR_RESULTS = new DetectorResult[0]; - - public MultiDetector(BitMatrix image) { - super(image); - } - - public DetectorResult[] detectMulti(Hashtable hints) throws NotFoundException { - BitMatrix image = getImage(); - MultiFinderPatternFinder finder = new MultiFinderPatternFinder(image); - FinderPatternInfo[] info = finder.findMulti(hints); - - if (info == null || info.length == 0) { - throw NotFoundException.getNotFoundInstance(); - } - - Vector result = new Vector(); - for (int i = 0; i < info.length; i++) { - try { - result.addElement(processFinderPatternInfo(info[i])); - } catch (ReaderException e) { - // ignore - } - } - if (result.isEmpty()) { - return EMPTY_DETECTOR_RESULTS; - } else { - DetectorResult[] resultArray = new DetectorResult[result.size()]; - for (int i = 0; i < result.size(); i++) { - resultArray[i] = (DetectorResult) result.elementAt(i); - } - return resultArray; - } - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/multi/qrcode/detector/MultiFinderPatternFinder.java b/OpenPGP-Keychain/src/com/google/zxing/multi/qrcode/detector/MultiFinderPatternFinder.java deleted file mode 100644 index 1162324e2..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/multi/qrcode/detector/MultiFinderPatternFinder.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * 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 com.google.zxing.multi.qrcode.detector; - -import com.google.zxing.DecodeHintType; -import com.google.zxing.NotFoundException; -import com.google.zxing.ResultPoint; -import com.google.zxing.ResultPointCallback; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.Collections; -import com.google.zxing.common.Comparator; -import com.google.zxing.qrcode.detector.FinderPattern; -import com.google.zxing.qrcode.detector.FinderPatternFinder; -import com.google.zxing.qrcode.detector.FinderPatternInfo; - -import java.util.Hashtable; -import java.util.Vector; - -/** - *

This class attempts to find finder patterns in a QR Code. Finder patterns are the square - * markers at three corners of a QR Code.

- * - *

This class is thread-safe but not reentrant. Each thread must allocate its own object. - * - *

In contrast to {@link FinderPatternFinder}, this class will return an array of all possible - * QR code locations in the image.

- * - *

Use the TRY_HARDER hint to ask for a more thorough detection.

- * - * @author Sean Owen - * @author Hannes Erven - */ -final class MultiFinderPatternFinder extends FinderPatternFinder { - - private static final FinderPatternInfo[] EMPTY_RESULT_ARRAY = new FinderPatternInfo[0]; - - // TODO MIN_MODULE_COUNT and MAX_MODULE_COUNT would be great hints to ask the user for - // since it limits the number of regions to decode - - // max. legal count of modules per QR code edge (177) - private static final float MAX_MODULE_COUNT_PER_EDGE = 180; - // min. legal count per modules per QR code edge (11) - private static final float MIN_MODULE_COUNT_PER_EDGE = 9; - - /** - * More or less arbitrary cutoff point for determining if two finder patterns might belong - * to the same code if they differ less than DIFF_MODSIZE_CUTOFF_PERCENT percent in their - * estimated modules sizes. - */ - private static final float DIFF_MODSIZE_CUTOFF_PERCENT = 0.05f; - - /** - * More or less arbitrary cutoff point for determining if two finder patterns might belong - * to the same code if they differ less than DIFF_MODSIZE_CUTOFF pixels/module in their - * estimated modules sizes. - */ - private static final float DIFF_MODSIZE_CUTOFF = 0.5f; - - - /** - * A comparator that orders FinderPatterns by their estimated module size. - */ - private static class ModuleSizeComparator implements Comparator { - public int compare(Object center1, Object center2) { - float value = ((FinderPattern) center2).getEstimatedModuleSize() - - ((FinderPattern) center1).getEstimatedModuleSize(); - return value < 0.0 ? -1 : value > 0.0 ? 1 : 0; - } - } - - /** - *

Creates a finder that will search the image for three finder patterns.

- * - * @param image image to search - */ - MultiFinderPatternFinder(BitMatrix image) { - super(image); - } - - MultiFinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback) { - super(image, resultPointCallback); - } - - /** - * @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are - * those that have been detected at least {@link #CENTER_QUORUM} times, and whose module - * size differs from the average among those patterns the least - * @throws NotFoundException if 3 such finder patterns do not exist - */ - private FinderPattern[][] selectBestPatterns() throws NotFoundException { - Vector possibleCenters = getPossibleCenters(); - int size = possibleCenters.size(); - - if (size < 3) { - // Couldn't find enough finder patterns - throw NotFoundException.getNotFoundInstance(); - } - - /* - * Begin HE modifications to safely detect multiple codes of equal size - */ - if (size == 3) { - return new FinderPattern[][]{ - new FinderPattern[]{ - (FinderPattern) possibleCenters.elementAt(0), - (FinderPattern) possibleCenters.elementAt(1), - (FinderPattern) possibleCenters.elementAt(2) - } - }; - } - - // Sort by estimated module size to speed up the upcoming checks - Collections.insertionSort(possibleCenters, new ModuleSizeComparator()); - - /* - * Now lets start: build a list of tuples of three finder locations that - * - feature similar module sizes - * - are placed in a distance so the estimated module count is within the QR specification - * - have similar distance between upper left/right and left top/bottom finder patterns - * - form a triangle with 90° angle (checked by comparing top right/bottom left distance - * with pythagoras) - * - * Note: we allow each point to be used for more than one code region: this might seem - * counterintuitive at first, but the performance penalty is not that big. At this point, - * we cannot make a good quality decision whether the three finders actually represent - * a QR code, or are just by chance layouted so it looks like there might be a QR code there. - * So, if the layout seems right, lets have the decoder try to decode. - */ - - Vector results = new Vector(); // holder for the results - - for (int i1 = 0; i1 < (size - 2); i1++) { - FinderPattern p1 = (FinderPattern) possibleCenters.elementAt(i1); - if (p1 == null) { - continue; - } - - for (int i2 = i1 + 1; i2 < (size - 1); i2++) { - FinderPattern p2 = (FinderPattern) possibleCenters.elementAt(i2); - if (p2 == null) { - continue; - } - - // Compare the expected module sizes; if they are really off, skip - float vModSize12 = (p1.getEstimatedModuleSize() - p2.getEstimatedModuleSize()) / - Math.min(p1.getEstimatedModuleSize(), p2.getEstimatedModuleSize()); - float vModSize12A = Math.abs(p1.getEstimatedModuleSize() - p2.getEstimatedModuleSize()); - if (vModSize12A > DIFF_MODSIZE_CUTOFF && vModSize12 >= DIFF_MODSIZE_CUTOFF_PERCENT) { - // break, since elements are ordered by the module size deviation there cannot be - // any more interesting elements for the given p1. - break; - } - - for (int i3 = i2 + 1; i3 < size; i3++) { - FinderPattern p3 = (FinderPattern) possibleCenters.elementAt(i3); - if (p3 == null) { - continue; - } - - // Compare the expected module sizes; if they are really off, skip - float vModSize23 = (p2.getEstimatedModuleSize() - p3.getEstimatedModuleSize()) / - Math.min(p2.getEstimatedModuleSize(), p3.getEstimatedModuleSize()); - float vModSize23A = Math.abs(p2.getEstimatedModuleSize() - p3.getEstimatedModuleSize()); - if (vModSize23A > DIFF_MODSIZE_CUTOFF && vModSize23 >= DIFF_MODSIZE_CUTOFF_PERCENT) { - // break, since elements are ordered by the module size deviation there cannot be - // any more interesting elements for the given p1. - break; - } - - FinderPattern[] test = {p1, p2, p3}; - ResultPoint.orderBestPatterns(test); - - // Calculate the distances: a = topleft-bottomleft, b=topleft-topright, c = diagonal - FinderPatternInfo info = new FinderPatternInfo(test); - float dA = ResultPoint.distance(info.getTopLeft(), info.getBottomLeft()); - float dC = ResultPoint.distance(info.getTopRight(), info.getBottomLeft()); - float dB = ResultPoint.distance(info.getTopLeft(), info.getTopRight()); - - // Check the sizes - float estimatedModuleCount = (dA + dB) / (p1.getEstimatedModuleSize() * 2.0f); - if (estimatedModuleCount > MAX_MODULE_COUNT_PER_EDGE || - estimatedModuleCount < MIN_MODULE_COUNT_PER_EDGE) { - continue; - } - - // Calculate the difference of the edge lengths in percent - float vABBC = Math.abs((dA - dB) / Math.min(dA, dB)); - if (vABBC >= 0.1f) { - continue; - } - - // Calculate the diagonal length by assuming a 90° angle at topleft - float dCpy = (float) Math.sqrt(dA * dA + dB * dB); - // Compare to the real distance in % - float vPyC = Math.abs((dC - dCpy) / Math.min(dC, dCpy)); - - if (vPyC >= 0.1f) { - continue; - } - - // All tests passed! - results.addElement(test); - } // end iterate p3 - } // end iterate p2 - } // end iterate p1 - - if (!results.isEmpty()) { - FinderPattern[][] resultArray = new FinderPattern[results.size()][]; - for (int i = 0; i < results.size(); i++) { - resultArray[i] = (FinderPattern[]) results.elementAt(i); - } - return resultArray; - } - - // Nothing found! - throw NotFoundException.getNotFoundInstance(); - } - - public FinderPatternInfo[] findMulti(Hashtable hints) throws NotFoundException { - boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER); - BitMatrix image = getImage(); - int maxI = image.getHeight(); - int maxJ = image.getWidth(); - // We are looking for black/white/black/white/black modules in - // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far - - // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the - // image, and then account for the center being 3 modules in size. This gives the smallest - // number of pixels the center could be, so skip this often. When trying harder, look for all - // QR versions regardless of how dense they are. - int iSkip = (int) (maxI / (MAX_MODULES * 4.0f) * 3); - if (iSkip < MIN_SKIP || tryHarder) { - iSkip = MIN_SKIP; - } - - int[] stateCount = new int[5]; - for (int i = iSkip - 1; i < maxI; i += iSkip) { - // Get a row of black/white values - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - stateCount[3] = 0; - stateCount[4] = 0; - int currentState = 0; - for (int j = 0; j < maxJ; j++) { - if (image.get(j, i)) { - // Black pixel - if ((currentState & 1) == 1) { // Counting white pixels - currentState++; - } - stateCount[currentState]++; - } else { // White pixel - if ((currentState & 1) == 0) { // Counting black pixels - if (currentState == 4) { // A winner? - if (foundPatternCross(stateCount)) { // Yes - boolean confirmed = handlePossibleCenter(stateCount, i, j); - if (!confirmed) { - do { // Advance to next black pixel - j++; - } while (j < maxJ && !image.get(j, i)); - j--; // back up to that last white pixel - } - // Clear state to start looking again - currentState = 0; - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - stateCount[3] = 0; - stateCount[4] = 0; - } else { // No, shift counts back by two - stateCount[0] = stateCount[2]; - stateCount[1] = stateCount[3]; - stateCount[2] = stateCount[4]; - stateCount[3] = 1; - stateCount[4] = 0; - currentState = 3; - } - } else { - stateCount[++currentState]++; - } - } else { // Counting white pixels - stateCount[currentState]++; - } - } - } // for j=... - - if (foundPatternCross(stateCount)) { - handlePossibleCenter(stateCount, i, maxJ); - } // end if foundPatternCross - } // for i=iSkip-1 ... - FinderPattern[][] patternInfo = selectBestPatterns(); - Vector result = new Vector(); - for (int i = 0; i < patternInfo.length; i++) { - FinderPattern[] pattern = patternInfo[i]; - ResultPoint.orderBestPatterns(pattern); - result.addElement(new FinderPatternInfo(pattern)); - } - - if (result.isEmpty()) { - return EMPTY_RESULT_ARRAY; - } else { - FinderPatternInfo[] resultArray = new FinderPatternInfo[result.size()]; - for (int i = 0; i < result.size(); i++) { - resultArray[i] = (FinderPatternInfo) result.elementAt(i); - } - return resultArray; - } - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/QRCodeWriter.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/QRCodeWriter.java deleted file mode 100644 index fff4f5d1e..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/QRCodeWriter.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing.qrcode; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.EncodeHintType; -import com.google.zxing.Writer; -import com.google.zxing.WriterException; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.qrcode.encoder.ByteMatrix; -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -import com.google.zxing.qrcode.encoder.Encoder; -import com.google.zxing.qrcode.encoder.QRCode; - -import java.util.Hashtable; - -/** - * This object renders a QR Code as a BitMatrix 2D array of greyscale values. - * - * @author dswitkin@google.com (Daniel Switkin) - */ -public final class QRCodeWriter implements Writer { - - private static final int QUIET_ZONE_SIZE = 0; // patched for Bitcoin Wallet - - public BitMatrix encode(String contents, BarcodeFormat format, int width, int height) - throws WriterException { - - return encode(contents, format, width, height, null); - } - - public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, - Hashtable hints) throws WriterException { - - if (contents == null || contents.length() == 0) { - throw new IllegalArgumentException("Found empty contents"); - } - - if (format != BarcodeFormat.QR_CODE) { - throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format); - } - - if (width < 0 || height < 0) { - throw new IllegalArgumentException("Requested dimensions are too small: " + width + 'x' + - height); - } - - ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L; - if (hints != null) { - ErrorCorrectionLevel requestedECLevel = (ErrorCorrectionLevel) hints.get(EncodeHintType.ERROR_CORRECTION); - if (requestedECLevel != null) { - errorCorrectionLevel = requestedECLevel; - } - } - - QRCode code = new QRCode(); - Encoder.encode(contents, errorCorrectionLevel, hints, code); - return renderResult(code, width, height); - } - - // Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses - // 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap). - private static BitMatrix renderResult(QRCode code, int width, int height) { - ByteMatrix input = code.getMatrix(); - int inputWidth = input.getWidth(); - int inputHeight = input.getHeight(); - int qrWidth = inputWidth + (QUIET_ZONE_SIZE << 1); - int qrHeight = inputHeight + (QUIET_ZONE_SIZE << 1); - int outputWidth = Math.max(width, qrWidth); - int outputHeight = Math.max(height, qrHeight); - - int multiple = Math.min(outputWidth / qrWidth, outputHeight / qrHeight); - // Padding includes both the quiet zone and the extra white pixels to accommodate the requested - // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone. - // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will - // handle all the padding from 100x100 (the actual QR) up to 200x160. - int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; - int topPadding = (outputHeight - (inputHeight * multiple)) / 2; - - BitMatrix output = new BitMatrix(outputWidth, outputHeight); - - for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) { - // Write the contents of this row of the barcode - for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { - if (input.get(inputX, inputY) == 1) { - output.setRegion(outputX, outputY, multiple, multiple); - } - } - } - - return output; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/BitMatrixParser.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/BitMatrixParser.java deleted file mode 100644 index 9d131a554..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/BitMatrixParser.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.decoder; - -import com.google.zxing.FormatException; -import com.google.zxing.common.BitMatrix; - -/** - * @author Sean Owen - */ -final class BitMatrixParser { - - private final BitMatrix bitMatrix; - private Version parsedVersion; - private FormatInformation parsedFormatInfo; - - /** - * @param bitMatrix {@link BitMatrix} to parse - * @throws FormatException if dimension is not >= 21 and 1 mod 4 - */ - BitMatrixParser(BitMatrix bitMatrix) throws FormatException { - int dimension = bitMatrix.getHeight(); - if (dimension < 21 || (dimension & 0x03) != 1) { - throw FormatException.getFormatInstance(); - } - this.bitMatrix = bitMatrix; - } - - /** - *

Reads format information from one of its two locations within the QR Code.

- * - * @return {@link FormatInformation} encapsulating the QR Code's format info - * @throws FormatException if both format information locations cannot be parsed as - * the valid encoding of format information - */ - FormatInformation readFormatInformation() throws FormatException { - - if (parsedFormatInfo != null) { - return parsedFormatInfo; - } - - // Read top-left format info bits - int formatInfoBits1 = 0; - for (int i = 0; i < 6; i++) { - formatInfoBits1 = copyBit(i, 8, formatInfoBits1); - } - // .. and skip a bit in the timing pattern ... - formatInfoBits1 = copyBit(7, 8, formatInfoBits1); - formatInfoBits1 = copyBit(8, 8, formatInfoBits1); - formatInfoBits1 = copyBit(8, 7, formatInfoBits1); - // .. and skip a bit in the timing pattern ... - for (int j = 5; j >= 0; j--) { - formatInfoBits1 = copyBit(8, j, formatInfoBits1); - } - - // Read the top-right/bottom-left pattern too - int dimension = bitMatrix.getHeight(); - int formatInfoBits2 = 0; - int jMin = dimension - 7; - for (int j = dimension - 1; j >= jMin; j--) { - formatInfoBits2 = copyBit(8, j, formatInfoBits2); - } - for (int i = dimension - 8; i < dimension; i++) { - formatInfoBits2 = copyBit(i, 8, formatInfoBits2); - } - - parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits1, formatInfoBits2); - if (parsedFormatInfo != null) { - return parsedFormatInfo; - } - throw FormatException.getFormatInstance(); - } - - /** - *

Reads version information from one of its two locations within the QR Code.

- * - * @return {@link Version} encapsulating the QR Code's version - * @throws FormatException if both version information locations cannot be parsed as - * the valid encoding of version information - */ - Version readVersion() throws FormatException { - - if (parsedVersion != null) { - return parsedVersion; - } - - int dimension = bitMatrix.getHeight(); - - int provisionalVersion = (dimension - 17) >> 2; - if (provisionalVersion <= 6) { - return Version.getVersionForNumber(provisionalVersion); - } - - // Read top-right version info: 3 wide by 6 tall - int versionBits = 0; - int ijMin = dimension - 11; - for (int j = 5; j >= 0; j--) { - for (int i = dimension - 9; i >= ijMin; i--) { - versionBits = copyBit(i, j, versionBits); - } - } - - parsedVersion = Version.decodeVersionInformation(versionBits); - if (parsedVersion != null && parsedVersion.getDimensionForVersion() == dimension) { - return parsedVersion; - } - - // Hmm, failed. Try bottom left: 6 wide by 3 tall - versionBits = 0; - for (int i = 5; i >= 0; i--) { - for (int j = dimension - 9; j >= ijMin; j--) { - versionBits = copyBit(i, j, versionBits); - } - } - - parsedVersion = Version.decodeVersionInformation(versionBits); - if (parsedVersion != null && parsedVersion.getDimensionForVersion() == dimension) { - return parsedVersion; - } - throw FormatException.getFormatInstance(); - } - - private int copyBit(int i, int j, int versionBits) { - return bitMatrix.get(i, j) ? (versionBits << 1) | 0x1 : versionBits << 1; - } - - /** - *

Reads the bits in the {@link BitMatrix} representing the finder pattern in the - * correct order in order to reconstitute the codewords bytes contained within the - * QR Code.

- * - * @return bytes encoded within the QR Code - * @throws FormatException if the exact number of bytes expected is not read - */ - byte[] readCodewords() throws FormatException { - - FormatInformation formatInfo = readFormatInformation(); - Version version = readVersion(); - - // Get the data mask for the format used in this QR Code. This will exclude - // some bits from reading as we wind through the bit matrix. - DataMask dataMask = DataMask.forReference((int) formatInfo.getDataMask()); - int dimension = bitMatrix.getHeight(); - dataMask.unmaskBitMatrix(bitMatrix, dimension); - - BitMatrix functionPattern = version.buildFunctionPattern(); - - boolean readingUp = true; - byte[] result = new byte[version.getTotalCodewords()]; - int resultOffset = 0; - int currentByte = 0; - int bitsRead = 0; - // Read columns in pairs, from right to left - for (int j = dimension - 1; j > 0; j -= 2) { - if (j == 6) { - // Skip whole column with vertical alignment pattern; - // saves time and makes the other code proceed more cleanly - j--; - } - // Read alternatingly from bottom to top then top to bottom - for (int count = 0; count < dimension; count++) { - int i = readingUp ? dimension - 1 - count : count; - for (int col = 0; col < 2; col++) { - // Ignore bits covered by the function pattern - if (!functionPattern.get(j - col, i)) { - // Read a bit - bitsRead++; - currentByte <<= 1; - if (bitMatrix.get(j - col, i)) { - currentByte |= 1; - } - // If we've made a whole byte, save it off - if (bitsRead == 8) { - result[resultOffset++] = (byte) currentByte; - bitsRead = 0; - currentByte = 0; - } - } - } - } - readingUp ^= true; // readingUp = !readingUp; // switch directions - } - if (resultOffset != version.getTotalCodewords()) { - throw FormatException.getFormatInstance(); - } - return result; - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/DataBlock.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/DataBlock.java deleted file mode 100644 index 12959d9c1..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/DataBlock.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.decoder; - -/** - *

Encapsulates a block of data within a QR Code. QR Codes may split their data into - * multiple blocks, each of which is a unit of data and error-correction codewords. Each - * is represented by an instance of this class.

- * - * @author Sean Owen - */ -final class DataBlock { - - private final int numDataCodewords; - private final byte[] codewords; - - private DataBlock(int numDataCodewords, byte[] codewords) { - this.numDataCodewords = numDataCodewords; - this.codewords = codewords; - } - - /** - *

When QR Codes use multiple data blocks, they are actually interleaved. - * That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This - * method will separate the data into original blocks.

- * - * @param rawCodewords bytes as read directly from the QR Code - * @param version version of the QR Code - * @param ecLevel error-correction level of the QR Code - * @return DataBlocks containing original bytes, "de-interleaved" from representation in the - * QR Code - */ - static DataBlock[] getDataBlocks(byte[] rawCodewords, - Version version, - ErrorCorrectionLevel ecLevel) { - - if (rawCodewords.length != version.getTotalCodewords()) { - throw new IllegalArgumentException(); - } - - // Figure out the number and size of data blocks used by this version and - // error correction level - Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); - - // First count the total number of data blocks - int totalBlocks = 0; - Version.ECB[] ecBlockArray = ecBlocks.getECBlocks(); - for (int i = 0; i < ecBlockArray.length; i++) { - totalBlocks += ecBlockArray[i].getCount(); - } - - // Now establish DataBlocks of the appropriate size and number of data codewords - DataBlock[] result = new DataBlock[totalBlocks]; - int numResultBlocks = 0; - for (int j = 0; j < ecBlockArray.length; j++) { - Version.ECB ecBlock = ecBlockArray[j]; - for (int i = 0; i < ecBlock.getCount(); i++) { - int numDataCodewords = ecBlock.getDataCodewords(); - int numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords; - result[numResultBlocks++] = new DataBlock(numDataCodewords, new byte[numBlockCodewords]); - } - } - - // All blocks have the same amount of data, except that the last n - // (where n may be 0) have 1 more byte. Figure out where these start. - int shorterBlocksTotalCodewords = result[0].codewords.length; - int longerBlocksStartAt = result.length - 1; - while (longerBlocksStartAt >= 0) { - int numCodewords = result[longerBlocksStartAt].codewords.length; - if (numCodewords == shorterBlocksTotalCodewords) { - break; - } - longerBlocksStartAt--; - } - longerBlocksStartAt++; - - int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock(); - // The last elements of result may be 1 element longer; - // first fill out as many elements as all of them have - int rawCodewordsOffset = 0; - for (int i = 0; i < shorterBlocksNumDataCodewords; i++) { - for (int j = 0; j < numResultBlocks; j++) { - result[j].codewords[i] = rawCodewords[rawCodewordsOffset++]; - } - } - // Fill out the last data block in the longer ones - for (int j = longerBlocksStartAt; j < numResultBlocks; j++) { - result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++]; - } - // Now add in error correction blocks - int max = result[0].codewords.length; - for (int i = shorterBlocksNumDataCodewords; i < max; i++) { - for (int j = 0; j < numResultBlocks; j++) { - int iOffset = j < longerBlocksStartAt ? i : i + 1; - result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++]; - } - } - return result; - } - - int getNumDataCodewords() { - return numDataCodewords; - } - - byte[] getCodewords() { - return codewords; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/DataMask.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/DataMask.java deleted file mode 100644 index d29dbd47f..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/DataMask.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.decoder; - -import com.google.zxing.common.BitMatrix; - -/** - *

Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations - * of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix, - * including areas used for finder patterns, timing patterns, etc. These areas should be unused - * after the point they are unmasked anyway.

- * - *

Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position - * and j is row position. In fact, as the text says, i is row position and j is column position.

- * - * @author Sean Owen - */ -abstract class DataMask { - - /** - * See ISO 18004:2006 6.8.1 - */ - private static final DataMask[] DATA_MASKS = { - new DataMask000(), - new DataMask001(), - new DataMask010(), - new DataMask011(), - new DataMask100(), - new DataMask101(), - new DataMask110(), - new DataMask111(), - }; - - private DataMask() { - } - - /** - *

Implementations of this method reverse the data masking process applied to a QR Code and - * make its bits ready to read.

- * - * @param bits representation of QR Code bits - * @param dimension dimension of QR Code, represented by bits, being unmasked - */ - final void unmaskBitMatrix(BitMatrix bits, int dimension) { - for (int i = 0; i < dimension; i++) { - for (int j = 0; j < dimension; j++) { - if (isMasked(i, j)) { - bits.flip(j, i); - } - } - } - } - - abstract boolean isMasked(int i, int j); - - /** - * @param reference a value between 0 and 7 indicating one of the eight possible - * data mask patterns a QR Code may use - * @return DataMask encapsulating the data mask pattern - */ - static DataMask forReference(int reference) { - if (reference < 0 || reference > 7) { - throw new IllegalArgumentException(); - } - return DATA_MASKS[reference]; - } - - /** - * 000: mask bits for which (x + y) mod 2 == 0 - */ - private static class DataMask000 extends DataMask { - boolean isMasked(int i, int j) { - return ((i + j) & 0x01) == 0; - } - } - - /** - * 001: mask bits for which x mod 2 == 0 - */ - private static class DataMask001 extends DataMask { - boolean isMasked(int i, int j) { - return (i & 0x01) == 0; - } - } - - /** - * 010: mask bits for which y mod 3 == 0 - */ - private static class DataMask010 extends DataMask { - boolean isMasked(int i, int j) { - return j % 3 == 0; - } - } - - /** - * 011: mask bits for which (x + y) mod 3 == 0 - */ - private static class DataMask011 extends DataMask { - boolean isMasked(int i, int j) { - return (i + j) % 3 == 0; - } - } - - /** - * 100: mask bits for which (x/2 + y/3) mod 2 == 0 - */ - private static class DataMask100 extends DataMask { - boolean isMasked(int i, int j) { - return (((i >>> 1) + (j /3)) & 0x01) == 0; - } - } - - /** - * 101: mask bits for which xy mod 2 + xy mod 3 == 0 - */ - private static class DataMask101 extends DataMask { - boolean isMasked(int i, int j) { - int temp = i * j; - return (temp & 0x01) + (temp % 3) == 0; - } - } - - /** - * 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0 - */ - private static class DataMask110 extends DataMask { - boolean isMasked(int i, int j) { - int temp = i * j; - return (((temp & 0x01) + (temp % 3)) & 0x01) == 0; - } - } - - /** - * 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0 - */ - private static class DataMask111 extends DataMask { - boolean isMasked(int i, int j) { - return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0; - } - } -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java deleted file mode 100644 index ff374ac50..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.decoder; - -import com.google.zxing.FormatException; -import com.google.zxing.common.BitSource; -import com.google.zxing.common.CharacterSetECI; -import com.google.zxing.common.DecoderResult; -import com.google.zxing.common.StringUtils; - -import java.io.UnsupportedEncodingException; -import java.util.Hashtable; -import java.util.Vector; - -/** - *

QR Codes can encode text as bits in one of several modes, and can use multiple modes - * in one QR Code. This class decodes the bits back into text.

- * - *

See ISO 18004:2006, 6.4.3 - 6.4.7

- * - * @author Sean Owen - */ -final class DecodedBitStreamParser { - - /** - * See ISO 18004:2006, 6.4.4 Table 5 - */ - private static final char[] ALPHANUMERIC_CHARS = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', - 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - ' ', '$', '%', '*', '+', '-', '.', '/', ':' - }; - private static final int GB2312_SUBSET = 1; - - private DecodedBitStreamParser() { - } - - static DecoderResult decode(byte[] bytes, Version version, ErrorCorrectionLevel ecLevel, Hashtable hints) - throws FormatException { - BitSource bits = new BitSource(bytes); - StringBuffer result = new StringBuffer(50); - CharacterSetECI currentCharacterSetECI = null; - boolean fc1InEffect = false; - Vector byteSegments = new Vector(1); - Mode mode; - do { - // While still another segment to read... - if (bits.available() < 4) { - // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here - mode = Mode.TERMINATOR; - } else { - try { - mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits - } catch (IllegalArgumentException iae) { - throw FormatException.getFormatInstance(); - } - } - if (!mode.equals(Mode.TERMINATOR)) { - if (mode.equals(Mode.FNC1_FIRST_POSITION) || mode.equals(Mode.FNC1_SECOND_POSITION)) { - // We do little with FNC1 except alter the parsed result a bit according to the spec - fc1InEffect = true; - } else if (mode.equals(Mode.STRUCTURED_APPEND)) { - // not really supported; all we do is ignore it - // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue - bits.readBits(16); - } else if (mode.equals(Mode.ECI)) { - // Count doesn't apply to ECI - int value = parseECIValue(bits); - currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value); - if (currentCharacterSetECI == null) { - throw FormatException.getFormatInstance(); - } - } else { - // First handle Hanzi mode which does not start with character count - if (mode.equals(Mode.HANZI)) { - //chinese mode contains a sub set indicator right after mode indicator - int subset = bits.readBits(4); - int countHanzi = bits.readBits(mode.getCharacterCountBits(version)); - if (subset == GB2312_SUBSET) { - decodeHanziSegment(bits, result, countHanzi); - } - } else { - // "Normal" QR code modes: - // How many characters will follow, encoded in this mode? - int count = bits.readBits(mode.getCharacterCountBits(version)); - if (mode.equals(Mode.NUMERIC)) { - decodeNumericSegment(bits, result, count); - } else if (mode.equals(Mode.ALPHANUMERIC)) { - decodeAlphanumericSegment(bits, result, count, fc1InEffect); - } else if (mode.equals(Mode.BYTE)) { - decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments, hints); - } else if (mode.equals(Mode.KANJI)) { - decodeKanjiSegment(bits, result, count); - } else { - throw FormatException.getFormatInstance(); - } - } - } - } - } while (!mode.equals(Mode.TERMINATOR)); - - return new DecoderResult(bytes, - result.toString(), - byteSegments.isEmpty() ? null : byteSegments, - ecLevel == null ? null : ecLevel.toString()); - } - - /** - * See specification GBT 18284-2000 - */ - private static void decodeHanziSegment(BitSource bits, - StringBuffer result, - int count) throws FormatException { - // Don't crash trying to read more bits than we have available. - if (count * 13 > bits.available()) { - throw FormatException.getFormatInstance(); - } - - // Each character will require 2 bytes. Read the characters as 2-byte pairs - // and decode as GB2312 afterwards - byte[] buffer = new byte[2 * count]; - int offset = 0; - while (count > 0) { - // Each 13 bits encodes a 2-byte character - int twoBytes = bits.readBits(13); - int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060); - if (assembledTwoBytes < 0x003BF) { - // In the 0xA1A1 to 0xAAFE range - assembledTwoBytes += 0x0A1A1; - } else { - // In the 0xB0A1 to 0xFAFE range - assembledTwoBytes += 0x0A6A1; - } - buffer[offset] = (byte) ((assembledTwoBytes >> 8) & 0xFF); - buffer[offset + 1] = (byte) (assembledTwoBytes & 0xFF); - offset += 2; - count--; - } - - try { - result.append(new String(buffer, StringUtils.GB2312)); - } catch (UnsupportedEncodingException uee) { - throw FormatException.getFormatInstance(); - } - } - - private static void decodeKanjiSegment(BitSource bits, - StringBuffer result, - int count) throws FormatException { - // Don't crash trying to read more bits than we have available. - if (count * 13 > bits.available()) { - throw FormatException.getFormatInstance(); - } - - // Each character will require 2 bytes. Read the characters as 2-byte pairs - // and decode as Shift_JIS afterwards - byte[] buffer = new byte[2 * count]; - int offset = 0; - while (count > 0) { - // Each 13 bits encodes a 2-byte character - int twoBytes = bits.readBits(13); - int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0); - if (assembledTwoBytes < 0x01F00) { - // In the 0x8140 to 0x9FFC range - assembledTwoBytes += 0x08140; - } else { - // In the 0xE040 to 0xEBBF range - assembledTwoBytes += 0x0C140; - } - buffer[offset] = (byte) (assembledTwoBytes >> 8); - buffer[offset + 1] = (byte) assembledTwoBytes; - offset += 2; - count--; - } - // Shift_JIS may not be supported in some environments: - try { - result.append(new String(buffer, StringUtils.SHIFT_JIS)); - } catch (UnsupportedEncodingException uee) { - throw FormatException.getFormatInstance(); - } - } - - private static void decodeByteSegment(BitSource bits, - StringBuffer result, - int count, - CharacterSetECI currentCharacterSetECI, - Vector byteSegments, - Hashtable hints) throws FormatException { - // Don't crash trying to read more bits than we have available. - if (count << 3 > bits.available()) { - throw FormatException.getFormatInstance(); - } - - byte[] readBytes = new byte[count]; - for (int i = 0; i < count; i++) { - readBytes[i] = (byte) bits.readBits(8); - } - String encoding; - if (currentCharacterSetECI == null) { - // The spec isn't clear on this mode; see - // section 6.4.5: t does not say which encoding to assuming - // upon decoding. I have seen ISO-8859-1 used as well as - // Shift_JIS -- without anything like an ECI designator to - // give a hint. - encoding = StringUtils.guessEncoding(readBytes, hints); - } else { - encoding = currentCharacterSetECI.getEncodingName(); - } - try { - result.append(new String(readBytes, encoding)); - } catch (UnsupportedEncodingException uce) { - throw FormatException.getFormatInstance(); - } - byteSegments.addElement(readBytes); - } - - private static char toAlphaNumericChar(int value) throws FormatException { - if (value >= ALPHANUMERIC_CHARS.length) { - throw FormatException.getFormatInstance(); - } - return ALPHANUMERIC_CHARS[value]; - } - - private static void decodeAlphanumericSegment(BitSource bits, - StringBuffer result, - int count, - boolean fc1InEffect) throws FormatException { - // Read two characters at a time - int start = result.length(); - while (count > 1) { - int nextTwoCharsBits = bits.readBits(11); - result.append(toAlphaNumericChar(nextTwoCharsBits / 45)); - result.append(toAlphaNumericChar(nextTwoCharsBits % 45)); - count -= 2; - } - if (count == 1) { - // special case: one character left - result.append(toAlphaNumericChar(bits.readBits(6))); - } - // See section 6.4.8.1, 6.4.8.2 - if (fc1InEffect) { - // We need to massage the result a bit if in an FNC1 mode: - for (int i = start; i < result.length(); i++) { - if (result.charAt(i) == '%') { - if (i < result.length() - 1 && result.charAt(i + 1) == '%') { - // %% is rendered as % - result.deleteCharAt(i + 1); - } else { - // In alpha mode, % should be converted to FNC1 separator 0x1D - result.setCharAt(i, (char) 0x1D); - } - } - } - } - } - - private static void decodeNumericSegment(BitSource bits, - StringBuffer result, - int count) throws FormatException { - // Read three digits at a time - while (count >= 3) { - // Each 10 bits encodes three digits - int threeDigitsBits = bits.readBits(10); - if (threeDigitsBits >= 1000) { - throw FormatException.getFormatInstance(); - } - result.append(toAlphaNumericChar(threeDigitsBits / 100)); - result.append(toAlphaNumericChar((threeDigitsBits / 10) % 10)); - result.append(toAlphaNumericChar(threeDigitsBits % 10)); - count -= 3; - } - if (count == 2) { - // Two digits left over to read, encoded in 7 bits - int twoDigitsBits = bits.readBits(7); - if (twoDigitsBits >= 100) { - throw FormatException.getFormatInstance(); - } - result.append(toAlphaNumericChar(twoDigitsBits / 10)); - result.append(toAlphaNumericChar(twoDigitsBits % 10)); - } else if (count == 1) { - // One digit left over to read - int digitBits = bits.readBits(4); - if (digitBits >= 10) { - throw FormatException.getFormatInstance(); - } - result.append(toAlphaNumericChar(digitBits)); - } - } - - private static int parseECIValue(BitSource bits) { - int firstByte = bits.readBits(8); - if ((firstByte & 0x80) == 0) { - // just one byte - return firstByte & 0x7F; - } else if ((firstByte & 0xC0) == 0x80) { - // two bytes - int secondByte = bits.readBits(8); - return ((firstByte & 0x3F) << 8) | secondByte; - } else if ((firstByte & 0xE0) == 0xC0) { - // three bytes - int secondThirdBytes = bits.readBits(16); - return ((firstByte & 0x1F) << 16) | secondThirdBytes; - } - throw new IllegalArgumentException("Bad ECI bits starting with byte " + firstByte); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/ErrorCorrectionLevel.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/ErrorCorrectionLevel.java deleted file mode 100644 index e8d6c2589..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/ErrorCorrectionLevel.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.decoder; - -/** - *

See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels - * defined by the QR code standard.

- * - * @author Sean Owen - */ -public final class ErrorCorrectionLevel { - - // No, we can't use an enum here. J2ME doesn't support it. - - /** - * L = ~7% correction - */ - public static final ErrorCorrectionLevel L = new ErrorCorrectionLevel(0, 0x01, "L"); - /** - * M = ~15% correction - */ - public static final ErrorCorrectionLevel M = new ErrorCorrectionLevel(1, 0x00, "M"); - /** - * Q = ~25% correction - */ - public static final ErrorCorrectionLevel Q = new ErrorCorrectionLevel(2, 0x03, "Q"); - /** - * H = ~30% correction - */ - public static final ErrorCorrectionLevel H = new ErrorCorrectionLevel(3, 0x02, "H"); - - private static final ErrorCorrectionLevel[] FOR_BITS = {M, L, H, Q}; - - private final int ordinal; - private final int bits; - private final String name; - - private ErrorCorrectionLevel(int ordinal, int bits, String name) { - this.ordinal = ordinal; - this.bits = bits; - this.name = name; - } - - public int ordinal() { - return ordinal; - } - - public int getBits() { - return bits; - } - - public String getName() { - return name; - } - - public String toString() { - return name; - } - - /** - * @param bits int containing the two bits encoding a QR Code's error correction level - * @return ErrorCorrectionLevel representing the encoded error correction level - */ - public static ErrorCorrectionLevel forBits(int bits) { - if (bits < 0 || bits >= FOR_BITS.length) { - throw new IllegalArgumentException(); - } - return FOR_BITS[bits]; - } - - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/FormatInformation.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/FormatInformation.java deleted file mode 100644 index 1b76b0de5..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/FormatInformation.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.decoder; - -/** - *

Encapsulates a QR Code's format information, including the data mask used and - * error correction level.

- * - * @author Sean Owen - * @see DataMask - * @see ErrorCorrectionLevel - */ -final class FormatInformation { - - private static final int FORMAT_INFO_MASK_QR = 0x5412; - - /** - * See ISO 18004:2006, Annex C, Table C.1 - */ - private static final int[][] FORMAT_INFO_DECODE_LOOKUP = { - {0x5412, 0x00}, - {0x5125, 0x01}, - {0x5E7C, 0x02}, - {0x5B4B, 0x03}, - {0x45F9, 0x04}, - {0x40CE, 0x05}, - {0x4F97, 0x06}, - {0x4AA0, 0x07}, - {0x77C4, 0x08}, - {0x72F3, 0x09}, - {0x7DAA, 0x0A}, - {0x789D, 0x0B}, - {0x662F, 0x0C}, - {0x6318, 0x0D}, - {0x6C41, 0x0E}, - {0x6976, 0x0F}, - {0x1689, 0x10}, - {0x13BE, 0x11}, - {0x1CE7, 0x12}, - {0x19D0, 0x13}, - {0x0762, 0x14}, - {0x0255, 0x15}, - {0x0D0C, 0x16}, - {0x083B, 0x17}, - {0x355F, 0x18}, - {0x3068, 0x19}, - {0x3F31, 0x1A}, - {0x3A06, 0x1B}, - {0x24B4, 0x1C}, - {0x2183, 0x1D}, - {0x2EDA, 0x1E}, - {0x2BED, 0x1F}, - }; - - /** - * Offset i holds the number of 1 bits in the binary representation of i - */ - private static final int[] BITS_SET_IN_HALF_BYTE = - {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; - - private final ErrorCorrectionLevel errorCorrectionLevel; - private final byte dataMask; - - private FormatInformation(int formatInfo) { - // Bits 3,4 - errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03); - // Bottom 3 bits - dataMask = (byte) (formatInfo & 0x07); - } - - static int numBitsDiffering(int a, int b) { - a ^= b; // a now has a 1 bit exactly where its bit differs with b's - // Count bits set quickly with a series of lookups: - return BITS_SET_IN_HALF_BYTE[a & 0x0F] + - BITS_SET_IN_HALF_BYTE[(a >>> 4 & 0x0F)] + - BITS_SET_IN_HALF_BYTE[(a >>> 8 & 0x0F)] + - BITS_SET_IN_HALF_BYTE[(a >>> 12 & 0x0F)] + - BITS_SET_IN_HALF_BYTE[(a >>> 16 & 0x0F)] + - BITS_SET_IN_HALF_BYTE[(a >>> 20 & 0x0F)] + - BITS_SET_IN_HALF_BYTE[(a >>> 24 & 0x0F)] + - BITS_SET_IN_HALF_BYTE[(a >>> 28 & 0x0F)]; - } - - /** - * @param maskedFormatInfo1 format info indicator, with mask still applied - * @param maskedFormatInfo2 second copy of same info; both are checked at the same time - * to establish best match - * @return information about the format it specifies, or null - * if doesn't seem to match any known pattern - */ - static FormatInformation decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) { - FormatInformation formatInfo = doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2); - if (formatInfo != null) { - return formatInfo; - } - // Should return null, but, some QR codes apparently - // do not mask this info. Try again by actually masking the pattern - // first - return doDecodeFormatInformation(maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR, - maskedFormatInfo2 ^ FORMAT_INFO_MASK_QR); - } - - private static FormatInformation doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) { - // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing - int bestDifference = Integer.MAX_VALUE; - int bestFormatInfo = 0; - for (int i = 0; i < FORMAT_INFO_DECODE_LOOKUP.length; i++) { - int[] decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i]; - int targetInfo = decodeInfo[0]; - if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2) { - // Found an exact match - return new FormatInformation(decodeInfo[1]); - } - int bitsDifference = numBitsDiffering(maskedFormatInfo1, targetInfo); - if (bitsDifference < bestDifference) { - bestFormatInfo = decodeInfo[1]; - bestDifference = bitsDifference; - } - if (maskedFormatInfo1 != maskedFormatInfo2) { - // also try the other option - bitsDifference = numBitsDiffering(maskedFormatInfo2, targetInfo); - if (bitsDifference < bestDifference) { - bestFormatInfo = decodeInfo[1]; - bestDifference = bitsDifference; - } - } - } - // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits - // differing means we found a match - if (bestDifference <= 3) { - return new FormatInformation(bestFormatInfo); - } - return null; - } - - ErrorCorrectionLevel getErrorCorrectionLevel() { - return errorCorrectionLevel; - } - - byte getDataMask() { - return dataMask; - } - - public int hashCode() { - return (errorCorrectionLevel.ordinal() << 3) | (int) dataMask; - } - - public boolean equals(Object o) { - if (!(o instanceof FormatInformation)) { - return false; - } - FormatInformation other = (FormatInformation) o; - return this.errorCorrectionLevel == other.errorCorrectionLevel && - this.dataMask == other.dataMask; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/Mode.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/Mode.java deleted file mode 100644 index 3c66217d3..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/Mode.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.decoder; - -/** - *

See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which - * data can be encoded to bits in the QR code standard.

- * - * @author Sean Owen - */ -public final class Mode { - - // No, we can't use an enum here. J2ME doesn't support it. - - public static final Mode TERMINATOR = new Mode(new int[]{0, 0, 0}, 0x00, "TERMINATOR"); // Not really a mode... - public static final Mode NUMERIC = new Mode(new int[]{10, 12, 14}, 0x01, "NUMERIC"); - public static final Mode ALPHANUMERIC = new Mode(new int[]{9, 11, 13}, 0x02, "ALPHANUMERIC"); - public static final Mode STRUCTURED_APPEND = new Mode(new int[]{0, 0, 0}, 0x03, "STRUCTURED_APPEND"); // Not supported - public static final Mode BYTE = new Mode(new int[]{8, 16, 16}, 0x04, "BYTE"); - public static final Mode ECI = new Mode(null, 0x07, "ECI"); // character counts don't apply - public static final Mode KANJI = new Mode(new int[]{8, 10, 12}, 0x08, "KANJI"); - public static final Mode FNC1_FIRST_POSITION = new Mode(null, 0x05, "FNC1_FIRST_POSITION"); - public static final Mode FNC1_SECOND_POSITION = new Mode(null, 0x09, "FNC1_SECOND_POSITION"); - /** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */ - public static final Mode HANZI = new Mode(new int[]{8, 10, 12}, 0x0D, "HANZI"); - - private final int[] characterCountBitsForVersions; - private final int bits; - private final String name; - - private Mode(int[] characterCountBitsForVersions, int bits, String name) { - this.characterCountBitsForVersions = characterCountBitsForVersions; - this.bits = bits; - this.name = name; - } - - /** - * @param bits four bits encoding a QR Code data mode - * @return Mode encoded by these bits - * @throws IllegalArgumentException if bits do not correspond to a known mode - */ - public static Mode forBits(int bits) { - switch (bits) { - case 0x0: - return TERMINATOR; - case 0x1: - return NUMERIC; - case 0x2: - return ALPHANUMERIC; - case 0x3: - return STRUCTURED_APPEND; - case 0x4: - return BYTE; - case 0x5: - return FNC1_FIRST_POSITION; - case 0x7: - return ECI; - case 0x8: - return KANJI; - case 0x9: - return FNC1_SECOND_POSITION; - case 0xD: - // 0xD is defined in GBT 18284-2000, may not be supported in foreign country - return HANZI; - default: - throw new IllegalArgumentException(); - } - } - - /** - * @param version version in question - * @return number of bits used, in this QR Code symbol {@link Version}, to encode the - * count of characters that will follow encoded in this Mode - */ - public int getCharacterCountBits(Version version) { - if (characterCountBitsForVersions == null) { - throw new IllegalArgumentException("Character count doesn't apply to this mode"); - } - int number = version.getVersionNumber(); - int offset; - if (number <= 9) { - offset = 0; - } else if (number <= 26) { - offset = 1; - } else { - offset = 2; - } - return characterCountBitsForVersions[offset]; - } - - public int getBits() { - return bits; - } - - public String getName() { - return name; - } - - public String toString() { - return name; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/Version.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/Version.java deleted file mode 100644 index ba795de42..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/decoder/Version.java +++ /dev/null @@ -1,586 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.decoder; - -import com.google.zxing.FormatException; -import com.google.zxing.common.BitMatrix; - -/** - * See ISO 18004:2006 Annex D - * - * @author Sean Owen - */ -public final class Version { - - /** - * See ISO 18004:2006 Annex D. - * Element i represents the raw version bits that specify version i + 7 - */ - private static final int[] VERSION_DECODE_INFO = { - 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, - 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, - 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, - 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, - 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, - 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, - 0x2542E, 0x26A64, 0x27541, 0x28C69 - }; - - private static final Version[] VERSIONS = buildVersions(); - - private final int versionNumber; - private final int[] alignmentPatternCenters; - private final ECBlocks[] ecBlocks; - private final int totalCodewords; - - private Version(int versionNumber, - int[] alignmentPatternCenters, - ECBlocks ecBlocks1, - ECBlocks ecBlocks2, - ECBlocks ecBlocks3, - ECBlocks ecBlocks4) { - this.versionNumber = versionNumber; - this.alignmentPatternCenters = alignmentPatternCenters; - this.ecBlocks = new ECBlocks[]{ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4}; - int total = 0; - int ecCodewords = ecBlocks1.getECCodewordsPerBlock(); - ECB[] ecbArray = ecBlocks1.getECBlocks(); - for (int i = 0; i < ecbArray.length; i++) { - ECB ecBlock = ecbArray[i]; - total += ecBlock.getCount() * (ecBlock.getDataCodewords() + ecCodewords); - } - this.totalCodewords = total; - } - - public int getVersionNumber() { - return versionNumber; - } - - public int[] getAlignmentPatternCenters() { - return alignmentPatternCenters; - } - - public int getTotalCodewords() { - return totalCodewords; - } - - public int getDimensionForVersion() { - return 17 + 4 * versionNumber; - } - - public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) { - return ecBlocks[ecLevel.ordinal()]; - } - - /** - *

Deduces version information purely from QR Code dimensions.

- * - * @param dimension dimension in modules - * @return Version for a QR Code of that dimension - * @throws FormatException if dimension is not 1 mod 4 - */ - public static Version getProvisionalVersionForDimension(int dimension) throws FormatException { - if (dimension % 4 != 1) { - throw FormatException.getFormatInstance(); - } - try { - return getVersionForNumber((dimension - 17) >> 2); - } catch (IllegalArgumentException iae) { - throw FormatException.getFormatInstance(); - } - } - - public static Version getVersionForNumber(int versionNumber) { - if (versionNumber < 1 || versionNumber > 40) { - throw new IllegalArgumentException(); - } - return VERSIONS[versionNumber - 1]; - } - - static Version decodeVersionInformation(int versionBits) { - int bestDifference = Integer.MAX_VALUE; - int bestVersion = 0; - for (int i = 0; i < VERSION_DECODE_INFO.length; i++) { - int targetVersion = VERSION_DECODE_INFO[i]; - // Do the version info bits match exactly? done. - if (targetVersion == versionBits) { - return getVersionForNumber(i + 7); - } - // Otherwise see if this is the closest to a real version info bit string - // we have seen so far - int bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion); - if (bitsDifference < bestDifference) { - bestVersion = i + 7; - bestDifference = bitsDifference; - } - } - // We can tolerate up to 3 bits of error since no two version info codewords will - // differ in less than 8 bits. - if (bestDifference <= 3) { - return getVersionForNumber(bestVersion); - } - // If we didn't find a close enough match, fail - return null; - } - - /** - * See ISO 18004:2006 Annex E - */ - BitMatrix buildFunctionPattern() { - int dimension = getDimensionForVersion(); - BitMatrix bitMatrix = new BitMatrix(dimension); - - // Top left finder pattern + separator + format - bitMatrix.setRegion(0, 0, 9, 9); - // Top right finder pattern + separator + format - bitMatrix.setRegion(dimension - 8, 0, 8, 9); - // Bottom left finder pattern + separator + format - bitMatrix.setRegion(0, dimension - 8, 9, 8); - - // Alignment patterns - int max = alignmentPatternCenters.length; - for (int x = 0; x < max; x++) { - int i = alignmentPatternCenters[x] - 2; - for (int y = 0; y < max; y++) { - if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) { - // No alignment patterns near the three finder paterns - continue; - } - bitMatrix.setRegion(alignmentPatternCenters[y] - 2, i, 5, 5); - } - } - - // Vertical timing pattern - bitMatrix.setRegion(6, 9, 1, dimension - 17); - // Horizontal timing pattern - bitMatrix.setRegion(9, 6, dimension - 17, 1); - - if (versionNumber > 6) { - // Version info, top right - bitMatrix.setRegion(dimension - 11, 0, 3, 6); - // Version info, bottom left - bitMatrix.setRegion(0, dimension - 11, 6, 3); - } - - return bitMatrix; - } - - /** - *

Encapsulates a set of error-correction blocks in one symbol version. Most versions will - * use blocks of differing sizes within one version, so, this encapsulates the parameters for - * each set of blocks. It also holds the number of error-correction codewords per block since it - * will be the same across all blocks within one version.

- */ - public static final class ECBlocks { - private final int ecCodewordsPerBlock; - private final ECB[] ecBlocks; - - ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks) { - this.ecCodewordsPerBlock = ecCodewordsPerBlock; - this.ecBlocks = new ECB[]{ecBlocks}; - } - - ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks1, ECB ecBlocks2) { - this.ecCodewordsPerBlock = ecCodewordsPerBlock; - this.ecBlocks = new ECB[]{ecBlocks1, ecBlocks2}; - } - - public int getECCodewordsPerBlock() { - return ecCodewordsPerBlock; - } - - public int getNumBlocks() { - int total = 0; - for (int i = 0; i < ecBlocks.length; i++) { - total += ecBlocks[i].getCount(); - } - return total; - } - - public int getTotalECCodewords() { - return ecCodewordsPerBlock * getNumBlocks(); - } - - public ECB[] getECBlocks() { - return ecBlocks; - } - } - - /** - *

Encapsualtes the parameters for one error-correction block in one symbol version. - * This includes the number of data codewords, and the number of times a block with these - * parameters is used consecutively in the QR code version's format.

- */ - public static final class ECB { - private final int count; - private final int dataCodewords; - - ECB(int count, int dataCodewords) { - this.count = count; - this.dataCodewords = dataCodewords; - } - - public int getCount() { - return count; - } - - public int getDataCodewords() { - return dataCodewords; - } - } - - public String toString() { - return String.valueOf(versionNumber); - } - - /** - * See ISO 18004:2006 6.5.1 Table 9 - */ - private static Version[] buildVersions() { - return new Version[]{ - new Version(1, new int[]{}, - new ECBlocks(7, new ECB(1, 19)), - new ECBlocks(10, new ECB(1, 16)), - new ECBlocks(13, new ECB(1, 13)), - new ECBlocks(17, new ECB(1, 9))), - new Version(2, new int[]{6, 18}, - new ECBlocks(10, new ECB(1, 34)), - new ECBlocks(16, new ECB(1, 28)), - new ECBlocks(22, new ECB(1, 22)), - new ECBlocks(28, new ECB(1, 16))), - new Version(3, new int[]{6, 22}, - new ECBlocks(15, new ECB(1, 55)), - new ECBlocks(26, new ECB(1, 44)), - new ECBlocks(18, new ECB(2, 17)), - new ECBlocks(22, new ECB(2, 13))), - new Version(4, new int[]{6, 26}, - new ECBlocks(20, new ECB(1, 80)), - new ECBlocks(18, new ECB(2, 32)), - new ECBlocks(26, new ECB(2, 24)), - new ECBlocks(16, new ECB(4, 9))), - new Version(5, new int[]{6, 30}, - new ECBlocks(26, new ECB(1, 108)), - new ECBlocks(24, new ECB(2, 43)), - new ECBlocks(18, new ECB(2, 15), - new ECB(2, 16)), - new ECBlocks(22, new ECB(2, 11), - new ECB(2, 12))), - new Version(6, new int[]{6, 34}, - new ECBlocks(18, new ECB(2, 68)), - new ECBlocks(16, new ECB(4, 27)), - new ECBlocks(24, new ECB(4, 19)), - new ECBlocks(28, new ECB(4, 15))), - new Version(7, new int[]{6, 22, 38}, - new ECBlocks(20, new ECB(2, 78)), - new ECBlocks(18, new ECB(4, 31)), - new ECBlocks(18, new ECB(2, 14), - new ECB(4, 15)), - new ECBlocks(26, new ECB(4, 13), - new ECB(1, 14))), - new Version(8, new int[]{6, 24, 42}, - new ECBlocks(24, new ECB(2, 97)), - new ECBlocks(22, new ECB(2, 38), - new ECB(2, 39)), - new ECBlocks(22, new ECB(4, 18), - new ECB(2, 19)), - new ECBlocks(26, new ECB(4, 14), - new ECB(2, 15))), - new Version(9, new int[]{6, 26, 46}, - new ECBlocks(30, new ECB(2, 116)), - new ECBlocks(22, new ECB(3, 36), - new ECB(2, 37)), - new ECBlocks(20, new ECB(4, 16), - new ECB(4, 17)), - new ECBlocks(24, new ECB(4, 12), - new ECB(4, 13))), - new Version(10, new int[]{6, 28, 50}, - new ECBlocks(18, new ECB(2, 68), - new ECB(2, 69)), - new ECBlocks(26, new ECB(4, 43), - new ECB(1, 44)), - new ECBlocks(24, new ECB(6, 19), - new ECB(2, 20)), - new ECBlocks(28, new ECB(6, 15), - new ECB(2, 16))), - new Version(11, new int[]{6, 30, 54}, - new ECBlocks(20, new ECB(4, 81)), - new ECBlocks(30, new ECB(1, 50), - new ECB(4, 51)), - new ECBlocks(28, new ECB(4, 22), - new ECB(4, 23)), - new ECBlocks(24, new ECB(3, 12), - new ECB(8, 13))), - new Version(12, new int[]{6, 32, 58}, - new ECBlocks(24, new ECB(2, 92), - new ECB(2, 93)), - new ECBlocks(22, new ECB(6, 36), - new ECB(2, 37)), - new ECBlocks(26, new ECB(4, 20), - new ECB(6, 21)), - new ECBlocks(28, new ECB(7, 14), - new ECB(4, 15))), - new Version(13, new int[]{6, 34, 62}, - new ECBlocks(26, new ECB(4, 107)), - new ECBlocks(22, new ECB(8, 37), - new ECB(1, 38)), - new ECBlocks(24, new ECB(8, 20), - new ECB(4, 21)), - new ECBlocks(22, new ECB(12, 11), - new ECB(4, 12))), - new Version(14, new int[]{6, 26, 46, 66}, - new ECBlocks(30, new ECB(3, 115), - new ECB(1, 116)), - new ECBlocks(24, new ECB(4, 40), - new ECB(5, 41)), - new ECBlocks(20, new ECB(11, 16), - new ECB(5, 17)), - new ECBlocks(24, new ECB(11, 12), - new ECB(5, 13))), - new Version(15, new int[]{6, 26, 48, 70}, - new ECBlocks(22, new ECB(5, 87), - new ECB(1, 88)), - new ECBlocks(24, new ECB(5, 41), - new ECB(5, 42)), - new ECBlocks(30, new ECB(5, 24), - new ECB(7, 25)), - new ECBlocks(24, new ECB(11, 12), - new ECB(7, 13))), - new Version(16, new int[]{6, 26, 50, 74}, - new ECBlocks(24, new ECB(5, 98), - new ECB(1, 99)), - new ECBlocks(28, new ECB(7, 45), - new ECB(3, 46)), - new ECBlocks(24, new ECB(15, 19), - new ECB(2, 20)), - new ECBlocks(30, new ECB(3, 15), - new ECB(13, 16))), - new Version(17, new int[]{6, 30, 54, 78}, - new ECBlocks(28, new ECB(1, 107), - new ECB(5, 108)), - new ECBlocks(28, new ECB(10, 46), - new ECB(1, 47)), - new ECBlocks(28, new ECB(1, 22), - new ECB(15, 23)), - new ECBlocks(28, new ECB(2, 14), - new ECB(17, 15))), - new Version(18, new int[]{6, 30, 56, 82}, - new ECBlocks(30, new ECB(5, 120), - new ECB(1, 121)), - new ECBlocks(26, new ECB(9, 43), - new ECB(4, 44)), - new ECBlocks(28, new ECB(17, 22), - new ECB(1, 23)), - new ECBlocks(28, new ECB(2, 14), - new ECB(19, 15))), - new Version(19, new int[]{6, 30, 58, 86}, - new ECBlocks(28, new ECB(3, 113), - new ECB(4, 114)), - new ECBlocks(26, new ECB(3, 44), - new ECB(11, 45)), - new ECBlocks(26, new ECB(17, 21), - new ECB(4, 22)), - new ECBlocks(26, new ECB(9, 13), - new ECB(16, 14))), - new Version(20, new int[]{6, 34, 62, 90}, - new ECBlocks(28, new ECB(3, 107), - new ECB(5, 108)), - new ECBlocks(26, new ECB(3, 41), - new ECB(13, 42)), - new ECBlocks(30, new ECB(15, 24), - new ECB(5, 25)), - new ECBlocks(28, new ECB(15, 15), - new ECB(10, 16))), - new Version(21, new int[]{6, 28, 50, 72, 94}, - new ECBlocks(28, new ECB(4, 116), - new ECB(4, 117)), - new ECBlocks(26, new ECB(17, 42)), - new ECBlocks(28, new ECB(17, 22), - new ECB(6, 23)), - new ECBlocks(30, new ECB(19, 16), - new ECB(6, 17))), - new Version(22, new int[]{6, 26, 50, 74, 98}, - new ECBlocks(28, new ECB(2, 111), - new ECB(7, 112)), - new ECBlocks(28, new ECB(17, 46)), - new ECBlocks(30, new ECB(7, 24), - new ECB(16, 25)), - new ECBlocks(24, new ECB(34, 13))), - new Version(23, new int[]{6, 30, 54, 78, 102}, - new ECBlocks(30, new ECB(4, 121), - new ECB(5, 122)), - new ECBlocks(28, new ECB(4, 47), - new ECB(14, 48)), - new ECBlocks(30, new ECB(11, 24), - new ECB(14, 25)), - new ECBlocks(30, new ECB(16, 15), - new ECB(14, 16))), - new Version(24, new int[]{6, 28, 54, 80, 106}, - new ECBlocks(30, new ECB(6, 117), - new ECB(4, 118)), - new ECBlocks(28, new ECB(6, 45), - new ECB(14, 46)), - new ECBlocks(30, new ECB(11, 24), - new ECB(16, 25)), - new ECBlocks(30, new ECB(30, 16), - new ECB(2, 17))), - new Version(25, new int[]{6, 32, 58, 84, 110}, - new ECBlocks(26, new ECB(8, 106), - new ECB(4, 107)), - new ECBlocks(28, new ECB(8, 47), - new ECB(13, 48)), - new ECBlocks(30, new ECB(7, 24), - new ECB(22, 25)), - new ECBlocks(30, new ECB(22, 15), - new ECB(13, 16))), - new Version(26, new int[]{6, 30, 58, 86, 114}, - new ECBlocks(28, new ECB(10, 114), - new ECB(2, 115)), - new ECBlocks(28, new ECB(19, 46), - new ECB(4, 47)), - new ECBlocks(28, new ECB(28, 22), - new ECB(6, 23)), - new ECBlocks(30, new ECB(33, 16), - new ECB(4, 17))), - new Version(27, new int[]{6, 34, 62, 90, 118}, - new ECBlocks(30, new ECB(8, 122), - new ECB(4, 123)), - new ECBlocks(28, new ECB(22, 45), - new ECB(3, 46)), - new ECBlocks(30, new ECB(8, 23), - new ECB(26, 24)), - new ECBlocks(30, new ECB(12, 15), - new ECB(28, 16))), - new Version(28, new int[]{6, 26, 50, 74, 98, 122}, - new ECBlocks(30, new ECB(3, 117), - new ECB(10, 118)), - new ECBlocks(28, new ECB(3, 45), - new ECB(23, 46)), - new ECBlocks(30, new ECB(4, 24), - new ECB(31, 25)), - new ECBlocks(30, new ECB(11, 15), - new ECB(31, 16))), - new Version(29, new int[]{6, 30, 54, 78, 102, 126}, - new ECBlocks(30, new ECB(7, 116), - new ECB(7, 117)), - new ECBlocks(28, new ECB(21, 45), - new ECB(7, 46)), - new ECBlocks(30, new ECB(1, 23), - new ECB(37, 24)), - new ECBlocks(30, new ECB(19, 15), - new ECB(26, 16))), - new Version(30, new int[]{6, 26, 52, 78, 104, 130}, - new ECBlocks(30, new ECB(5, 115), - new ECB(10, 116)), - new ECBlocks(28, new ECB(19, 47), - new ECB(10, 48)), - new ECBlocks(30, new ECB(15, 24), - new ECB(25, 25)), - new ECBlocks(30, new ECB(23, 15), - new ECB(25, 16))), - new Version(31, new int[]{6, 30, 56, 82, 108, 134}, - new ECBlocks(30, new ECB(13, 115), - new ECB(3, 116)), - new ECBlocks(28, new ECB(2, 46), - new ECB(29, 47)), - new ECBlocks(30, new ECB(42, 24), - new ECB(1, 25)), - new ECBlocks(30, new ECB(23, 15), - new ECB(28, 16))), - new Version(32, new int[]{6, 34, 60, 86, 112, 138}, - new ECBlocks(30, new ECB(17, 115)), - new ECBlocks(28, new ECB(10, 46), - new ECB(23, 47)), - new ECBlocks(30, new ECB(10, 24), - new ECB(35, 25)), - new ECBlocks(30, new ECB(19, 15), - new ECB(35, 16))), - new Version(33, new int[]{6, 30, 58, 86, 114, 142}, - new ECBlocks(30, new ECB(17, 115), - new ECB(1, 116)), - new ECBlocks(28, new ECB(14, 46), - new ECB(21, 47)), - new ECBlocks(30, new ECB(29, 24), - new ECB(19, 25)), - new ECBlocks(30, new ECB(11, 15), - new ECB(46, 16))), - new Version(34, new int[]{6, 34, 62, 90, 118, 146}, - new ECBlocks(30, new ECB(13, 115), - new ECB(6, 116)), - new ECBlocks(28, new ECB(14, 46), - new ECB(23, 47)), - new ECBlocks(30, new ECB(44, 24), - new ECB(7, 25)), - new ECBlocks(30, new ECB(59, 16), - new ECB(1, 17))), - new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150}, - new ECBlocks(30, new ECB(12, 121), - new ECB(7, 122)), - new ECBlocks(28, new ECB(12, 47), - new ECB(26, 48)), - new ECBlocks(30, new ECB(39, 24), - new ECB(14, 25)), - new ECBlocks(30, new ECB(22, 15), - new ECB(41, 16))), - new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154}, - new ECBlocks(30, new ECB(6, 121), - new ECB(14, 122)), - new ECBlocks(28, new ECB(6, 47), - new ECB(34, 48)), - new ECBlocks(30, new ECB(46, 24), - new ECB(10, 25)), - new ECBlocks(30, new ECB(2, 15), - new ECB(64, 16))), - new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158}, - new ECBlocks(30, new ECB(17, 122), - new ECB(4, 123)), - new ECBlocks(28, new ECB(29, 46), - new ECB(14, 47)), - new ECBlocks(30, new ECB(49, 24), - new ECB(10, 25)), - new ECBlocks(30, new ECB(24, 15), - new ECB(46, 16))), - new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162}, - new ECBlocks(30, new ECB(4, 122), - new ECB(18, 123)), - new ECBlocks(28, new ECB(13, 46), - new ECB(32, 47)), - new ECBlocks(30, new ECB(48, 24), - new ECB(14, 25)), - new ECBlocks(30, new ECB(42, 15), - new ECB(32, 16))), - new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166}, - new ECBlocks(30, new ECB(20, 117), - new ECB(4, 118)), - new ECBlocks(28, new ECB(40, 47), - new ECB(7, 48)), - new ECBlocks(30, new ECB(43, 24), - new ECB(22, 25)), - new ECBlocks(30, new ECB(10, 15), - new ECB(67, 16))), - new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170}, - new ECBlocks(30, new ECB(19, 118), - new ECB(6, 119)), - new ECBlocks(28, new ECB(18, 47), - new ECB(31, 48)), - new ECBlocks(30, new ECB(34, 24), - new ECB(34, 25)), - new ECBlocks(30, new ECB(20, 15), - new ECB(61, 16))) - }; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/AlignmentPattern.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/AlignmentPattern.java deleted file mode 100644 index 6fc1a2c88..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/AlignmentPattern.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.detector; - -import com.google.zxing.ResultPoint; - -/** - *

Encapsulates an alignment pattern, which are the smaller square patterns found in - * all but the simplest QR Codes.

- * - * @author Sean Owen - */ -public final class AlignmentPattern extends ResultPoint { - - private final float estimatedModuleSize; - - AlignmentPattern(float posX, float posY, float estimatedModuleSize) { - super(posX, posY); - this.estimatedModuleSize = estimatedModuleSize; - } - - /** - *

Determines if this alignment pattern "about equals" an alignment pattern at the stated - * position and size -- meaning, it is at nearly the same center with nearly the same size.

- */ - boolean aboutEquals(float moduleSize, float i, float j) { - if (Math.abs(i - getY()) <= moduleSize && Math.abs(j - getX()) <= moduleSize) { - float moduleSizeDiff = Math.abs(moduleSize - estimatedModuleSize); - return moduleSizeDiff <= 1.0f || moduleSizeDiff / estimatedModuleSize <= 1.0f; - } - return false; - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/AlignmentPatternFinder.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/AlignmentPatternFinder.java deleted file mode 100644 index 3aadf284f..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/AlignmentPatternFinder.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.detector; - -import com.google.zxing.NotFoundException; -import com.google.zxing.ResultPoint; -import com.google.zxing.ResultPointCallback; -import com.google.zxing.common.BitMatrix; - -import java.util.Vector; - -/** - *

This class attempts to find alignment patterns in a QR Code. Alignment patterns look like finder - * patterns but are smaller and appear at regular intervals throughout the image.

- * - *

At the moment this only looks for the bottom-right alignment pattern.

- * - *

This is mostly a simplified copy of {@link FinderPatternFinder}. It is copied, - * pasted and stripped down here for maximum performance but does unfortunately duplicate - * some code.

- * - *

This class is thread-safe but not reentrant. Each thread must allocate its own object. - * - * @author Sean Owen - */ -final class AlignmentPatternFinder { - - private final BitMatrix image; - private final Vector possibleCenters; - private final int startX; - private final int startY; - private final int width; - private final int height; - private final float moduleSize; - private final int[] crossCheckStateCount; - private final ResultPointCallback resultPointCallback; - - /** - *

Creates a finder that will look in a portion of the whole image.

- * - * @param image image to search - * @param startX left column from which to start searching - * @param startY top row from which to start searching - * @param width width of region to search - * @param height height of region to search - * @param moduleSize estimated module size so far - */ - AlignmentPatternFinder(BitMatrix image, - int startX, - int startY, - int width, - int height, - float moduleSize, - ResultPointCallback resultPointCallback) { - this.image = image; - this.possibleCenters = new Vector(5); - this.startX = startX; - this.startY = startY; - this.width = width; - this.height = height; - this.moduleSize = moduleSize; - this.crossCheckStateCount = new int[3]; - this.resultPointCallback = resultPointCallback; - } - - /** - *

This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since - * it's pretty performance-critical and so is written to be fast foremost.

- * - * @return {@link AlignmentPattern} if found - * @throws NotFoundException if not found - */ - AlignmentPattern find() throws NotFoundException { - int startX = this.startX; - int height = this.height; - int maxJ = startX + width; - int middleI = startY + (height >> 1); - // We are looking for black/white/black modules in 1:1:1 ratio; - // this tracks the number of black/white/black modules seen so far - int[] stateCount = new int[3]; - for (int iGen = 0; iGen < height; iGen++) { - // Search from middle outwards - int i = middleI + ((iGen & 0x01) == 0 ? (iGen + 1) >> 1 : -((iGen + 1) >> 1)); - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - int j = startX; - // Burn off leading white pixels before anything else; if we start in the middle of - // a white run, it doesn't make sense to count its length, since we don't know if the - // white run continued to the left of the start point - while (j < maxJ && !image.get(j, i)) { - j++; - } - int currentState = 0; - while (j < maxJ) { - if (image.get(j, i)) { - // Black pixel - if (currentState == 1) { // Counting black pixels - stateCount[currentState]++; - } else { // Counting white pixels - if (currentState == 2) { // A winner? - if (foundPatternCross(stateCount)) { // Yes - AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, j); - if (confirmed != null) { - return confirmed; - } - } - stateCount[0] = stateCount[2]; - stateCount[1] = 1; - stateCount[2] = 0; - currentState = 1; - } else { - stateCount[++currentState]++; - } - } - } else { // White pixel - if (currentState == 1) { // Counting black pixels - currentState++; - } - stateCount[currentState]++; - } - j++; - } - if (foundPatternCross(stateCount)) { - AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, maxJ); - if (confirmed != null) { - return confirmed; - } - } - - } - - // Hmm, nothing we saw was observed and confirmed twice. If we had - // any guess at all, return it. - if (!possibleCenters.isEmpty()) { - return (AlignmentPattern) possibleCenters.elementAt(0); - } - - throw NotFoundException.getNotFoundInstance(); - } - - /** - * Given a count of black/white/black pixels just seen and an end position, - * figures the location of the center of this black/white/black run. - */ - private static float centerFromEnd(int[] stateCount, int end) { - return (float) (end - stateCount[2]) - stateCount[1] / 2.0f; - } - - /** - * @param stateCount count of black/white/black pixels just read - * @return true iff the proportions of the counts is close enough to the 1/1/1 ratios - * used by alignment patterns to be considered a match - */ - private boolean foundPatternCross(int[] stateCount) { - float moduleSize = this.moduleSize; - float maxVariance = moduleSize / 2.0f; - for (int i = 0; i < 3; i++) { - if (Math.abs(moduleSize - stateCount[i]) >= maxVariance) { - return false; - } - } - return true; - } - - /** - *

After a horizontal scan finds a potential alignment pattern, this method - * "cross-checks" by scanning down vertically through the center of the possible - * alignment pattern to see if the same proportion is detected.

- * - * @param startI row where an alignment pattern was detected - * @param centerJ center of the section that appears to cross an alignment pattern - * @param maxCount maximum reasonable number of modules that should be - * observed in any reading state, based on the results of the horizontal scan - * @return vertical center of alignment pattern, or {@link Float#NaN} if not found - */ - private float crossCheckVertical(int startI, int centerJ, int maxCount, - int originalStateCountTotal) { - BitMatrix image = this.image; - - int maxI = image.getHeight(); - int[] stateCount = crossCheckStateCount; - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - - // Start counting up from center - int i = startI; - while (i >= 0 && image.get(centerJ, i) && stateCount[1] <= maxCount) { - stateCount[1]++; - i--; - } - // If already too many modules in this state or ran off the edge: - if (i < 0 || stateCount[1] > maxCount) { - return Float.NaN; - } - while (i >= 0 && !image.get(centerJ, i) && stateCount[0] <= maxCount) { - stateCount[0]++; - i--; - } - if (stateCount[0] > maxCount) { - return Float.NaN; - } - - // Now also count down from center - i = startI + 1; - while (i < maxI && image.get(centerJ, i) && stateCount[1] <= maxCount) { - stateCount[1]++; - i++; - } - if (i == maxI || stateCount[1] > maxCount) { - return Float.NaN; - } - while (i < maxI && !image.get(centerJ, i) && stateCount[2] <= maxCount) { - stateCount[2]++; - i++; - } - if (stateCount[2] > maxCount) { - return Float.NaN; - } - - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; - if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { - return Float.NaN; - } - - return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : Float.NaN; - } - - /** - *

This is called when a horizontal scan finds a possible alignment pattern. It will - * cross check with a vertical scan, and if successful, will see if this pattern had been - * found on a previous horizontal scan. If so, we consider it confirmed and conclude we have - * found the alignment pattern.

- * - * @param stateCount reading state module counts from horizontal scan - * @param i row where alignment pattern may be found - * @param j end of possible alignment pattern in row - * @return {@link AlignmentPattern} if we have found the same pattern twice, or null if not - */ - private AlignmentPattern handlePossibleCenter(int[] stateCount, int i, int j) { - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; - float centerJ = centerFromEnd(stateCount, j); - float centerI = crossCheckVertical(i, (int) centerJ, 2 * stateCount[1], stateCountTotal); - if (!Float.isNaN(centerI)) { - float estimatedModuleSize = (float) (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0f; - int max = possibleCenters.size(); - for (int index = 0; index < max; index++) { - AlignmentPattern center = (AlignmentPattern) possibleCenters.elementAt(index); - // Look for about the same center and module size: - if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { - return new AlignmentPattern(centerJ, centerI, estimatedModuleSize); - } - } - // Hadn't found this before; save it - ResultPoint point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize); - possibleCenters.addElement(point); - if (resultPointCallback != null) { - resultPointCallback.foundPossibleResultPoint(point); - } - } - return null; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/Detector.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/Detector.java deleted file mode 100644 index 724d39d59..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/Detector.java +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.detector; - -import com.google.zxing.DecodeHintType; -import com.google.zxing.FormatException; -import com.google.zxing.NotFoundException; -import com.google.zxing.ResultPoint; -import com.google.zxing.ResultPointCallback; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.DetectorResult; -import com.google.zxing.common.GridSampler; -import com.google.zxing.common.PerspectiveTransform; -import com.google.zxing.qrcode.decoder.Version; - -import java.util.Hashtable; - -/** - *

Encapsulates logic that can detect a QR Code in an image, even if the QR Code - * is rotated or skewed, or partially obscured.

- * - * @author Sean Owen - */ -public class Detector { - - private final BitMatrix image; - private ResultPointCallback resultPointCallback; - - public Detector(BitMatrix image) { - this.image = image; - } - - protected BitMatrix getImage() { - return image; - } - - protected ResultPointCallback getResultPointCallback() { - return resultPointCallback; - } - - /** - *

Detects a QR Code in an image, simply.

- * - * @return {@link DetectorResult} encapsulating results of detecting a QR Code - * @throws NotFoundException if no QR Code can be found - */ - public DetectorResult detect() throws NotFoundException, FormatException { - return detect(null); - } - - /** - *

Detects a QR Code in an image, simply.

- * - * @param hints optional hints to detector - * @return {@link NotFoundException} encapsulating results of detecting a QR Code - * @throws NotFoundException if QR Code cannot be found - * @throws FormatException if a QR Code cannot be decoded - */ - public DetectorResult detect(Hashtable hints) throws NotFoundException, FormatException { - - resultPointCallback = hints == null ? null : - (ResultPointCallback) hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK); - - FinderPatternFinder finder = new FinderPatternFinder(image, resultPointCallback); - FinderPatternInfo info = finder.find(hints); - - return processFinderPatternInfo(info); - } - - protected DetectorResult processFinderPatternInfo(FinderPatternInfo info) - throws NotFoundException, FormatException { - - FinderPattern topLeft = info.getTopLeft(); - FinderPattern topRight = info.getTopRight(); - FinderPattern bottomLeft = info.getBottomLeft(); - - float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); - if (moduleSize < 1.0f) { - throw NotFoundException.getNotFoundInstance(); - } - int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); - Version provisionalVersion = Version.getProvisionalVersionForDimension(dimension); - int modulesBetweenFPCenters = provisionalVersion.getDimensionForVersion() - 7; - - AlignmentPattern alignmentPattern = null; - // Anything above version 1 has an alignment pattern - if (provisionalVersion.getAlignmentPatternCenters().length > 0) { - - // Guess where a "bottom right" finder pattern would have been - float bottomRightX = topRight.getX() - topLeft.getX() + bottomLeft.getX(); - float bottomRightY = topRight.getY() - topLeft.getY() + bottomLeft.getY(); - - // Estimate that alignment pattern is closer by 3 modules - // from "bottom right" to known top left location - float correctionToTopLeft = 1.0f - 3.0f / (float) modulesBetweenFPCenters; - int estAlignmentX = (int) (topLeft.getX() + correctionToTopLeft * (bottomRightX - topLeft.getX())); - int estAlignmentY = (int) (topLeft.getY() + correctionToTopLeft * (bottomRightY - topLeft.getY())); - - // Kind of arbitrary -- expand search radius before giving up - for (int i = 4; i <= 16; i <<= 1) { - try { - alignmentPattern = findAlignmentInRegion(moduleSize, - estAlignmentX, - estAlignmentY, - (float) i); - break; - } catch (NotFoundException re) { - // try next round - } - } - // If we didn't find alignment pattern... well try anyway without it - } - - PerspectiveTransform transform = - createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); - - BitMatrix bits = sampleGrid(image, transform, dimension); - - ResultPoint[] points; - if (alignmentPattern == null) { - points = new ResultPoint[]{bottomLeft, topLeft, topRight}; - } else { - points = new ResultPoint[]{bottomLeft, topLeft, topRight, alignmentPattern}; - } - return new DetectorResult(bits, points); - } - - public static PerspectiveTransform createTransform(ResultPoint topLeft, - ResultPoint topRight, - ResultPoint bottomLeft, - ResultPoint alignmentPattern, - int dimension) { - float dimMinusThree = (float) dimension - 3.5f; - float bottomRightX; - float bottomRightY; - float sourceBottomRightX; - float sourceBottomRightY; - if (alignmentPattern != null) { - bottomRightX = alignmentPattern.getX(); - bottomRightY = alignmentPattern.getY(); - sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f; - } else { - // Don't have an alignment pattern, just make up the bottom-right point - bottomRightX = (topRight.getX() - topLeft.getX()) + bottomLeft.getX(); - bottomRightY = (topRight.getY() - topLeft.getY()) + bottomLeft.getY(); - sourceBottomRightX = sourceBottomRightY = dimMinusThree; - } - - return PerspectiveTransform.quadrilateralToQuadrilateral( - 3.5f, - 3.5f, - dimMinusThree, - 3.5f, - sourceBottomRightX, - sourceBottomRightY, - 3.5f, - dimMinusThree, - topLeft.getX(), - topLeft.getY(), - topRight.getX(), - topRight.getY(), - bottomRightX, - bottomRightY, - bottomLeft.getX(), - bottomLeft.getY()); - } - - private static BitMatrix sampleGrid(BitMatrix image, - PerspectiveTransform transform, - int dimension) throws NotFoundException { - - GridSampler sampler = GridSampler.getInstance(); - return sampler.sampleGrid(image, dimension, dimension, transform); - } - - /** - *

Computes the dimension (number of modules on a size) of the QR Code based on the position - * of the finder patterns and estimated module size.

- */ - protected static int computeDimension(ResultPoint topLeft, - ResultPoint topRight, - ResultPoint bottomLeft, - float moduleSize) throws NotFoundException { - int tltrCentersDimension = round(ResultPoint.distance(topLeft, topRight) / moduleSize); - int tlblCentersDimension = round(ResultPoint.distance(topLeft, bottomLeft) / moduleSize); - int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; - switch (dimension & 0x03) { // mod 4 - case 0: - dimension++; - break; - // 1? do nothing - case 2: - dimension--; - break; - case 3: - throw NotFoundException.getNotFoundInstance(); - } - return dimension; - } - - /** - *

Computes an average estimated module size based on estimated derived from the positions - * of the three finder patterns.

- */ - protected float calculateModuleSize(ResultPoint topLeft, - ResultPoint topRight, - ResultPoint bottomLeft) { - // Take the average - return (calculateModuleSizeOneWay(topLeft, topRight) + - calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f; - } - - /** - *

Estimates module size based on two finder patterns -- it uses - * {@link #sizeOfBlackWhiteBlackRunBothWays(int, int, int, int)} to figure the - * width of each, measuring along the axis between their centers.

- */ - private float calculateModuleSizeOneWay(ResultPoint pattern, ResultPoint otherPattern) { - float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int) pattern.getX(), - (int) pattern.getY(), - (int) otherPattern.getX(), - (int) otherPattern.getY()); - float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int) otherPattern.getX(), - (int) otherPattern.getY(), - (int) pattern.getX(), - (int) pattern.getY()); - if (Float.isNaN(moduleSizeEst1)) { - return moduleSizeEst2 / 7.0f; - } - if (Float.isNaN(moduleSizeEst2)) { - return moduleSizeEst1 / 7.0f; - } - // Average them, and divide by 7 since we've counted the width of 3 black modules, - // and 1 white and 1 black module on either side. Ergo, divide sum by 14. - return (moduleSizeEst1 + moduleSizeEst2) / 14.0f; - } - - /** - * See {@link #sizeOfBlackWhiteBlackRun(int, int, int, int)}; computes the total width of - * a finder pattern by looking for a black-white-black run from the center in the direction - * of another point (another finder pattern center), and in the opposite direction too.

- */ - private float sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY) { - - float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY); - - // Now count other way -- don't run off image though of course - float scale = 1.0f; - int otherToX = fromX - (toX - fromX); - if (otherToX < 0) { - scale = (float) fromX / (float) (fromX - otherToX); - otherToX = 0; - } else if (otherToX > image.getWidth()) { - scale = (float) (image.getWidth() - fromX) / (float) (otherToX - fromX); - otherToX = image.getWidth(); - } - int otherToY = (int) (fromY - (toY - fromY) * scale); - - scale = 1.0f; - if (otherToY < 0) { - scale = (float) fromY / (float) (fromY - otherToY); - otherToY = 0; - } else if (otherToY > image.getHeight()) { - scale = (float) (image.getHeight() - fromY) / (float) (otherToY - fromY); - otherToY = image.getHeight(); - } - otherToX = (int) (fromX + (otherToX - fromX) * scale); - - result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); - return result; - } - - /** - *

This method traces a line from a point in the image, in the direction towards another point. - * It begins in a black region, and keeps going until it finds white, then black, then white again. - * It reports the distance from the start to this point.

- * - *

This is used when figuring out how wide a finder pattern is, when the finder pattern - * may be skewed or rotated.

- */ - private float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY) { - // Mild variant of Bresenham's algorithm; - // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm - boolean steep = Math.abs(toY - fromY) > Math.abs(toX - fromX); - if (steep) { - int temp = fromX; - fromX = fromY; - fromY = temp; - temp = toX; - toX = toY; - toY = temp; - } - - int dx = Math.abs(toX - fromX); - int dy = Math.abs(toY - fromY); - int error = -dx >> 1; - int xstep = fromX < toX ? 1 : -1; - int ystep = fromY < toY ? 1 : -1; - - // In black pixels, looking for white, first or second time. - int state = 0; - for (int x = fromX, y = fromY; x != toX; x += xstep) { - int realX = steep ? y : x; - int realY = steep ? x : y; - - // In white pixels, looking for black. - // FIXME(dswitkin): This method seems to assume square images, which can cause these calls to - // BitMatrix.get() to throw ArrayIndexOutOfBoundsException. - if (state == 1) { - if (image.get(realX, realY)) { - state++; - } - } else { - if (!image.get(realX, realY)) { - state++; - } - } - - // Found black, white, black, and stumbled back onto white, so we're done. - if (state == 3) { - int diffX = x - fromX; - int diffY = y - fromY; - if (xstep < 0) { - diffX++; - } - return (float) Math.sqrt((double) (diffX * diffX + diffY * diffY)); - } - error += dy; - if (error > 0) { - if (y == toY) { - break; - } - y += ystep; - error -= dx; - } - } - int diffX = toX - fromX; - int diffY = toY - fromY; - return (float) Math.sqrt((double) (diffX * diffX + diffY * diffY)); - } - - /** - *

Attempts to locate an alignment pattern in a limited region of the image, which is - * guessed to contain it. This method uses {@link AlignmentPattern}.

- * - * @param overallEstModuleSize estimated module size so far - * @param estAlignmentX x coordinate of center of area probably containing alignment pattern - * @param estAlignmentY y coordinate of above - * @param allowanceFactor number of pixels in all directions to search from the center - * @return {@link AlignmentPattern} if found, or null otherwise - * @throws NotFoundException if an unexpected error occurs during detection - */ - protected AlignmentPattern findAlignmentInRegion(float overallEstModuleSize, - int estAlignmentX, - int estAlignmentY, - float allowanceFactor) - throws NotFoundException { - // Look for an alignment pattern (3 modules in size) around where it - // should be - int allowance = (int) (allowanceFactor * overallEstModuleSize); - int alignmentAreaLeftX = Math.max(0, estAlignmentX - allowance); - int alignmentAreaRightX = Math.min(image.getWidth() - 1, estAlignmentX + allowance); - if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) { - throw NotFoundException.getNotFoundInstance(); - } - - int alignmentAreaTopY = Math.max(0, estAlignmentY - allowance); - int alignmentAreaBottomY = Math.min(image.getHeight() - 1, estAlignmentY + allowance); - if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3) { - throw NotFoundException.getNotFoundInstance(); - } - - AlignmentPatternFinder alignmentFinder = - new AlignmentPatternFinder( - image, - alignmentAreaLeftX, - alignmentAreaTopY, - alignmentAreaRightX - alignmentAreaLeftX, - alignmentAreaBottomY - alignmentAreaTopY, - overallEstModuleSize, - resultPointCallback); - return alignmentFinder.find(); - } - - /** - * Ends up being a bit faster than Math.round(). This merely rounds its argument to the nearest int, - * where x.5 rounds up. - */ - private static int round(float d) { - return (int) (d + 0.5f); - } -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/FinderPattern.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/FinderPattern.java deleted file mode 100644 index 7a9914d76..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/FinderPattern.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.detector; - -import com.google.zxing.ResultPoint; - -/** - *

Encapsulates a finder pattern, which are the three square patterns found in - * the corners of QR Codes. It also encapsulates a count of similar finder patterns, - * as a convenience to the finder's bookkeeping.

- * - * @author Sean Owen - */ -public final class FinderPattern extends ResultPoint { - - private final float estimatedModuleSize; - private int count; - - FinderPattern(float posX, float posY, float estimatedModuleSize) { - super(posX, posY); - this.estimatedModuleSize = estimatedModuleSize; - this.count = 1; - } - - public float getEstimatedModuleSize() { - return estimatedModuleSize; - } - - int getCount() { - return count; - } - - void incrementCount() { - this.count++; - } - - /** - *

Determines if this finder pattern "about equals" a finder pattern at the stated - * position and size -- meaning, it is at nearly the same center with nearly the same size.

- */ - boolean aboutEquals(float moduleSize, float i, float j) { - if (Math.abs(i - getY()) <= moduleSize && Math.abs(j - getX()) <= moduleSize) { - float moduleSizeDiff = Math.abs(moduleSize - estimatedModuleSize); - return moduleSizeDiff <= 1.0f || moduleSizeDiff / estimatedModuleSize <= 1.0f; - } - return false; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/FinderPatternFinder.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/FinderPatternFinder.java deleted file mode 100644 index 01b3bde2a..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/FinderPatternFinder.java +++ /dev/null @@ -1,585 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.detector; - -import com.google.zxing.DecodeHintType; -import com.google.zxing.NotFoundException; -import com.google.zxing.ResultPoint; -import com.google.zxing.ResultPointCallback; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.Collections; -import com.google.zxing.common.Comparator; - -import java.util.Hashtable; -import java.util.Vector; - -/** - *

This class attempts to find finder patterns in a QR Code. Finder patterns are the square - * markers at three corners of a QR Code.

- * - *

This class is thread-safe but not reentrant. Each thread must allocate its own object. - * - * @author Sean Owen - */ -public class FinderPatternFinder { - - private static final int CENTER_QUORUM = 2; - protected static final int MIN_SKIP = 3; // 1 pixel/module times 3 modules/center - protected static final int MAX_MODULES = 57; // support up to version 10 for mobile clients - private static final int INTEGER_MATH_SHIFT = 8; - - private final BitMatrix image; - private final Vector possibleCenters; - private boolean hasSkipped; - private final int[] crossCheckStateCount; - private final ResultPointCallback resultPointCallback; - - /** - *

Creates a finder that will search the image for three finder patterns.

- * - * @param image image to search - */ - public FinderPatternFinder(BitMatrix image) { - this(image, null); - } - - public FinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback) { - this.image = image; - this.possibleCenters = new Vector(); - this.crossCheckStateCount = new int[5]; - this.resultPointCallback = resultPointCallback; - } - - protected BitMatrix getImage() { - return image; - } - - protected Vector getPossibleCenters() { - return possibleCenters; - } - - FinderPatternInfo find(Hashtable hints) throws NotFoundException { - boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER); - int maxI = image.getHeight(); - int maxJ = image.getWidth(); - // We are looking for black/white/black/white/black modules in - // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far - - // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the - // image, and then account for the center being 3 modules in size. This gives the smallest - // number of pixels the center could be, so skip this often. When trying harder, look for all - // QR versions regardless of how dense they are. - int iSkip = (3 * maxI) / (4 * MAX_MODULES); - if (iSkip < MIN_SKIP || tryHarder) { - iSkip = MIN_SKIP; - } - - boolean done = false; - int[] stateCount = new int[5]; - for (int i = iSkip - 1; i < maxI && !done; i += iSkip) { - // Get a row of black/white values - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - stateCount[3] = 0; - stateCount[4] = 0; - int currentState = 0; - for (int j = 0; j < maxJ; j++) { - if (image.get(j, i)) { - // Black pixel - if ((currentState & 1) == 1) { // Counting white pixels - currentState++; - } - stateCount[currentState]++; - } else { // White pixel - if ((currentState & 1) == 0) { // Counting black pixels - if (currentState == 4) { // A winner? - if (foundPatternCross(stateCount)) { // Yes - boolean confirmed = handlePossibleCenter(stateCount, i, j); - if (confirmed) { - // Start examining every other line. Checking each line turned out to be too - // expensive and didn't improve performance. - iSkip = 2; - if (hasSkipped) { - done = haveMultiplyConfirmedCenters(); - } else { - int rowSkip = findRowSkip(); - if (rowSkip > stateCount[2]) { - // Skip rows between row of lower confirmed center - // and top of presumed third confirmed center - // but back up a bit to get a full chance of detecting - // it, entire width of center of finder pattern - - // Skip by rowSkip, but back off by stateCount[2] (size of last center - // of pattern we saw) to be conservative, and also back off by iSkip which - // is about to be re-added - i += rowSkip - stateCount[2] - iSkip; - j = maxJ - 1; - } - } - } else { - stateCount[0] = stateCount[2]; - stateCount[1] = stateCount[3]; - stateCount[2] = stateCount[4]; - stateCount[3] = 1; - stateCount[4] = 0; - currentState = 3; - continue; - } - // Clear state to start looking again - currentState = 0; - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - stateCount[3] = 0; - stateCount[4] = 0; - } else { // No, shift counts back by two - stateCount[0] = stateCount[2]; - stateCount[1] = stateCount[3]; - stateCount[2] = stateCount[4]; - stateCount[3] = 1; - stateCount[4] = 0; - currentState = 3; - } - } else { - stateCount[++currentState]++; - } - } else { // Counting white pixels - stateCount[currentState]++; - } - } - } - if (foundPatternCross(stateCount)) { - boolean confirmed = handlePossibleCenter(stateCount, i, maxJ); - if (confirmed) { - iSkip = stateCount[0]; - if (hasSkipped) { - // Found a third one - done = haveMultiplyConfirmedCenters(); - } - } - } - } - - FinderPattern[] patternInfo = selectBestPatterns(); - ResultPoint.orderBestPatterns(patternInfo); - - return new FinderPatternInfo(patternInfo); - } - - /** - * Given a count of black/white/black/white/black pixels just seen and an end position, - * figures the location of the center of this run. - */ - private static float centerFromEnd(int[] stateCount, int end) { - return (float) (end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0f; - } - - /** - * @param stateCount count of black/white/black/white/black pixels just read - * @return true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios - * used by finder patterns to be considered a match - */ - protected static boolean foundPatternCross(int[] stateCount) { - int totalModuleSize = 0; - for (int i = 0; i < 5; i++) { - int count = stateCount[i]; - if (count == 0) { - return false; - } - totalModuleSize += count; - } - if (totalModuleSize < 7) { - return false; - } - int moduleSize = (totalModuleSize << INTEGER_MATH_SHIFT) / 7; - int maxVariance = moduleSize / 2; - // Allow less than 50% variance from 1-1-3-1-1 proportions - return Math.abs(moduleSize - (stateCount[0] << INTEGER_MATH_SHIFT)) < maxVariance && - Math.abs(moduleSize - (stateCount[1] << INTEGER_MATH_SHIFT)) < maxVariance && - Math.abs(3 * moduleSize - (stateCount[2] << INTEGER_MATH_SHIFT)) < 3 * maxVariance && - Math.abs(moduleSize - (stateCount[3] << INTEGER_MATH_SHIFT)) < maxVariance && - Math.abs(moduleSize - (stateCount[4] << INTEGER_MATH_SHIFT)) < maxVariance; - } - - private int[] getCrossCheckStateCount() { - crossCheckStateCount[0] = 0; - crossCheckStateCount[1] = 0; - crossCheckStateCount[2] = 0; - crossCheckStateCount[3] = 0; - crossCheckStateCount[4] = 0; - return crossCheckStateCount; - } - - /** - *

After a horizontal scan finds a potential finder pattern, this method - * "cross-checks" by scanning down vertically through the center of the possible - * finder pattern to see if the same proportion is detected.

- * - * @param startI row where a finder pattern was detected - * @param centerJ center of the section that appears to cross a finder pattern - * @param maxCount maximum reasonable number of modules that should be - * observed in any reading state, based on the results of the horizontal scan - * @return vertical center of finder pattern, or {@link Float#NaN} if not found - */ - private float crossCheckVertical(int startI, int centerJ, int maxCount, - int originalStateCountTotal) { - BitMatrix image = this.image; - - int maxI = image.getHeight(); - int[] stateCount = getCrossCheckStateCount(); - - // Start counting up from center - int i = startI; - while (i >= 0 && image.get(centerJ, i)) { - stateCount[2]++; - i--; - } - if (i < 0) { - return Float.NaN; - } - while (i >= 0 && !image.get(centerJ, i) && stateCount[1] <= maxCount) { - stateCount[1]++; - i--; - } - // If already too many modules in this state or ran off the edge: - if (i < 0 || stateCount[1] > maxCount) { - return Float.NaN; - } - while (i >= 0 && image.get(centerJ, i) && stateCount[0] <= maxCount) { - stateCount[0]++; - i--; - } - if (stateCount[0] > maxCount) { - return Float.NaN; - } - - // Now also count down from center - i = startI + 1; - while (i < maxI && image.get(centerJ, i)) { - stateCount[2]++; - i++; - } - if (i == maxI) { - return Float.NaN; - } - while (i < maxI && !image.get(centerJ, i) && stateCount[3] < maxCount) { - stateCount[3]++; - i++; - } - if (i == maxI || stateCount[3] >= maxCount) { - return Float.NaN; - } - while (i < maxI && image.get(centerJ, i) && stateCount[4] < maxCount) { - stateCount[4]++; - i++; - } - if (stateCount[4] >= maxCount) { - return Float.NaN; - } - - // If we found a finder-pattern-like section, but its size is more than 40% different than - // the original, assume it's a false positive - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + - stateCount[4]; - if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { - return Float.NaN; - } - - return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : Float.NaN; - } - - /** - *

Like {@link #crossCheckVertical(int, int, int, int)}, and in fact is basically identical, - * except it reads horizontally instead of vertically. This is used to cross-cross - * check a vertical cross check and locate the real center of the alignment pattern.

- */ - private float crossCheckHorizontal(int startJ, int centerI, int maxCount, - int originalStateCountTotal) { - BitMatrix image = this.image; - - int maxJ = image.getWidth(); - int[] stateCount = getCrossCheckStateCount(); - - int j = startJ; - while (j >= 0 && image.get(j, centerI)) { - stateCount[2]++; - j--; - } - if (j < 0) { - return Float.NaN; - } - while (j >= 0 && !image.get(j, centerI) && stateCount[1] <= maxCount) { - stateCount[1]++; - j--; - } - if (j < 0 || stateCount[1] > maxCount) { - return Float.NaN; - } - while (j >= 0 && image.get(j, centerI) && stateCount[0] <= maxCount) { - stateCount[0]++; - j--; - } - if (stateCount[0] > maxCount) { - return Float.NaN; - } - - j = startJ + 1; - while (j < maxJ && image.get(j, centerI)) { - stateCount[2]++; - j++; - } - if (j == maxJ) { - return Float.NaN; - } - while (j < maxJ && !image.get(j, centerI) && stateCount[3] < maxCount) { - stateCount[3]++; - j++; - } - if (j == maxJ || stateCount[3] >= maxCount) { - return Float.NaN; - } - while (j < maxJ && image.get(j, centerI) && stateCount[4] < maxCount) { - stateCount[4]++; - j++; - } - if (stateCount[4] >= maxCount) { - return Float.NaN; - } - - // If we found a finder-pattern-like section, but its size is significantly different than - // the original, assume it's a false positive - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + - stateCount[4]; - if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) { - return Float.NaN; - } - - return foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : Float.NaN; - } - - /** - *

This is called when a horizontal scan finds a possible alignment pattern. It will - * cross check with a vertical scan, and if successful, will, ah, cross-cross-check - * with another horizontal scan. This is needed primarily to locate the real horizontal - * center of the pattern in cases of extreme skew.

- * - *

If that succeeds the finder pattern location is added to a list that tracks - * the number of times each location has been nearly-matched as a finder pattern. - * Each additional find is more evidence that the location is in fact a finder - * pattern center - * - * @param stateCount reading state module counts from horizontal scan - * @param i row where finder pattern may be found - * @param j end of possible finder pattern in row - * @return true if a finder pattern candidate was found this time - */ - protected boolean handlePossibleCenter(int[] stateCount, int i, int j) { - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + - stateCount[4]; - float centerJ = centerFromEnd(stateCount, j); - float centerI = crossCheckVertical(i, (int) centerJ, stateCount[2], stateCountTotal); - if (!Float.isNaN(centerI)) { - // Re-cross check - centerJ = crossCheckHorizontal((int) centerJ, (int) centerI, stateCount[2], stateCountTotal); - if (!Float.isNaN(centerJ)) { - float estimatedModuleSize = (float) stateCountTotal / 7.0f; - boolean found = false; - int max = possibleCenters.size(); - for (int index = 0; index < max; index++) { - FinderPattern center = (FinderPattern) possibleCenters.elementAt(index); - // Look for about the same center and module size: - if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { - center.incrementCount(); - found = true; - break; - } - } - if (!found) { - ResultPoint point = new FinderPattern(centerJ, centerI, estimatedModuleSize); - possibleCenters.addElement(point); - if (resultPointCallback != null) { - resultPointCallback.foundPossibleResultPoint(point); - } - } - return true; - } - } - return false; - } - - /** - * @return number of rows we could safely skip during scanning, based on the first - * two finder patterns that have been located. In some cases their position will - * allow us to infer that the third pattern must lie below a certain point farther - * down in the image. - */ - private int findRowSkip() { - int max = possibleCenters.size(); - if (max <= 1) { - return 0; - } - FinderPattern firstConfirmedCenter = null; - for (int i = 0; i < max; i++) { - FinderPattern center = (FinderPattern) possibleCenters.elementAt(i); - if (center.getCount() >= CENTER_QUORUM) { - if (firstConfirmedCenter == null) { - firstConfirmedCenter = center; - } else { - // We have two confirmed centers - // How far down can we skip before resuming looking for the next - // pattern? In the worst case, only the difference between the - // difference in the x / y coordinates of the two centers. - // This is the case where you find top left last. - hasSkipped = true; - return (int) (Math.abs(firstConfirmedCenter.getX() - center.getX()) - - Math.abs(firstConfirmedCenter.getY() - center.getY())) / 2; - } - } - } - return 0; - } - - /** - * @return true iff we have found at least 3 finder patterns that have been detected - * at least {@link #CENTER_QUORUM} times each, and, the estimated module size of the - * candidates is "pretty similar" - */ - private boolean haveMultiplyConfirmedCenters() { - int confirmedCount = 0; - float totalModuleSize = 0.0f; - int max = possibleCenters.size(); - for (int i = 0; i < max; i++) { - FinderPattern pattern = (FinderPattern) possibleCenters.elementAt(i); - if (pattern.getCount() >= CENTER_QUORUM) { - confirmedCount++; - totalModuleSize += pattern.getEstimatedModuleSize(); - } - } - if (confirmedCount < 3) { - return false; - } - // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive" - // and that we need to keep looking. We detect this by asking if the estimated module sizes - // vary too much. We arbitrarily say that when the total deviation from average exceeds - // 5% of the total module size estimates, it's too much. - float average = totalModuleSize / (float) max; - float totalDeviation = 0.0f; - for (int i = 0; i < max; i++) { - FinderPattern pattern = (FinderPattern) possibleCenters.elementAt(i); - totalDeviation += Math.abs(pattern.getEstimatedModuleSize() - average); - } - return totalDeviation <= 0.05f * totalModuleSize; - } - - /** - * @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are - * those that have been detected at least {@link #CENTER_QUORUM} times, and whose module - * size differs from the average among those patterns the least - * @throws NotFoundException if 3 such finder patterns do not exist - */ - private FinderPattern[] selectBestPatterns() throws NotFoundException { - - int startSize = possibleCenters.size(); - if (startSize < 3) { - // Couldn't find enough finder patterns - throw NotFoundException.getNotFoundInstance(); - } - - // Filter outlier possibilities whose module size is too different - if (startSize > 3) { - // But we can only afford to do so if we have at least 4 possibilities to choose from - float totalModuleSize = 0.0f; - float square = 0.0f; - for (int i = 0; i < startSize; i++) { - float size = ((FinderPattern) possibleCenters.elementAt(i)).getEstimatedModuleSize(); - totalModuleSize += size; - square += size * size; - } - float average = totalModuleSize / (float) startSize; - float stdDev = (float) Math.sqrt(square / startSize - average * average); - - Collections.insertionSort(possibleCenters, new FurthestFromAverageComparator(average)); - - float limit = Math.max(0.2f * average, stdDev); - - for (int i = 0; i < possibleCenters.size() && possibleCenters.size() > 3; i++) { - FinderPattern pattern = (FinderPattern) possibleCenters.elementAt(i); - if (Math.abs(pattern.getEstimatedModuleSize() - average) > limit) { - possibleCenters.removeElementAt(i); - i--; - } - } - } - - if (possibleCenters.size() > 3) { - // Throw away all but those first size candidate points we found. - - float totalModuleSize = 0.0f; - for (int i = 0; i < possibleCenters.size(); i++) { - totalModuleSize += ((FinderPattern) possibleCenters.elementAt(i)).getEstimatedModuleSize(); - } - - float average = totalModuleSize / (float) possibleCenters.size(); - - Collections.insertionSort(possibleCenters, new CenterComparator(average)); - - possibleCenters.setSize(3); - } - - return new FinderPattern[]{ - (FinderPattern) possibleCenters.elementAt(0), - (FinderPattern) possibleCenters.elementAt(1), - (FinderPattern) possibleCenters.elementAt(2) - }; - } - - /** - *

Orders by furthest from average

- */ - private static class FurthestFromAverageComparator implements Comparator { - private final float average; - private FurthestFromAverageComparator(float f) { - average = f; - } - public int compare(Object center1, Object center2) { - float dA = Math.abs(((FinderPattern) center2).getEstimatedModuleSize() - average); - float dB = Math.abs(((FinderPattern) center1).getEstimatedModuleSize() - average); - return dA < dB ? -1 : dA == dB ? 0 : 1; - } - } - - /** - *

Orders by {@link FinderPattern#getCount()}, descending.

- */ - private static class CenterComparator implements Comparator { - private final float average; - private CenterComparator(float f) { - average = f; - } - public int compare(Object center1, Object center2) { - if (((FinderPattern) center2).getCount() == ((FinderPattern) center1).getCount()) { - float dA = Math.abs(((FinderPattern) center2).getEstimatedModuleSize() - average); - float dB = Math.abs(((FinderPattern) center1).getEstimatedModuleSize() - average); - return dA < dB ? 1 : dA == dB ? 0 : -1; - } else { - return ((FinderPattern) center2).getCount() - ((FinderPattern) center1).getCount(); - } - } - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/FinderPatternInfo.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/FinderPatternInfo.java deleted file mode 100644 index 3c3401085..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/detector/FinderPatternInfo.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * 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 com.google.zxing.qrcode.detector; - -/** - *

Encapsulates information about finder patterns in an image, including the location of - * the three finder patterns, and their estimated module size.

- * - * @author Sean Owen - */ -public final class FinderPatternInfo { - - private final FinderPattern bottomLeft; - private final FinderPattern topLeft; - private final FinderPattern topRight; - - public FinderPatternInfo(FinderPattern[] patternCenters) { - this.bottomLeft = patternCenters[0]; - this.topLeft = patternCenters[1]; - this.topRight = patternCenters[2]; - } - - public FinderPattern getBottomLeft() { - return bottomLeft; - } - - public FinderPattern getTopLeft() { - return topLeft; - } - - public FinderPattern getTopRight() { - return topRight; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/BlockPair.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/BlockPair.java deleted file mode 100644 index 5714d9c3a..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/BlockPair.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing.qrcode.encoder; - -final class BlockPair { - - private final byte[] dataBytes; - private final byte[] errorCorrectionBytes; - - BlockPair(byte[] data, byte[] errorCorrection) { - dataBytes = data; - errorCorrectionBytes = errorCorrection; - } - - public byte[] getDataBytes() { - return dataBytes; - } - - public byte[] getErrorCorrectionBytes() { - return errorCorrectionBytes; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/ByteMatrix.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/ByteMatrix.java deleted file mode 100644 index eb248a26c..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/ByteMatrix.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing.qrcode.encoder; - -/** - * A class which wraps a 2D array of bytes. The default usage is signed. If you want to use it as a - * unsigned container, it's up to you to do byteValue & 0xff at each location. - * - * JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned - * -1, 0, and 1, I'm going to use less memory and go with bytes. - * - * @author dswitkin@google.com (Daniel Switkin) - */ -public final class ByteMatrix { - - private final byte[][] bytes; - private final int width; - private final int height; - - public ByteMatrix(int width, int height) { - bytes = new byte[height][width]; - this.width = width; - this.height = height; - } - - public int getHeight() { - return height; - } - - public int getWidth() { - return width; - } - - public byte get(int x, int y) { - return bytes[y][x]; - } - - public byte[][] getArray() { - return bytes; - } - - public void set(int x, int y, byte value) { - bytes[y][x] = value; - } - - public void set(int x, int y, int value) { - bytes[y][x] = (byte) value; - } - - public void set(int x, int y, boolean value) { - bytes[y][x] = (byte) (value ? 1 : 0); - } - - public void clear(byte value) { - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - bytes[y][x] = value; - } - } - } - - public String toString() { - StringBuffer result = new StringBuffer(2 * width * height + 2); - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - switch (bytes[y][x]) { - case 0: - result.append(" 0"); - break; - case 1: - result.append(" 1"); - break; - default: - result.append(" "); - break; - } - } - result.append('\n'); - } - return result.toString(); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/Encoder.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/Encoder.java deleted file mode 100644 index 8796511ab..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/Encoder.java +++ /dev/null @@ -1,557 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing.qrcode.encoder; - -import com.google.zxing.EncodeHintType; -import com.google.zxing.WriterException; -import com.google.zxing.common.BitArray; -import com.google.zxing.common.CharacterSetECI; -import com.google.zxing.common.ECI; -import com.google.zxing.common.reedsolomon.GenericGF; -import com.google.zxing.common.reedsolomon.ReedSolomonEncoder; -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -import com.google.zxing.qrcode.decoder.Mode; -import com.google.zxing.qrcode.decoder.Version; - -import java.io.UnsupportedEncodingException; -import java.util.Hashtable; -import java.util.Vector; - -/** - * @author satorux@google.com (Satoru Takabayashi) - creator - * @author dswitkin@google.com (Daniel Switkin) - ported from C++ - */ -public final class Encoder { - - // The original table is defined in the table 5 of JISX0510:2004 (p.19). - private static final int[] ALPHANUMERIC_TABLE = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f - 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f - -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f - }; - - static final String DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1"; - - private Encoder() { - } - - // The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details. - // Basically it applies four rules and summate all penalties. - private static int calculateMaskPenalty(ByteMatrix matrix) { - int penalty = 0; - penalty += MaskUtil.applyMaskPenaltyRule1(matrix); - penalty += MaskUtil.applyMaskPenaltyRule2(matrix); - penalty += MaskUtil.applyMaskPenaltyRule3(matrix); - penalty += MaskUtil.applyMaskPenaltyRule4(matrix); - return penalty; - } - - /** - * Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen - * internally by chooseMode(). On success, store the result in "qrCode". - * - * We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for - * "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very - * strong error correction for this purpose. - * - * Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode() - * with which clients can specify the encoding mode. For now, we don't need the functionality. - */ - public static void encode(String content, ErrorCorrectionLevel ecLevel, QRCode qrCode) - throws WriterException { - encode(content, ecLevel, null, qrCode); - } - - public static void encode(String content, ErrorCorrectionLevel ecLevel, Hashtable hints, - QRCode qrCode) throws WriterException { - - String encoding = hints == null ? null : (String) hints.get(EncodeHintType.CHARACTER_SET); - if (encoding == null) { - encoding = DEFAULT_BYTE_MODE_ENCODING; - } - - // Step 1: Choose the mode (encoding). - Mode mode = chooseMode(content, encoding); - - // Step 2: Append "bytes" into "dataBits" in appropriate encoding. - BitArray dataBits = new BitArray(); - appendBytes(content, mode, dataBits, encoding); - // Step 3: Initialize QR code that can contain "dataBits". - int numInputBytes = dataBits.getSizeInBytes(); - initQRCode(numInputBytes, ecLevel, mode, qrCode); - - // Step 4: Build another bit vector that contains header and data. - BitArray headerAndDataBits = new BitArray(); - - // Step 4.5: Append ECI message if applicable - if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.equals(encoding)) { - CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); - if (eci != null) { - appendECI(eci, headerAndDataBits); - } - } - - appendModeInfo(mode, headerAndDataBits); - - int numLetters = mode.equals(Mode.BYTE) ? dataBits.getSizeInBytes() : content.length(); - appendLengthInfo(numLetters, qrCode.getVersion(), mode, headerAndDataBits); - headerAndDataBits.appendBitArray(dataBits); - - // Step 5: Terminate the bits properly. - terminateBits(qrCode.getNumDataBytes(), headerAndDataBits); - - // Step 6: Interleave data bits with error correction code. - BitArray finalBits = new BitArray(); - interleaveWithECBytes(headerAndDataBits, qrCode.getNumTotalBytes(), qrCode.getNumDataBytes(), - qrCode.getNumRSBlocks(), finalBits); - - // Step 7: Choose the mask pattern and set to "qrCode". - ByteMatrix matrix = new ByteMatrix(qrCode.getMatrixWidth(), qrCode.getMatrixWidth()); - qrCode.setMaskPattern(chooseMaskPattern(finalBits, qrCode.getECLevel(), qrCode.getVersion(), - matrix)); - - // Step 8. Build the matrix and set it to "qrCode". - MatrixUtil.buildMatrix(finalBits, qrCode.getECLevel(), qrCode.getVersion(), - qrCode.getMaskPattern(), matrix); - qrCode.setMatrix(matrix); - // Step 9. Make sure we have a valid QR Code. - if (!qrCode.isValid()) { - throw new WriterException("Invalid QR code: " + qrCode.toString()); - } - } - - /** - * @return the code point of the table used in alphanumeric mode or - * -1 if there is no corresponding code in the table. - */ - static int getAlphanumericCode(int code) { - if (code < ALPHANUMERIC_TABLE.length) { - return ALPHANUMERIC_TABLE[code]; - } - return -1; - } - - public static Mode chooseMode(String content) { - return chooseMode(content, null); - } - - /** - * Choose the best mode by examining the content. Note that 'encoding' is used as a hint; - * if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}. - */ - public static Mode chooseMode(String content, String encoding) { - if ("Shift_JIS".equals(encoding)) { - // Choose Kanji mode if all input are double-byte characters - return isOnlyDoubleByteKanji(content) ? Mode.KANJI : Mode.BYTE; - } - boolean hasNumeric = false; - boolean hasAlphanumeric = false; - for (int i = 0; i < content.length(); ++i) { - char c = content.charAt(i); - if (c >= '0' && c <= '9') { - hasNumeric = true; - } else if (getAlphanumericCode(c) != -1) { - hasAlphanumeric = true; - } else { - return Mode.BYTE; - } - } - if (hasAlphanumeric) { - return Mode.ALPHANUMERIC; - } else if (hasNumeric) { - return Mode.NUMERIC; - } - return Mode.BYTE; - } - - private static boolean isOnlyDoubleByteKanji(String content) { - byte[] bytes; - try { - bytes = content.getBytes("Shift_JIS"); - } catch (UnsupportedEncodingException uee) { - return false; - } - int length = bytes.length; - if (length % 2 != 0) { - return false; - } - for (int i = 0; i < length; i += 2) { - int byte1 = bytes[i] & 0xFF; - if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB)) { - return false; - } - } - return true; - } - - private static int chooseMaskPattern(BitArray bits, ErrorCorrectionLevel ecLevel, int version, - ByteMatrix matrix) throws WriterException { - - int minPenalty = Integer.MAX_VALUE; // Lower penalty is better. - int bestMaskPattern = -1; - // We try all mask patterns to choose the best one. - for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) { - MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix); - int penalty = calculateMaskPenalty(matrix); - if (penalty < minPenalty) { - minPenalty = penalty; - bestMaskPattern = maskPattern; - } - } - return bestMaskPattern; - } - - /** - * Initialize "qrCode" according to "numInputBytes", "ecLevel", and "mode". On success, - * modify "qrCode". - */ - private static void initQRCode(int numInputBytes, ErrorCorrectionLevel ecLevel, Mode mode, - QRCode qrCode) throws WriterException { - qrCode.setECLevel(ecLevel); - qrCode.setMode(mode); - - // In the following comments, we use numbers of Version 7-H. - for (int versionNum = 1; versionNum <= 40; versionNum++) { - Version version = Version.getVersionForNumber(versionNum); - // numBytes = 196 - int numBytes = version.getTotalCodewords(); - // getNumECBytes = 130 - Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); - int numEcBytes = ecBlocks.getTotalECCodewords(); - // getNumRSBlocks = 5 - int numRSBlocks = ecBlocks.getNumBlocks(); - // getNumDataBytes = 196 - 130 = 66 - int numDataBytes = numBytes - numEcBytes; - // We want to choose the smallest version which can contain data of "numInputBytes" + some - // extra bits for the header (mode info and length info). The header can be three bytes - // (precisely 4 + 16 bits) at most. Hence we do +3 here. - if (numDataBytes >= numInputBytes + 3) { - // Yay, we found the proper rs block info! - qrCode.setVersion(versionNum); - qrCode.setNumTotalBytes(numBytes); - qrCode.setNumDataBytes(numDataBytes); - qrCode.setNumRSBlocks(numRSBlocks); - // getNumECBytes = 196 - 66 = 130 - qrCode.setNumECBytes(numEcBytes); - // matrix width = 21 + 6 * 4 = 45 - qrCode.setMatrixWidth(version.getDimensionForVersion()); - return; - } - } - throw new WriterException("Cannot find proper rs block info (input data too big?)"); - } - - /** - * Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24). - */ - static void terminateBits(int numDataBytes, BitArray bits) throws WriterException { - int capacity = numDataBytes << 3; - if (bits.getSize() > capacity) { - throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " + - capacity); - } - for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) { - bits.appendBit(false); - } - // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details. - // If the last byte isn't 8-bit aligned, we'll add padding bits. - int numBitsInLastByte = bits.getSize() & 0x07; - if (numBitsInLastByte > 0) { - for (int i = numBitsInLastByte; i < 8; i++) { - bits.appendBit(false); - } - } - // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24). - int numPaddingBytes = numDataBytes - bits.getSizeInBytes(); - for (int i = 0; i < numPaddingBytes; ++i) { - bits.appendBits((i & 0x01) == 0 ? 0xEC : 0x11, 8); - } - if (bits.getSize() != capacity) { - throw new WriterException("Bits size does not equal capacity"); - } - } - - /** - * Get number of data bytes and number of error correction bytes for block id "blockID". Store - * the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of - * JISX0510:2004 (p.30) - */ - static void getNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes, - int numRSBlocks, int blockID, int[] numDataBytesInBlock, - int[] numECBytesInBlock) throws WriterException { - if (blockID >= numRSBlocks) { - throw new WriterException("Block ID too large"); - } - // numRsBlocksInGroup2 = 196 % 5 = 1 - int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks; - // numRsBlocksInGroup1 = 5 - 1 = 4 - int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2; - // numTotalBytesInGroup1 = 196 / 5 = 39 - int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks; - // numTotalBytesInGroup2 = 39 + 1 = 40 - int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1; - // numDataBytesInGroup1 = 66 / 5 = 13 - int numDataBytesInGroup1 = numDataBytes / numRSBlocks; - // numDataBytesInGroup2 = 13 + 1 = 14 - int numDataBytesInGroup2 = numDataBytesInGroup1 + 1; - // numEcBytesInGroup1 = 39 - 13 = 26 - int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1; - // numEcBytesInGroup2 = 40 - 14 = 26 - int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2; - // Sanity checks. - // 26 = 26 - if (numEcBytesInGroup1 != numEcBytesInGroup2) { - throw new WriterException("EC bytes mismatch"); - } - // 5 = 4 + 1. - if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) { - throw new WriterException("RS blocks mismatch"); - } - // 196 = (13 + 26) * 4 + (14 + 26) * 1 - if (numTotalBytes != - ((numDataBytesInGroup1 + numEcBytesInGroup1) * - numRsBlocksInGroup1) + - ((numDataBytesInGroup2 + numEcBytesInGroup2) * - numRsBlocksInGroup2)) { - throw new WriterException("Total bytes mismatch"); - } - - if (blockID < numRsBlocksInGroup1) { - numDataBytesInBlock[0] = numDataBytesInGroup1; - numECBytesInBlock[0] = numEcBytesInGroup1; - } else { - numDataBytesInBlock[0] = numDataBytesInGroup2; - numECBytesInBlock[0] = numEcBytesInGroup2; - } - } - - /** - * Interleave "bits" with corresponding error correction bytes. On success, store the result in - * "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details. - */ - static void interleaveWithECBytes(BitArray bits, int numTotalBytes, - int numDataBytes, int numRSBlocks, BitArray result) throws WriterException { - - // "bits" must have "getNumDataBytes" bytes of data. - if (bits.getSizeInBytes() != numDataBytes) { - throw new WriterException("Number of bits and data bytes does not match"); - } - - // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll - // store the divided data bytes blocks and error correction bytes blocks into "blocks". - int dataBytesOffset = 0; - int maxNumDataBytes = 0; - int maxNumEcBytes = 0; - - // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number. - Vector blocks = new Vector(numRSBlocks); - - for (int i = 0; i < numRSBlocks; ++i) { - int[] numDataBytesInBlock = new int[1]; - int[] numEcBytesInBlock = new int[1]; - getNumDataBytesAndNumECBytesForBlockID( - numTotalBytes, numDataBytes, numRSBlocks, i, - numDataBytesInBlock, numEcBytesInBlock); - - int size = numDataBytesInBlock[0]; - byte[] dataBytes = new byte[size]; - bits.toBytes(8*dataBytesOffset, dataBytes, 0, size); - byte[] ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]); - blocks.addElement(new BlockPair(dataBytes, ecBytes)); - - maxNumDataBytes = Math.max(maxNumDataBytes, size); - maxNumEcBytes = Math.max(maxNumEcBytes, ecBytes.length); - dataBytesOffset += numDataBytesInBlock[0]; - } - if (numDataBytes != dataBytesOffset) { - throw new WriterException("Data bytes does not match offset"); - } - - // First, place data blocks. - for (int i = 0; i < maxNumDataBytes; ++i) { - for (int j = 0; j < blocks.size(); ++j) { - byte[] dataBytes = ((BlockPair) blocks.elementAt(j)).getDataBytes(); - if (i < dataBytes.length) { - result.appendBits(dataBytes[i], 8); - } - } - } - // Then, place error correction blocks. - for (int i = 0; i < maxNumEcBytes; ++i) { - for (int j = 0; j < blocks.size(); ++j) { - byte[] ecBytes = ((BlockPair) blocks.elementAt(j)).getErrorCorrectionBytes(); - if (i < ecBytes.length) { - result.appendBits(ecBytes[i], 8); - } - } - } - if (numTotalBytes != result.getSizeInBytes()) { // Should be same. - throw new WriterException("Interleaving error: " + numTotalBytes + " and " + - result.getSizeInBytes() + " differ."); - } - } - - static byte[] generateECBytes(byte[] dataBytes, int numEcBytesInBlock) { - int numDataBytes = dataBytes.length; - int[] toEncode = new int[numDataBytes + numEcBytesInBlock]; - for (int i = 0; i < numDataBytes; i++) { - toEncode[i] = dataBytes[i] & 0xFF; - } - new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256).encode(toEncode, numEcBytesInBlock); - - byte[] ecBytes = new byte[numEcBytesInBlock]; - for (int i = 0; i < numEcBytesInBlock; i++) { - ecBytes[i] = (byte) toEncode[numDataBytes + i]; - } - return ecBytes; - } - - /** - * Append mode info. On success, store the result in "bits". - */ - static void appendModeInfo(Mode mode, BitArray bits) { - bits.appendBits(mode.getBits(), 4); - } - - - /** - * Append length info. On success, store the result in "bits". - */ - static void appendLengthInfo(int numLetters, int version, Mode mode, BitArray bits) - throws WriterException { - int numBits = mode.getCharacterCountBits(Version.getVersionForNumber(version)); - if (numLetters > ((1 << numBits) - 1)) { - throw new WriterException(numLetters + "is bigger than" + ((1 << numBits) - 1)); - } - bits.appendBits(numLetters, numBits); - } - - /** - * Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits". - */ - static void appendBytes(String content, Mode mode, BitArray bits, String encoding) - throws WriterException { - if (mode.equals(Mode.NUMERIC)) { - appendNumericBytes(content, bits); - } else if (mode.equals(Mode.ALPHANUMERIC)) { - appendAlphanumericBytes(content, bits); - } else if (mode.equals(Mode.BYTE)) { - append8BitBytes(content, bits, encoding); - } else if (mode.equals(Mode.KANJI)) { - appendKanjiBytes(content, bits); - } else { - throw new WriterException("Invalid mode: " + mode); - } - } - - static void appendNumericBytes(String content, BitArray bits) { - int length = content.length(); - int i = 0; - while (i < length) { - int num1 = content.charAt(i) - '0'; - if (i + 2 < length) { - // Encode three numeric letters in ten bits. - int num2 = content.charAt(i + 1) - '0'; - int num3 = content.charAt(i + 2) - '0'; - bits.appendBits(num1 * 100 + num2 * 10 + num3, 10); - i += 3; - } else if (i + 1 < length) { - // Encode two numeric letters in seven bits. - int num2 = content.charAt(i + 1) - '0'; - bits.appendBits(num1 * 10 + num2, 7); - i += 2; - } else { - // Encode one numeric letter in four bits. - bits.appendBits(num1, 4); - i++; - } - } - } - - static void appendAlphanumericBytes(String content, BitArray bits) throws WriterException { - int length = content.length(); - int i = 0; - while (i < length) { - int code1 = getAlphanumericCode(content.charAt(i)); - if (code1 == -1) { - throw new WriterException(); - } - if (i + 1 < length) { - int code2 = getAlphanumericCode(content.charAt(i + 1)); - if (code2 == -1) { - throw new WriterException(); - } - // Encode two alphanumeric letters in 11 bits. - bits.appendBits(code1 * 45 + code2, 11); - i += 2; - } else { - // Encode one alphanumeric letter in six bits. - bits.appendBits(code1, 6); - i++; - } - } - } - - static void append8BitBytes(String content, BitArray bits, String encoding) - throws WriterException { - byte[] bytes; - try { - bytes = content.getBytes(encoding); - } catch (UnsupportedEncodingException uee) { - throw new WriterException(uee.toString()); - } - for (int i = 0; i < bytes.length; ++i) { - bits.appendBits(bytes[i], 8); - } - } - - static void appendKanjiBytes(String content, BitArray bits) throws WriterException { - byte[] bytes; - try { - bytes = content.getBytes("Shift_JIS"); - } catch (UnsupportedEncodingException uee) { - throw new WriterException(uee.toString()); - } - int length = bytes.length; - for (int i = 0; i < length; i += 2) { - int byte1 = bytes[i] & 0xFF; - int byte2 = bytes[i + 1] & 0xFF; - int code = (byte1 << 8) | byte2; - int subtracted = -1; - if (code >= 0x8140 && code <= 0x9ffc) { - subtracted = code - 0x8140; - } else if (code >= 0xe040 && code <= 0xebbf) { - subtracted = code - 0xc140; - } - if (subtracted == -1) { - throw new WriterException("Invalid byte sequence"); - } - int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff); - bits.appendBits(encoded, 13); - } - } - - private static void appendECI(ECI eci, BitArray bits) { - bits.appendBits(Mode.ECI.getBits(), 4); - // This is correct for values up to 127, which is all we need now. - bits.appendBits(eci.getValue(), 8); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MaskUtil.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MaskUtil.java deleted file mode 100644 index 61ccf48c1..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MaskUtil.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing.qrcode.encoder; - -/** - * @author satorux@google.com (Satoru Takabayashi) - creator - * @author dswitkin@google.com (Daniel Switkin) - ported from C++ - */ -public final class MaskUtil { - - private MaskUtil() { - // do nothing - } - - // Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and - // give penalty to them. Example: 00000 or 11111. - public static int applyMaskPenaltyRule1(ByteMatrix matrix) { - return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false); - } - - // Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give - // penalty to them. - public static int applyMaskPenaltyRule2(ByteMatrix matrix) { - int penalty = 0; - byte[][] array = matrix.getArray(); - int width = matrix.getWidth(); - int height = matrix.getHeight(); - for (int y = 0; y < height - 1; ++y) { - for (int x = 0; x < width - 1; ++x) { - int value = array[y][x]; - if (value == array[y][x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1]) { - penalty += 3; - } - } - } - return penalty; - } - - // Apply mask penalty rule 3 and return the penalty. Find consecutive cells of 00001011101 or - // 10111010000, and give penalty to them. If we find patterns like 000010111010000, we give - // penalties twice (i.e. 40 * 2). - public static int applyMaskPenaltyRule3(ByteMatrix matrix) { - int penalty = 0; - byte[][] array = matrix.getArray(); - int width = matrix.getWidth(); - int height = matrix.getHeight(); - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - // Tried to simplify following conditions but failed. - if (x + 6 < width && - array[y][x] == 1 && - array[y][x + 1] == 0 && - array[y][x + 2] == 1 && - array[y][x + 3] == 1 && - array[y][x + 4] == 1 && - array[y][x + 5] == 0 && - array[y][x + 6] == 1 && - ((x + 10 < width && - array[y][x + 7] == 0 && - array[y][x + 8] == 0 && - array[y][x + 9] == 0 && - array[y][x + 10] == 0) || - (x - 4 >= 0 && - array[y][x - 1] == 0 && - array[y][x - 2] == 0 && - array[y][x - 3] == 0 && - array[y][x - 4] == 0))) { - penalty += 40; - } - if (y + 6 < height && - array[y][x] == 1 && - array[y + 1][x] == 0 && - array[y + 2][x] == 1 && - array[y + 3][x] == 1 && - array[y + 4][x] == 1 && - array[y + 5][x] == 0 && - array[y + 6][x] == 1 && - ((y + 10 < height && - array[y + 7][x] == 0 && - array[y + 8][x] == 0 && - array[y + 9][x] == 0 && - array[y + 10][x] == 0) || - (y - 4 >= 0 && - array[y - 1][x] == 0 && - array[y - 2][x] == 0 && - array[y - 3][x] == 0 && - array[y - 4][x] == 0))) { - penalty += 40; - } - } - } - return penalty; - } - - // Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give - // penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. Examples: - // - 0% => 100 - // - 40% => 20 - // - 45% => 10 - // - 50% => 0 - // - 55% => 10 - // - 55% => 20 - // - 100% => 100 - public static int applyMaskPenaltyRule4(ByteMatrix matrix) { - int numDarkCells = 0; - byte[][] array = matrix.getArray(); - int width = matrix.getWidth(); - int height = matrix.getHeight(); - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - if (array[y][x] == 1) { - numDarkCells += 1; - } - } - } - int numTotalCells = matrix.getHeight() * matrix.getWidth(); - double darkRatio = (double) numDarkCells / numTotalCells; - return Math.abs((int) (darkRatio * 100 - 50)) / 5 * 10; - } - - // Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask - // pattern conditions. - public static boolean getDataMaskBit(int maskPattern, int x, int y) { - if (!QRCode.isValidMaskPattern(maskPattern)) { - throw new IllegalArgumentException("Invalid mask pattern"); - } - int intermediate; - int temp; - switch (maskPattern) { - case 0: - intermediate = (y + x) & 0x1; - break; - case 1: - intermediate = y & 0x1; - break; - case 2: - intermediate = x % 3; - break; - case 3: - intermediate = (y + x) % 3; - break; - case 4: - intermediate = ((y >>> 1) + (x / 3)) & 0x1; - break; - case 5: - temp = y * x; - intermediate = (temp & 0x1) + (temp % 3); - break; - case 6: - temp = y * x; - intermediate = ((temp & 0x1) + (temp % 3)) & 0x1; - break; - case 7: - temp = y * x; - intermediate = ((temp % 3) + ((y + x) & 0x1)) & 0x1; - break; - default: - throw new IllegalArgumentException("Invalid mask pattern: " + maskPattern); - } - return intermediate == 0; - } - - // Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both - // vertical and horizontal orders respectively. - private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, boolean isHorizontal) { - int penalty = 0; - int numSameBitCells = 0; - int prevBit = -1; - // Horizontal mode: - // for (int i = 0; i < matrix.height(); ++i) { - // for (int j = 0; j < matrix.width(); ++j) { - // int bit = matrix.get(i, j); - // Vertical mode: - // for (int i = 0; i < matrix.width(); ++i) { - // for (int j = 0; j < matrix.height(); ++j) { - // int bit = matrix.get(j, i); - int iLimit = isHorizontal ? matrix.getHeight() : matrix.getWidth(); - int jLimit = isHorizontal ? matrix.getWidth() : matrix.getHeight(); - byte[][] array = matrix.getArray(); - for (int i = 0; i < iLimit; ++i) { - for (int j = 0; j < jLimit; ++j) { - int bit = isHorizontal ? array[i][j] : array[j][i]; - if (bit == prevBit) { - numSameBitCells += 1; - // Found five repetitive cells with the same color (bit). - // We'll give penalty of 3. - if (numSameBitCells == 5) { - penalty += 3; - } else if (numSameBitCells > 5) { - // After five repetitive cells, we'll add the penalty one - // by one. - penalty += 1; - } - } else { - numSameBitCells = 1; // Include the cell itself. - prevBit = bit; - } - } - numSameBitCells = 0; // Clear at each row/column. - } - return penalty; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MatrixUtil.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MatrixUtil.java deleted file mode 100644 index 3d434e675..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MatrixUtil.java +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing.qrcode.encoder; - -import com.google.zxing.WriterException; -import com.google.zxing.common.BitArray; -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; - -/** - * @author satorux@google.com (Satoru Takabayashi) - creator - * @author dswitkin@google.com (Daniel Switkin) - ported from C++ - */ -public final class MatrixUtil { - - private MatrixUtil() { - // do nothing - } - - private static final int[][] POSITION_DETECTION_PATTERN = { - {1, 1, 1, 1, 1, 1, 1}, - {1, 0, 0, 0, 0, 0, 1}, - {1, 0, 1, 1, 1, 0, 1}, - {1, 0, 1, 1, 1, 0, 1}, - {1, 0, 1, 1, 1, 0, 1}, - {1, 0, 0, 0, 0, 0, 1}, - {1, 1, 1, 1, 1, 1, 1}, - }; - - private static final int[][] HORIZONTAL_SEPARATION_PATTERN = { - {0, 0, 0, 0, 0, 0, 0, 0}, - }; - - private static final int[][] VERTICAL_SEPARATION_PATTERN = { - {0}, {0}, {0}, {0}, {0}, {0}, {0}, - }; - - private static final int[][] POSITION_ADJUSTMENT_PATTERN = { - {1, 1, 1, 1, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 1, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 1, 1, 1, 1}, - }; - - // From Appendix E. Table 1, JIS0510X:2004 (p 71). The table was double-checked by komatsu. - private static final int[][] POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE = { - {-1, -1, -1, -1, -1, -1, -1}, // Version 1 - { 6, 18, -1, -1, -1, -1, -1}, // Version 2 - { 6, 22, -1, -1, -1, -1, -1}, // Version 3 - { 6, 26, -1, -1, -1, -1, -1}, // Version 4 - { 6, 30, -1, -1, -1, -1, -1}, // Version 5 - { 6, 34, -1, -1, -1, -1, -1}, // Version 6 - { 6, 22, 38, -1, -1, -1, -1}, // Version 7 - { 6, 24, 42, -1, -1, -1, -1}, // Version 8 - { 6, 26, 46, -1, -1, -1, -1}, // Version 9 - { 6, 28, 50, -1, -1, -1, -1}, // Version 10 - { 6, 30, 54, -1, -1, -1, -1}, // Version 11 - { 6, 32, 58, -1, -1, -1, -1}, // Version 12 - { 6, 34, 62, -1, -1, -1, -1}, // Version 13 - { 6, 26, 46, 66, -1, -1, -1}, // Version 14 - { 6, 26, 48, 70, -1, -1, -1}, // Version 15 - { 6, 26, 50, 74, -1, -1, -1}, // Version 16 - { 6, 30, 54, 78, -1, -1, -1}, // Version 17 - { 6, 30, 56, 82, -1, -1, -1}, // Version 18 - { 6, 30, 58, 86, -1, -1, -1}, // Version 19 - { 6, 34, 62, 90, -1, -1, -1}, // Version 20 - { 6, 28, 50, 72, 94, -1, -1}, // Version 21 - { 6, 26, 50, 74, 98, -1, -1}, // Version 22 - { 6, 30, 54, 78, 102, -1, -1}, // Version 23 - { 6, 28, 54, 80, 106, -1, -1}, // Version 24 - { 6, 32, 58, 84, 110, -1, -1}, // Version 25 - { 6, 30, 58, 86, 114, -1, -1}, // Version 26 - { 6, 34, 62, 90, 118, -1, -1}, // Version 27 - { 6, 26, 50, 74, 98, 122, -1}, // Version 28 - { 6, 30, 54, 78, 102, 126, -1}, // Version 29 - { 6, 26, 52, 78, 104, 130, -1}, // Version 30 - { 6, 30, 56, 82, 108, 134, -1}, // Version 31 - { 6, 34, 60, 86, 112, 138, -1}, // Version 32 - { 6, 30, 58, 86, 114, 142, -1}, // Version 33 - { 6, 34, 62, 90, 118, 146, -1}, // Version 34 - { 6, 30, 54, 78, 102, 126, 150}, // Version 35 - { 6, 24, 50, 76, 102, 128, 154}, // Version 36 - { 6, 28, 54, 80, 106, 132, 158}, // Version 37 - { 6, 32, 58, 84, 110, 136, 162}, // Version 38 - { 6, 26, 54, 82, 110, 138, 166}, // Version 39 - { 6, 30, 58, 86, 114, 142, 170}, // Version 40 - }; - - // Type info cells at the left top corner. - private static final int[][] TYPE_INFO_COORDINATES = { - {8, 0}, - {8, 1}, - {8, 2}, - {8, 3}, - {8, 4}, - {8, 5}, - {8, 7}, - {8, 8}, - {7, 8}, - {5, 8}, - {4, 8}, - {3, 8}, - {2, 8}, - {1, 8}, - {0, 8}, - }; - - // From Appendix D in JISX0510:2004 (p. 67) - private static final int VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101 - - // From Appendix C in JISX0510:2004 (p.65). - private static final int TYPE_INFO_POLY = 0x537; - private static final int TYPE_INFO_MASK_PATTERN = 0x5412; - - // Set all cells to -1. -1 means that the cell is empty (not set yet). - // - // JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding - // with the ByteMatrix initialized all to zero. - public static void clearMatrix(ByteMatrix matrix) { - matrix.clear((byte) -1); - } - - // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On - // success, store the result in "matrix" and return true. - public static void buildMatrix(BitArray dataBits, ErrorCorrectionLevel ecLevel, int version, - int maskPattern, ByteMatrix matrix) throws WriterException { - clearMatrix(matrix); - embedBasicPatterns(version, matrix); - // Type information appear with any version. - embedTypeInfo(ecLevel, maskPattern, matrix); - // Version info appear if version >= 7. - maybeEmbedVersionInfo(version, matrix); - // Data should be embedded at end. - embedDataBits(dataBits, maskPattern, matrix); - } - - // Embed basic patterns. On success, modify the matrix and return true. - // The basic patterns are: - // - Position detection patterns - // - Timing patterns - // - Dark dot at the left bottom corner - // - Position adjustment patterns, if need be - public static void embedBasicPatterns(int version, ByteMatrix matrix) throws WriterException { - // Let's get started with embedding big squares at corners. - embedPositionDetectionPatternsAndSeparators(matrix); - // Then, embed the dark dot at the left bottom corner. - embedDarkDotAtLeftBottomCorner(matrix); - - // Position adjustment patterns appear if version >= 2. - maybeEmbedPositionAdjustmentPatterns(version, matrix); - // Timing patterns should be embedded after position adj. patterns. - embedTimingPatterns(matrix); - } - - // Embed type information. On success, modify the matrix. - public static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix) - throws WriterException { - BitArray typeInfoBits = new BitArray(); - makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits); - - for (int i = 0; i < typeInfoBits.getSize(); ++i) { - // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in - // "typeInfoBits". - boolean bit = typeInfoBits.get(typeInfoBits.getSize() - 1 - i); - - // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46). - int x1 = TYPE_INFO_COORDINATES[i][0]; - int y1 = TYPE_INFO_COORDINATES[i][1]; - matrix.set(x1, y1, bit); - - if (i < 8) { - // Right top corner. - int x2 = matrix.getWidth() - i - 1; - int y2 = 8; - matrix.set(x2, y2, bit); - } else { - // Left bottom corner. - int x2 = 8; - int y2 = matrix.getHeight() - 7 + (i - 8); - matrix.set(x2, y2, bit); - } - } - } - - // Embed version information if need be. On success, modify the matrix and return true. - // See 8.10 of JISX0510:2004 (p.47) for how to embed version information. - public static void maybeEmbedVersionInfo(int version, ByteMatrix matrix) throws WriterException { - if (version < 7) { // Version info is necessary if version >= 7. - return; // Don't need version info. - } - BitArray versionInfoBits = new BitArray(); - makeVersionInfoBits(version, versionInfoBits); - - int bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0. - for (int i = 0; i < 6; ++i) { - for (int j = 0; j < 3; ++j) { - // Place bits in LSB (least significant bit) to MSB order. - boolean bit = versionInfoBits.get(bitIndex); - bitIndex--; - // Left bottom corner. - matrix.set(i, matrix.getHeight() - 11 + j, bit); - // Right bottom corner. - matrix.set(matrix.getHeight() - 11 + j, i, bit); - } - } - } - - // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true. - // For debugging purposes, it skips masking process if "getMaskPattern" is -1. - // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits. - public static void embedDataBits(BitArray dataBits, int maskPattern, ByteMatrix matrix) - throws WriterException { - int bitIndex = 0; - int direction = -1; - // Start from the right bottom cell. - int x = matrix.getWidth() - 1; - int y = matrix.getHeight() - 1; - while (x > 0) { - // Skip the vertical timing pattern. - if (x == 6) { - x -= 1; - } - while (y >= 0 && y < matrix.getHeight()) { - for (int i = 0; i < 2; ++i) { - int xx = x - i; - // Skip the cell if it's not empty. - if (!isEmpty(matrix.get(xx, y))) { - continue; - } - boolean bit; - if (bitIndex < dataBits.getSize()) { - bit = dataBits.get(bitIndex); - ++bitIndex; - } else { - // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described - // in 8.4.9 of JISX0510:2004 (p. 24). - bit = false; - } - - // Skip masking if mask_pattern is -1. - if (maskPattern != -1) { - if (MaskUtil.getDataMaskBit(maskPattern, xx, y)) { - bit = !bit; - } - } - matrix.set(xx, y, bit); - } - y += direction; - } - direction = -direction; // Reverse the direction. - y += direction; - x -= 2; // Move to the left. - } - // All bits should be consumed. - if (bitIndex != dataBits.getSize()) { - throw new WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.getSize()); - } - } - - // Return the position of the most significant bit set (to one) in the "value". The most - // significant bit is position 32. If there is no bit set, return 0. Examples: - // - findMSBSet(0) => 0 - // - findMSBSet(1) => 1 - // - findMSBSet(255) => 8 - public static int findMSBSet(int value) { - int numDigits = 0; - while (value != 0) { - value >>>= 1; - ++numDigits; - } - return numDigits; - } - - // Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH - // code is used for encoding type information and version information. - // Example: Calculation of version information of 7. - // f(x) is created from 7. - // - 7 = 000111 in 6 bits - // - f(x) = x^2 + x^1 + x^0 - // g(x) is given by the standard (p. 67) - // - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 - // Multiply f(x) by x^(18 - 6) - // - f'(x) = f(x) * x^(18 - 6) - // - f'(x) = x^14 + x^13 + x^12 - // Calculate the remainder of f'(x) / g(x) - // x^2 - // __________________________________________________ - // g(x) )x^14 + x^13 + x^12 - // x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2 - // -------------------------------------------------- - // x^11 + x^10 + x^7 + x^4 + x^2 - // - // The remainder is x^11 + x^10 + x^7 + x^4 + x^2 - // Encode it in binary: 110010010100 - // The return value is 0xc94 (1100 1001 0100) - // - // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit - // operations. We don't care if cofficients are positive or negative. - public static int calculateBCHCode(int value, int poly) { - // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1 - // from 13 to make it 12. - int msbSetInPoly = findMSBSet(poly); - value <<= msbSetInPoly - 1; - // Do the division business using exclusive-or operations. - while (findMSBSet(value) >= msbSetInPoly) { - value ^= poly << (findMSBSet(value) - msbSetInPoly); - } - // Now the "value" is the remainder (i.e. the BCH code) - return value; - } - - // Make bit vector of type information. On success, store the result in "bits" and return true. - // Encode error correction level and mask pattern. See 8.9 of - // JISX0510:2004 (p.45) for details. - public static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitArray bits) - throws WriterException { - if (!QRCode.isValidMaskPattern(maskPattern)) { - throw new WriterException("Invalid mask pattern"); - } - int typeInfo = (ecLevel.getBits() << 3) | maskPattern; - bits.appendBits(typeInfo, 5); - - int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY); - bits.appendBits(bchCode, 10); - - BitArray maskBits = new BitArray(); - maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15); - bits.xor(maskBits); - - if (bits.getSize() != 15) { // Just in case. - throw new WriterException("should not happen but we got: " + bits.getSize()); - } - } - - // Make bit vector of version information. On success, store the result in "bits" and return true. - // See 8.10 of JISX0510:2004 (p.45) for details. - public static void makeVersionInfoBits(int version, BitArray bits) throws WriterException { - bits.appendBits(version, 6); - int bchCode = calculateBCHCode(version, VERSION_INFO_POLY); - bits.appendBits(bchCode, 12); - - if (bits.getSize() != 18) { // Just in case. - throw new WriterException("should not happen but we got: " + bits.getSize()); - } - } - - // Check if "value" is empty. - private static boolean isEmpty(int value) { - return value == -1; - } - - // Check if "value" is valid. - private static boolean isValidValue(int value) { - return value == -1 || // Empty. - value == 0 || // Light (white). - value == 1; // Dark (black). - } - - private static void embedTimingPatterns(ByteMatrix matrix) throws WriterException { - // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical - // separation patterns (size 1). Thus, 8 = 7 + 1. - for (int i = 8; i < matrix.getWidth() - 8; ++i) { - int bit = (i + 1) % 2; - // Horizontal line. - if (!isValidValue(matrix.get(i, 6))) { - throw new WriterException(); - } - if (isEmpty(matrix.get(i, 6))) { - matrix.set(i, 6, bit); - } - // Vertical line. - if (!isValidValue(matrix.get(6, i))) { - throw new WriterException(); - } - if (isEmpty(matrix.get(6, i))) { - matrix.set(6, i, bit); - } - } - } - - // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) - private static void embedDarkDotAtLeftBottomCorner(ByteMatrix matrix) throws WriterException { - if (matrix.get(8, matrix.getHeight() - 8) == 0) { - throw new WriterException(); - } - matrix.set(8, matrix.getHeight() - 8, 1); - } - - private static void embedHorizontalSeparationPattern(int xStart, int yStart, - ByteMatrix matrix) throws WriterException { - // We know the width and height. - if (HORIZONTAL_SEPARATION_PATTERN[0].length != 8 || HORIZONTAL_SEPARATION_PATTERN.length != 1) { - throw new WriterException("Bad horizontal separation pattern"); - } - for (int x = 0; x < 8; ++x) { - if (!isEmpty(matrix.get(xStart + x, yStart))) { - throw new WriterException(); - } - matrix.set(xStart + x, yStart, HORIZONTAL_SEPARATION_PATTERN[0][x]); - } - } - - private static void embedVerticalSeparationPattern(int xStart, int yStart, - ByteMatrix matrix) throws WriterException { - // We know the width and height. - if (VERTICAL_SEPARATION_PATTERN[0].length != 1 || VERTICAL_SEPARATION_PATTERN.length != 7) { - throw new WriterException("Bad vertical separation pattern"); - } - for (int y = 0; y < 7; ++y) { - if (!isEmpty(matrix.get(xStart, yStart + y))) { - throw new WriterException(); - } - matrix.set(xStart, yStart + y, VERTICAL_SEPARATION_PATTERN[y][0]); - } - } - - // Note that we cannot unify the function with embedPositionDetectionPattern() despite they are - // almost identical, since we cannot write a function that takes 2D arrays in different sizes in - // C/C++. We should live with the fact. - private static void embedPositionAdjustmentPattern(int xStart, int yStart, - ByteMatrix matrix) throws WriterException { - // We know the width and height. - if (POSITION_ADJUSTMENT_PATTERN[0].length != 5 || POSITION_ADJUSTMENT_PATTERN.length != 5) { - throw new WriterException("Bad position adjustment"); - } - for (int y = 0; y < 5; ++y) { - for (int x = 0; x < 5; ++x) { - if (!isEmpty(matrix.get(xStart + x, yStart + y))) { - throw new WriterException(); - } - matrix.set(xStart + x, yStart + y, POSITION_ADJUSTMENT_PATTERN[y][x]); - } - } - } - - private static void embedPositionDetectionPattern(int xStart, int yStart, - ByteMatrix matrix) throws WriterException { - // We know the width and height. - if (POSITION_DETECTION_PATTERN[0].length != 7 || POSITION_DETECTION_PATTERN.length != 7) { - throw new WriterException("Bad position detection pattern"); - } - for (int y = 0; y < 7; ++y) { - for (int x = 0; x < 7; ++x) { - if (!isEmpty(matrix.get(xStart + x, yStart + y))) { - throw new WriterException(); - } - matrix.set(xStart + x, yStart + y, POSITION_DETECTION_PATTERN[y][x]); - } - } - } - - // Embed position detection patterns and surrounding vertical/horizontal separators. - private static void embedPositionDetectionPatternsAndSeparators(ByteMatrix matrix) throws WriterException { - // Embed three big squares at corners. - int pdpWidth = POSITION_DETECTION_PATTERN[0].length; - // Left top corner. - embedPositionDetectionPattern(0, 0, matrix); - // Right top corner. - embedPositionDetectionPattern(matrix.getWidth() - pdpWidth, 0, matrix); - // Left bottom corner. - embedPositionDetectionPattern(0, matrix.getWidth() - pdpWidth, matrix); - - // Embed horizontal separation patterns around the squares. - int hspWidth = HORIZONTAL_SEPARATION_PATTERN[0].length; - // Left top corner. - embedHorizontalSeparationPattern(0, hspWidth - 1, matrix); - // Right top corner. - embedHorizontalSeparationPattern(matrix.getWidth() - hspWidth, - hspWidth - 1, matrix); - // Left bottom corner. - embedHorizontalSeparationPattern(0, matrix.getWidth() - hspWidth, matrix); - - // Embed vertical separation patterns around the squares. - int vspSize = VERTICAL_SEPARATION_PATTERN.length; - // Left top corner. - embedVerticalSeparationPattern(vspSize, 0, matrix); - // Right top corner. - embedVerticalSeparationPattern(matrix.getHeight() - vspSize - 1, 0, matrix); - // Left bottom corner. - embedVerticalSeparationPattern(vspSize, matrix.getHeight() - vspSize, - matrix); - } - - // Embed position adjustment patterns if need be. - private static void maybeEmbedPositionAdjustmentPatterns(int version, ByteMatrix matrix) - throws WriterException { - if (version < 2) { // The patterns appear if version >= 2 - return; - } - int index = version - 1; - int[] coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index]; - int numCoordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index].length; - for (int i = 0; i < numCoordinates; ++i) { - for (int j = 0; j < numCoordinates; ++j) { - int y = coordinates[i]; - int x = coordinates[j]; - if (x == -1 || y == -1) { - continue; - } - // If the cell is unset, we embed the position adjustment pattern here. - if (isEmpty(matrix.get(x, y))) { - // -2 is necessary since the x/y coordinates point to the center of the pattern, not the - // left top corner. - embedPositionAdjustmentPattern(x - 2, y - 2, matrix); - } - } - } - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/QRCode.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/QRCode.java deleted file mode 100644 index 05c818513..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/QRCode.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * 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 com.google.zxing.qrcode.encoder; - -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -import com.google.zxing.qrcode.decoder.Mode; - -/** - * @author satorux@google.com (Satoru Takabayashi) - creator - * @author dswitkin@google.com (Daniel Switkin) - ported from C++ - */ -public final class QRCode { - - public static final int NUM_MASK_PATTERNS = 8; - - private Mode mode; - private ErrorCorrectionLevel ecLevel; - private int version; - private int matrixWidth; - private int maskPattern; - private int numTotalBytes; - private int numDataBytes; - private int numECBytes; - private int numRSBlocks; - private ByteMatrix matrix; - - public QRCode() { - mode = null; - ecLevel = null; - version = -1; - matrixWidth = -1; - maskPattern = -1; - numTotalBytes = -1; - numDataBytes = -1; - numECBytes = -1; - numRSBlocks = -1; - matrix = null; - } - - // Mode of the QR Code. - public Mode getMode() { - return mode; - } - - // Error correction level of the QR Code. - public ErrorCorrectionLevel getECLevel() { - return ecLevel; - } - - // Version of the QR Code. The bigger size, the bigger version. - public int getVersion() { - return version; - } - - // ByteMatrix width of the QR Code. - public int getMatrixWidth() { - return matrixWidth; - } - - // Mask pattern of the QR Code. - public int getMaskPattern() { - return maskPattern; - } - - // Number of total bytes in the QR Code. - public int getNumTotalBytes() { - return numTotalBytes; - } - - // Number of data bytes in the QR Code. - public int getNumDataBytes() { - return numDataBytes; - } - - // Number of error correction bytes in the QR Code. - public int getNumECBytes() { - return numECBytes; - } - - // Number of Reedsolomon blocks in the QR Code. - public int getNumRSBlocks() { - return numRSBlocks; - } - - // ByteMatrix data of the QR Code. - public ByteMatrix getMatrix() { - return matrix; - } - - - // Return the value of the module (cell) pointed by "x" and "y" in the matrix of the QR Code. They - // call cells in the matrix "modules". 1 represents a black cell, and 0 represents a white cell. - public int at(int x, int y) { - // The value must be zero or one. - int value = matrix.get(x, y); - if (!(value == 0 || value == 1)) { - // this is really like an assert... not sure what better exception to use? - throw new RuntimeException("Bad value"); - } - return value; - } - - // Checks all the member variables are set properly. Returns true on success. Otherwise, returns - // false. - public boolean isValid() { - return - // First check if all version are not uninitialized. - mode != null && - ecLevel != null && - version != -1 && - matrixWidth != -1 && - maskPattern != -1 && - numTotalBytes != -1 && - numDataBytes != -1 && - numECBytes != -1 && - numRSBlocks != -1 && - // Then check them in other ways.. - isValidMaskPattern(maskPattern) && - numTotalBytes == numDataBytes + numECBytes && - // ByteMatrix stuff. - matrix != null && - matrixWidth == matrix.getWidth() && - // See 7.3.1 of JISX0510:2004 (p.5). - matrix.getWidth() == matrix.getHeight(); // Must be square. - } - - // Return debug String. - public String toString() { - StringBuffer result = new StringBuffer(200); - result.append("<<\n"); - result.append(" mode: "); - result.append(mode); - result.append("\n ecLevel: "); - result.append(ecLevel); - result.append("\n version: "); - result.append(version); - result.append("\n matrixWidth: "); - result.append(matrixWidth); - result.append("\n maskPattern: "); - result.append(maskPattern); - result.append("\n numTotalBytes: "); - result.append(numTotalBytes); - result.append("\n numDataBytes: "); - result.append(numDataBytes); - result.append("\n numECBytes: "); - result.append(numECBytes); - result.append("\n numRSBlocks: "); - result.append(numRSBlocks); - if (matrix == null) { - result.append("\n matrix: null\n"); - } else { - result.append("\n matrix:\n"); - result.append(matrix.toString()); - } - result.append(">>\n"); - return result.toString(); - } - - public void setMode(Mode value) { - mode = value; - } - - public void setECLevel(ErrorCorrectionLevel value) { - ecLevel = value; - } - - public void setVersion(int value) { - version = value; - } - - public void setMatrixWidth(int value) { - matrixWidth = value; - } - - public void setMaskPattern(int value) { - maskPattern = value; - } - - public void setNumTotalBytes(int value) { - numTotalBytes = value; - } - - public void setNumDataBytes(int value) { - numDataBytes = value; - } - - public void setNumECBytes(int value) { - numECBytes = value; - } - - public void setNumRSBlocks(int value) { - numRSBlocks = value; - } - - // This takes ownership of the 2D array. - public void setMatrix(ByteMatrix value) { - matrix = value; - } - - // Check if "mask_pattern" is valid. - public static boolean isValidMaskPattern(int maskPattern) { - return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS; - } - - // Return true if the all values in the matrix are binary numbers. - // - // JAVAPORT: This is going to be super expensive and unnecessary, we should not call this in - // production. I'm leaving it because it may be useful for testing. It should be removed entirely - // if ByteMatrix is changed never to contain a -1. - /* - private static boolean EverythingIsBinary(final ByteMatrix matrix) { - for (int y = 0; y < matrix.height(); ++y) { - for (int x = 0; x < matrix.width(); ++x) { - int value = matrix.get(y, x); - if (!(value == 0 || value == 1)) { - // Found non zero/one value. - return false; - } - } - } - return true; - } - */ - -} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java index 4bffd9f3d..13926d172 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java @@ -90,7 +90,7 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN Intent intent = getIntent(); mDataUri = intent.getData(); if (mDataUri == null) { - Log.e(Constants.TAG, "Intent data missing. Should be Uri of app!"); + Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!"); finish(); return; } else { -- cgit v1.2.3 From 4ea64968afde98fc8df444dbc076549437967a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 6 Jan 2014 22:58:04 +0100 Subject: integrate UnderlineTextView, add zxing info --- .../keychain/ui/widget/UnderlineTextView.java | 69 ++++++++++++++++++++++ .../stickylistheaders/views/UnderlineTextView.java | 50 ---------------- 2 files changed, 69 insertions(+), 50 deletions(-) create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java delete mode 100644 OpenPGP-Keychain/src/se/emilsjolander/stickylistheaders/views/UnderlineTextView.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java new file mode 100644 index 000000000..752d44f89 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java @@ -0,0 +1,69 @@ +/* + * 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); + } +} diff --git a/OpenPGP-Keychain/src/se/emilsjolander/stickylistheaders/views/UnderlineTextView.java b/OpenPGP-Keychain/src/se/emilsjolander/stickylistheaders/views/UnderlineTextView.java deleted file mode 100644 index c202c00b8..000000000 --- a/OpenPGP-Keychain/src/se/emilsjolander/stickylistheaders/views/UnderlineTextView.java +++ /dev/null @@ -1,50 +0,0 @@ -package se.emilsjolander.stickylistheaders.views; - -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; - -/** - * @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 44117fb191763e16a8ca3418522d3d5be6582a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 7 Jan 2014 21:02:31 +0100 Subject: key edit fixes --- .../keychain/provider/ProviderHelper.java | 10 +- .../keychain/ui/EditKeyActivity.java | 157 +++++++++------ .../keychain/ui/KeyActivity.java | 217 +++++++++++++++++++++ .../keychain/ui/KeyListPublicFragment.java | 22 +-- .../keychain/ui/KeyListSecretActivity.java | 12 +- .../keychain/ui/KeyListSecretFragment.java | 31 ++- .../keychain/ui/KeyViewActivity.java | 132 +++++-------- 7 files changed, 392 insertions(+), 189 deletions(-) create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java index b07ac53f8..1683c7c0e 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -493,7 +493,7 @@ public class ProviderHelper { */ public static long getPublicMasterKeyId(Context context, long keyRingRowId) { Uri queryUri = KeyRings.buildPublicKeyRingsUri(String.valueOf(keyRingRowId)); - return getMasterKeyId(context, queryUri, keyRingRowId); + return getMasterKeyId(context, queryUri); } /** @@ -551,7 +551,7 @@ public class ProviderHelper { */ public static long getSecretMasterKeyId(Context context, long keyRingRowId) { Uri queryUri = KeyRings.buildSecretKeyRingsUri(String.valueOf(keyRingRowId)); - return getMasterKeyId(context, queryUri, keyRingRowId); + return getMasterKeyId(context, queryUri); } /** @@ -562,7 +562,7 @@ public class ProviderHelper { * @param keyRingRowId * @return */ - private static long getMasterKeyId(Context context, Uri queryUri, long keyRingRowId) { + public static long getMasterKeyId(Context context, Uri queryUri) { String[] projection = new String[] { KeyRings.MASTER_KEY_ID }; ContentResolver cr = context.getContentResolver(); @@ -592,7 +592,7 @@ public class ProviderHelper { return getKeyRingsAsArmoredString(context, KeyRings.buildSecretKeyRingsUri(), masterKeyIds); } - private static ArrayList getKeyRingsAsArmoredString(Context context, Uri uri, + public static ArrayList getKeyRingsAsArmoredString(Context context, Uri uri, long[] masterKeyIds) { ArrayList output = new ArrayList(); @@ -661,7 +661,7 @@ public class ProviderHelper { return getKeyRingsAsByteArray(context, KeyRings.buildSecretKeyRingsUri(), masterKeyIds); } - private static byte[] getKeyRingsAsByteArray(Context context, Uri uri, long[] masterKeyIds) { + public static byte[] getKeyRingsAsByteArray(Context context, Uri uri, long[] masterKeyIds) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); if (masterKeyIds != null && masterKeyIds.length > 0) { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 4dcaa6d73..c0c81b969 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -34,6 +34,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.PassphraseCacheService; +import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.widget.KeyEditor; @@ -45,6 +46,7 @@ import org.sufficientlysecure.keychain.util.Log; import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -60,9 +62,10 @@ import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.LinearLayout; import android.widget.Toast; -import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; -public class EditKeyActivity extends SherlockFragmentActivity { +public class EditKeyActivity extends KeyActivity { // Actions for internal use only: public static final String ACTION_CREATE_KEY = Constants.INTENT_PREFIX + "CREATE_KEY"; @@ -72,13 +75,14 @@ public class EditKeyActivity extends SherlockFragmentActivity { public static final String EXTRA_USER_IDS = "user_ids"; public static final String EXTRA_NO_PASSPHRASE = "no_passphrase"; public static final String EXTRA_GENERATE_DEFAULT_KEYS = "generate_default_keys"; - public static final String EXTRA_MASTER_KEY_ID = "master_key_id"; - public static final String EXTRA_MASTER_CAN_SIGN = "master_can_sign"; // results when saving key public static final String RESULT_EXTRA_MASTER_KEY_ID = "master_key_id"; public static final String RESULT_EXTRA_USER_ID = "user_id"; + // EDIT + private Uri mDataUri; + private PGPSecretKeyRing mKeyRing = null; private SectionView mUserIdsView; @@ -96,29 +100,10 @@ public class EditKeyActivity extends SherlockFragmentActivity { Vector mKeysUsages; boolean masterCanSign = true; - // will be set to false to build layout later in handler - private boolean mBuildLayout = true; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // Inflate a "Done"/"Cancel" custom action bar - ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_save, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // save - saveClicked(); - } - }, R.string.btn_do_not_save, new View.OnClickListener() { - @Override - public void onClick(View v) { - // cancel - cancelClicked(); - } - }); - mUserIds = new Vector(); mKeys = new Vector(); mKeysUsages = new Vector(); @@ -131,10 +116,6 @@ public class EditKeyActivity extends SherlockFragmentActivity { } else if (ACTION_EDIT_KEY.equals(action)) { handleActionEditKey(intent); } - - if (mBuildLayout) { - buildLayout(); - } } /** @@ -143,6 +124,20 @@ public class EditKeyActivity extends SherlockFragmentActivity { * @param intent */ private void handleActionCreateKey(Intent intent) { + // Inflate a "Done"/"Cancel" custom action bar + ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_save, + new View.OnClickListener() { + @Override + public void onClick(View v) { + saveClicked(); + } + }, R.string.btn_do_not_save, new View.OnClickListener() { + @Override + public void onClick(View v) { + cancelClicked(); + } + }); + Bundle extras = intent.getExtras(); mCurrentPassPhrase = ""; @@ -169,9 +164,6 @@ public class EditKeyActivity extends SherlockFragmentActivity { boolean generateDefaultKeys = extras.getBoolean(EXTRA_GENERATE_DEFAULT_KEYS); if (generateDefaultKeys) { - // build layout in handler after generating keys not directly in onCreate - mBuildLayout = false; - // Send all information needed to service generate keys in other thread Intent serviceIntent = new Intent(this, KeychainIntentService.class); serviceIntent.setAction(KeychainIntentService.ACTION_GENERATE_DEFAULT_RSA_KEYS); @@ -228,12 +220,55 @@ public class EditKeyActivity extends SherlockFragmentActivity { startService(serviceIntent); } } + } else { + buildLayout(); + } + } + + /** + * Handle intent action to edit existing key + * + * @param intent + */ + private void handleActionEditKey(Intent intent) { + // Inflate a "Done"/"Cancel" custom action bar + ActionBarHelper.setDoneView(getSupportActionBar(), R.string.btn_save, + new View.OnClickListener() { + @Override + public void onClick(View v) { + saveClicked(); + } + }); + + mDataUri = intent.getData(); + if (mDataUri == null) { + Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!"); + finish(); + return; + } else { + Log.d(Constants.TAG, "uri: " + mDataUri); + + long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); + + // get master key id using row id + long masterKeyId = ProviderHelper.getSecretMasterKeyId(this, keyRingRowId); + + boolean masterCanSign = ProviderHelper.getSecretMasterKeyCanSign(this, keyRingRowId); + + String passphrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId); + if (passphrase == null) { + showPassphraseDialog(masterKeyId, masterCanSign); + } else { + // PgpMain.setEditPassPhrase(passPhrase); + mCurrentPassPhrase = passphrase; + + finallyEdit(masterKeyId, masterCanSign); + } } } private void showPassphraseDialog(final long masterKeyId, final boolean masterCanSign) { // Message is received after passphrase is cached - final boolean mCanSign = masterCanSign; Handler returnHandler = new Handler() { @Override public void handleMessage(Message message) { @@ -263,37 +298,41 @@ public class EditKeyActivity extends SherlockFragmentActivity { } } - /** - * Handle intent action to edit existing key - * - * @param intent - */ - private void handleActionEditKey(Intent intent) { - Bundle extras = intent.getExtras(); - - if (extras != null) { - if (extras.containsKey(EXTRA_MASTER_CAN_SIGN)) { - masterCanSign = extras.getBoolean(EXTRA_MASTER_CAN_SIGN); - } - if (extras.containsKey(EXTRA_MASTER_KEY_ID)) { - long masterKeyId = extras.getLong(EXTRA_MASTER_KEY_ID); - - // build layout in edit() - mBuildLayout = false; + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + // show menu only on edit + if (mDataUri != null) { + return super.onPrepareOptionsMenu(menu); + } else { + return false; + } + } - String passPhrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId); - if (passPhrase == null) { - showPassphraseDialog(masterKeyId, masterCanSign); - } else { - // PgpMain.setEditPassPhrase(passPhrase); - mCurrentPassPhrase = passPhrase; + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + getSupportMenuInflater().inflate(R.menu.key_edit, menu); + return true; + } - finallyEdit(masterKeyId, masterCanSign); - } - } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_key_edit_cancel: + cancelClicked(); + return true; + case R.id.menu_key_edit_export_file: + showExportKeysDialog(mDataUri, Id.type.secret_key, Constants.path.APP_DIR + + "/secexport.asc"); + return true; + case R.id.menu_key_edit_delete: + deleteKey(mDataUri, Id.type.secret_key); + return true; } + return super.onOptionsItemSelected(item); } + @SuppressWarnings("unchecked") private void finallyEdit(final long masterKeyId, final boolean masterCanSign) { if (masterKeyId != 0) { PGPSecretKey masterKey = null; @@ -316,13 +355,13 @@ public class EditKeyActivity extends SherlockFragmentActivity { } } - buildLayout(); - // TODO: ??? if (mCurrentPassPhrase == null) { mCurrentPassPhrase = ""; } + buildLayout(); + if (mCurrentPassPhrase.equals("")) { // check "no passphrase" checkbox and remove button mNoPassphrase.setChecked(true); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java new file mode 100644 index 000000000..0415087dc --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java @@ -0,0 +1,217 @@ +/* + * 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; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; +import org.sufficientlysecure.keychain.util.Log; + +import android.app.ProgressDialog; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; +import android.widget.Toast; + +import com.actionbarsherlock.app.SherlockFragmentActivity; + +/** + * TODO: get key type by looking at dataUri! + * + */ +public class KeyActivity extends SherlockFragmentActivity { + + protected FileDialogFragment mFileDialog; + protected String mExportFilename; + + protected void deleteKey(Uri dataUri, final int keyType) { + long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment()); + + // Message is received after key is deleted + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { + setResult(RESULT_CANCELED); + finish(); + } + } + }; + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(returnHandler); + + DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, + new long[] { keyRingRowId }, keyType); + + deleteKeyDialog.show(getSupportFragmentManager(), "deleteKeyDialog"); + } + + /** + * Show dialog where to export keys + * + * @param keyRingMasterKeyId + * if -1 export all keys + */ + public void showExportKeysDialog(Uri dataUri, final int keyType, final String exportFilename) { + long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment()); + + // TODO? + final long keyRingMasterKeyId = ProviderHelper.getSecretMasterKeyId(this, keyRingRowId); + mExportFilename = exportFilename; + + // Message is received after file is selected + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == FileDialogFragment.MESSAGE_OKAY) { + Bundle data = message.getData(); + mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME); + + exportKeys(keyRingMasterKeyId, keyType); + } + } + }; + + // Create a new Messenger for the communication back + final Messenger messenger = new Messenger(returnHandler); + + DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { + public void run() { + String title = null; + if (keyRingMasterKeyId != -1) { + // single key export + title = getString(R.string.title_export_key); + } else { + title = getString(R.string.title_export_keys); + } + + String message = null; + if (keyType == Id.type.public_key) { + message = getString(R.string.specify_file_to_export_to); + } else { + message = getString(R.string.specify_file_to_export_secret_keys_to); + } + + mFileDialog = FileDialogFragment.newInstance(messenger, title, message, + exportFilename, null, Id.request.filename); + + mFileDialog.show(getSupportFragmentManager(), "fileDialog"); + } + }); + } + + /** + * Export keys + * + * @param keyRingMasterKeyId + * if -1 export all keys + */ + public void exportKeys(long keyRingMasterKeyId, int keyType) { + Log.d(Constants.TAG, "exportKeys started"); + + // Send all information needed to service to export key in other thread + Intent intent = new Intent(this, KeychainIntentService.class); + + intent.setAction(KeychainIntentService.ACTION_EXPORT_KEYRING); + + // fill values for this action + Bundle data = new Bundle(); + + data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename); + data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, keyType); + + if (keyRingMasterKeyId == -1) { + data.putBoolean(KeychainIntentService.EXPORT_ALL, true); + } else { + data.putLong(KeychainIntentService.EXPORT_KEY_RING_MASTER_KEY_ID, keyRingMasterKeyId); + } + + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Message is received after exporting is done in ApgService + KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(this, + R.string.progress_exporting, ProgressDialog.STYLE_HORIZONTAL) { + public void handleMessage(Message message) { + // handle messages by standard ApgHandler first + super.handleMessage(message); + + if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { + // get returned data bundle + Bundle returnData = message.getData(); + + int exported = returnData.getInt(KeychainIntentService.RESULT_EXPORT); + String toastMessage; + if (exported == 1) { + toastMessage = getString(R.string.key_exported); + } else if (exported > 0) { + toastMessage = getString(R.string.keys_exported, exported); + } else { + toastMessage = getString(R.string.no_keys_exported); + } + Toast.makeText(KeyActivity.this, toastMessage, Toast.LENGTH_SHORT).show(); + + } + }; + }; + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(exportHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // show progress dialog + exportHandler.showProgressDialog(this); + + // start service with intent + startService(intent); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case Id.request.filename: { + if (resultCode == RESULT_OK && data != null) { + try { + String path = data.getData().getPath(); + Log.d(Constants.TAG, "path=" + path); + + // set filename used in export/import dialogs + mFileDialog.setFilename(path); + } catch (NullPointerException e) { + Log.e(Constants.TAG, "Nullpointer while retrieving path!", e); + } + } + return; + } + + default: { + break; + } + } + super.onActivityResult(requestCode, resultCode, data); + } +} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index f0a009482..fde90bb32 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -35,9 +35,6 @@ import android.database.Cursor; import android.net.Uri; import android.os.Build; 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; @@ -122,7 +119,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte Set positions = mAdapter.getCurrentCheckedPosition(); switch (item.getItemId()) { case R.id.delete_entry: - + // get IDs for checked positions as long array long[] ids = new long[positions.size()]; int i = 0; @@ -233,25 +230,10 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte /** * Show dialog to delete key * - * TODO: no messenger needed etc! - * * @param keyRingRowIds */ public void showDeleteKeyDialog(long[] keyRingRowIds) { - // Message is received after key is deleted - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { - // no further actions needed - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - - DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, + DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(null, keyRingRowIds, Id.type.public_key); deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog"); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java index d98b5ab37..c19cdeea5 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java @@ -45,8 +45,8 @@ public class KeyListSecretActivity extends KeyListActivity { super.onCreateOptionsMenu(menu); menu.add(1, Id.menu.option.create, 1, R.string.menu_create_key).setShowAsAction( MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); - menu.add(1, Id.menu.option.createExpert, 2, R.string.menu_create_key_expert).setShowAsAction( - MenuItem.SHOW_AS_ACTION_NEVER); + menu.add(1, Id.menu.option.createExpert, 2, R.string.menu_create_key_expert) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); return true; } @@ -84,12 +84,4 @@ public class KeyListSecretActivity extends KeyListActivity { startActivityForResult(intent, 0); } - void editKey(long masterKeyId, boolean masterCanSign) { - Intent intent = new Intent(this, EditKeyActivity.class); - intent.setAction(EditKeyActivity.ACTION_EDIT_KEY); - intent.putExtra(EditKeyActivity.EXTRA_MASTER_KEY_ID, masterKeyId); - intent.putExtra(EditKeyActivity.EXTRA_MASTER_CAN_SIGN, masterCanSign); - startActivityForResult(intent, 0); - } - } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java index e8a306063..40579a3c2 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java @@ -19,11 +19,12 @@ package org.sufficientlysecure.keychain.ui; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.KeyListSecretAdapter; +import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; @@ -37,7 +38,7 @@ import android.widget.AdapterView.OnItemClickListener; import com.actionbarsherlock.app.SherlockListFragment; public class KeyListSecretFragment extends SherlockListFragment implements - LoaderManager.LoaderCallbacks { + LoaderManager.LoaderCallbacks, OnItemClickListener { private KeyListSecretActivity mKeyListSecretActivity; @@ -52,20 +53,7 @@ public class KeyListSecretFragment extends SherlockListFragment implements mKeyListSecretActivity = (KeyListSecretActivity) getActivity(); - getListView().setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView adapterView, View view, int position, long id) { - // TODO: currently this is EDIT directly, later first show VIEW - - // get master key id using row id - long masterKeyId = ProviderHelper.getSecretMasterKeyId(mKeyListSecretActivity, id); - - boolean masterCanSign = ProviderHelper.getSecretMasterKeyCanSign( - mKeyListSecretActivity, id); - - mKeyListSecretActivity.editKey(masterKeyId, masterCanSign); - } - }); + getListView().setOnItemClickListener(this); // Give some text to display if there is no data. In a real // application this would come from a resource. @@ -124,4 +112,15 @@ public class KeyListSecretFragment extends SherlockListFragment implements // longer using it. mAdapter.swapCursor(null); } + + /** + * On click on item, start key view activity + */ + @Override + public void onItemClick(AdapterView adapterView, View view, int position, long id) { + Intent editIntent = new Intent(mKeyListSecretActivity, EditKeyActivity.class); + editIntent.setData(KeychainContract.KeyRings.buildSecretKeyRingsUri(Long.toString(id))); + editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY); + startActivityForResult(editIntent, 0); + } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java index 13926d172..c32a797be 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java @@ -52,12 +52,11 @@ import android.text.format.DateFormat; import android.widget.TextView; import android.widget.Toast; -import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; @SuppressLint("NewApi") -public class KeyViewActivity extends SherlockFragmentActivity implements CreateNdefMessageCallback, +public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCallback, OnNdefPushCompleteCallback { private Uri mDataUri; @@ -96,7 +95,7 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN } else { Log.d(Constants.TAG, "uri: " + mDataUri); loadData(mDataUri); - initNfc(); + initNfc(mDataUri); } } @@ -111,31 +110,32 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_key_view_update: - updateFromKeyserver(); + updateFromKeyserver(mDataUri); return true; case R.id.menu_key_view_sign: - signKey(); + signKey(mDataUri); return true; case R.id.menu_key_view_export_keyserver: - uploadToKeyserver(); + uploadToKeyserver(mDataUri); return true; case R.id.menu_key_view_export_file: - exportToFile(); + showExportKeysDialog(mDataUri, Id.type.public_key, Constants.path.APP_DIR + + "/pubexport.asc"); return true; case R.id.menu_key_view_share_default: - shareKey(); + shareKey(mDataUri); return true; case R.id.menu_key_view_share_qr_code: - shareKeyQrCode(); + shareKeyQrCode(mDataUri); return true; case R.id.menu_key_view_share_nfc: shareNfc(); return true; case R.id.menu_key_view_share_clipboard: - copyToClipboard(); + copyToClipboard(mDataUri); return true; case R.id.menu_key_view_delete: - deleteKey(); + deleteKey(mDataUri, Id.type.public_key); return true; } @@ -188,24 +188,8 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN return result; } - private void exportToFile() { - // long masterKeyId = ProviderHelper.getPublicMasterKeyId(mKeyListActivity, - // keyRingRowId); - // if (masterKeyId == -1) { - // masterKeyId = ProviderHelper.getSecretMasterKeyId(mKeyListActivity, keyRingRowId); - // } - // - // mKeyListActivity.showExportKeysDialog(masterKeyId); - } - - private void deleteKey() { - long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); - - // mKeyListActivity.showDeleteKeyDialog(keyRingRowId); - } - - private void uploadToKeyserver() { - long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); + private void uploadToKeyserver(Uri dataUri) { + long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment()); Intent uploadIntent = new Intent(this, KeyServerUploadActivity.class); uploadIntent.setAction(KeyServerUploadActivity.ACTION_EXPORT_KEY_TO_SERVER); @@ -213,20 +197,22 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN startActivityForResult(uploadIntent, Id.request.export_to_server); } - private void updateFromKeyserver() { - // TODO: use data uri! - long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); - + private void updateFromKeyserver(Uri dataUri) { long updateKeyId = 0; - PGPPublicKeyRing updateKeyRing = ProviderHelper.getPGPPublicKeyRingByRowId(this, - keyRingRowId); - if (updateKeyRing != null) { - updateKeyId = PgpKeyHelper.getMasterKey(updateKeyRing).getKeyID(); + PGPPublicKeyRing updateRing = (PGPPublicKeyRing) ProviderHelper + .getPGPKeyRing(this, dataUri); + + if (updateRing != null) { + updateKeyId = PgpKeyHelper.getMasterKey(updateRing).getKeyID(); + } + if (updateKeyId == 0) { + Log.e(Constants.TAG, "this shouldn't happen. KeyId == 0!"); + return; } - // if (updateKeyId == 0) { - // // this shouldn't happen - // return true; - // } + + Intent signIntent = new Intent(this, SignKeyActivity.class); + signIntent.putExtra(SignKeyActivity.EXTRA_KEY_ID, updateKeyId); + startActivity(signIntent); Intent queryIntent = new Intent(this, KeyServerQueryActivity.class); queryIntent.setAction(KeyServerQueryActivity.ACTION_LOOK_UP_KEY_ID_AND_RETURN); @@ -234,35 +220,29 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN // TODO: lookup?? startActivityForResult(queryIntent, Id.request.look_up_key_id); - } - private void signKey() { - // TODO: use data uri! - long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); - + private void signKey(Uri dataUri) { long keyId = 0; - PGPPublicKeyRing signKeyRing = ProviderHelper - .getPGPPublicKeyRingByRowId(this, keyRingRowId); - if (signKeyRing != null) { - keyId = PgpKeyHelper.getMasterKey(signKeyRing).getKeyID(); + PGPPublicKeyRing signKey = (PGPPublicKeyRing) ProviderHelper.getPGPKeyRing(this, dataUri); + + if (signKey != null) { + keyId = PgpKeyHelper.getMasterKey(signKey).getKeyID(); + } + if (keyId == 0) { + Log.e(Constants.TAG, "this shouldn't happen. KeyId == 0!"); + return; } - // if (keyId == 0) { - // // this shouldn't happen - // return true; - // } Intent signIntent = new Intent(this, SignKeyActivity.class); signIntent.putExtra(SignKeyActivity.EXTRA_KEY_ID, keyId); startActivity(signIntent); } - private void shareKey() { - // TODO: use data uri! - long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); - long masterKeyId = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); + private void shareKey(Uri dataUri) { // get public keyring as ascii armored string - ArrayList keyringArmored = ProviderHelper.getPublicKeyRingsAsArmoredString(this, + long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); + ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, dataUri, new long[] { masterKeyId }); // let user choose application @@ -273,12 +253,10 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN getResources().getText(R.string.action_share_key_with))); } - private void shareKeyQrCode() { - // TODO: use data uri! - long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); - long masterKeyId = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); + private void shareKeyQrCode(Uri dataUri) { // get public keyring as ascii armored string - ArrayList keyringArmored = ProviderHelper.getPublicKeyRingsAsArmoredString(this, + long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); + ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, dataUri, new long[] { masterKeyId }); ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(keyringArmored @@ -286,38 +264,34 @@ public class KeyViewActivity extends SherlockFragmentActivity implements CreateN dialog.show(getSupportFragmentManager(), "shareQrCodeDialog"); } - private void shareNfc() { - ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); - dialog.show(getSupportFragmentManager(), "shareNfcDialog"); - } - - private void copyToClipboard() { - // TODO: use data uri! - long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); - long masterKeyId = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); + private void copyToClipboard(Uri dataUri) { // get public keyring as ascii armored string - ArrayList keyringArmored = ProviderHelper.getPublicKeyRingsAsArmoredString(this, + long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); + ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, dataUri, new long[] { masterKeyId }); ClipboardReflection.copyToClipboard(this, keyringArmored.get(0)); } + private void shareNfc() { + ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); + dialog.show(getSupportFragmentManager(), "shareNfcDialog"); + } + /** * NFC: Initialize NFC sharing if OS and device supports it */ - private void initNfc() { + private void initNfc(Uri dataUri) { // check if NFC Beam is supported (>= Android 4.1) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { // Check for available NFC Adapter mNfcAdapter = NfcAdapter.getDefaultAdapter(this); if (mNfcAdapter != null) { // init nfc - // TODO: use data uri! - long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment()); - long masterKeyId = ProviderHelper.getPublicMasterKeyId(this, keyRingRowId); // get public keyring as byte array - mSharedKeyringBytes = ProviderHelper.getPublicKeyRingsAsByteArray(this, + long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); + mSharedKeyringBytes = ProviderHelper.getKeyRingsAsByteArray(this, dataUri, new long[] { masterKeyId }); // Register callback to set NDEF message -- cgit v1.2.3 From caf3b02042f94b7b2a9b019b01d45c41bf035140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 7 Jan 2014 22:40:18 +0100 Subject: reorder menus, cleanup code, add experimental tab activity --- .../keychain/ui/EditKeyActivity.java | 16 +- .../keychain/ui/EncryptDecryptActivity.java | 175 ++++++++++++ .../keychain/ui/KeyActivity.java | 32 +-- .../keychain/ui/KeyListActivity.java | 314 --------------------- .../keychain/ui/KeyListPublicActivity.java | 54 ++-- .../keychain/ui/KeyListPublicFragment.java | 8 +- .../keychain/ui/KeyListSecretActivity.java | 42 +-- .../keychain/ui/KeyViewActivity.java | 18 +- 8 files changed, 263 insertions(+), 396 deletions(-) create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptDecryptActivity.java delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListActivity.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index c0c81b969..d141fbe3a 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -325,10 +325,22 @@ public class EditKeyActivity extends KeyActivity { showExportKeysDialog(mDataUri, Id.type.secret_key, Constants.path.APP_DIR + "/secexport.asc"); return true; - case R.id.menu_key_edit_delete: - deleteKey(mDataUri, Id.type.secret_key); + case R.id.menu_key_edit_delete: { + // Message is received after key is deleted + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { + setResult(RESULT_CANCELED); + finish(); + } + } + }; + + deleteKey(mDataUri, Id.type.secret_key, returnHandler); return true; } + } return super.onOptionsItemSelected(item); } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptDecryptActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptDecryptActivity.java new file mode 100644 index 000000000..7f0184381 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptDecryptActivity.java @@ -0,0 +1,175 @@ +package org.sufficientlysecure.keychain.ui; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Log; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.ActionBar.Tab; +import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; + +public class EncryptDecryptActivity extends SherlockFragmentActivity { + private FragmentActivity mActivity; + private ActionBar mActionBar; + private ActionBar.Tab mTab1; + private ActionBar.Tab mTab2; + private ActionBar.Tab mTab3; + + // @Override + // public boolean onCreateOptionsMenu(Menu menu) { + // MenuInflater inflater = getSupportMenuInflater(); + // inflater.inflate(R.menu.lists_activity, menu); + // return true; + // } + + /** + * Menu item to go back home in ActionBar, other menu items are defined in Fragments + */ + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + // app icon in Action Bar clicked; go home + Intent intent = new Intent(mActivity, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + return true; + + // case R.id.menu_import: + // ImportExportHelper.openFileStream(mActivity); + // return true; + // + // case R.id.menu_export: + // ImportExportHelper.exportLists(mActivity); + // return true; + + default: + return super.onOptionsItemSelected(item); + } + } + + /** + * Set up Tabs on create + */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mActivity = this; + + setContentView(R.layout.lists_activity); + + mActionBar = getSupportActionBar(); + mActionBar.setDisplayShowTitleEnabled(true); + mActionBar.setDisplayHomeAsUpEnabled(true); + + mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + + mTab1 = getSupportActionBar().newTab(); + mTab2 = getSupportActionBar().newTab(); + mTab3 = getSupportActionBar().newTab(); + + mTab1.setTabListener(new TabListener(this, "publicList", + KeyListPublicFragment.class)); + mTab2.setTabListener(new TabListener(this, "import", + KeyListPublicFragment.class)); + + setTabTextBasedOnOrientation(getResources().getConfiguration()); + + mActionBar.addTab(mTab1); + mActionBar.addTab(mTab2); + // mActionBar.addTab(mTab3); + } + + private void setTabTextBasedOnOrientation(Configuration config) { + // longer names for landscape mode or tablets + // if (config.orientation == Configuration.ORIENTATION_LANDSCAPE + // || config.screenLayout == Configuration.SCREENLAYOUT_SIZE_XLARGE) { + mTab1.setText(getString(R.string.dashboard_manage_keys)); + mTab2.setText(getString(R.string.dashboard_manage_keys)); + + // } else { + // mTab1.setText(getString(R.string.lists_tab_blacklist_short)); + // mTab2.setText(getString(R.string.lists_tab_whitelist_short)); + // mTab3.setText(getString(R.string.lists_tab_redirection_list_short)); + // } + } + + /** + * Change text on orientation change + */ + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + setTabTextBasedOnOrientation(newConfig); + } + + public static class TabListener implements ActionBar.TabListener { + private Fragment mFragment; + private final Activity mActivity; + private final String mTag; + private final Class mClass; + + /** + * Constructor used each time a new tab is created. + * + * @param activity + * The host Activity, used to instantiate the fragment + * @param tag + * The identifier tag for the fragment + * @param clz + * The fragment's Class, used to instantiate the fragment + */ + public TabListener(Activity activity, String tag, Class clz) { + mActivity = activity; + mTag = tag; + mClass = clz; + } + + @Override + public void onTabReselected(Tab tab, FragmentTransaction ft) { + } + + /** + * Open Fragment based on selected Tab + */ + @Override + public void onTabSelected(Tab tab, FragmentTransaction ignoredFt) { + // bug in compatibility lib: + // http://stackoverflow.com/questions/8645549/null-fragmenttransaction-being-passed-to-tablistener-ontabselected + FragmentManager fragMgr = ((FragmentActivity) mActivity).getSupportFragmentManager(); + FragmentTransaction ft = fragMgr.beginTransaction(); + + mFragment = Fragment.instantiate(mActivity, mClass.getName()); + ft.replace(R.id.lists_tabs_container, mFragment, mTag); + ft.commit(); + } + + @Override + public void onTabUnselected(Tab tab, FragmentTransaction ignoredFt) { + FragmentManager fragMgr = ((FragmentActivity) mActivity).getSupportFragmentManager(); + FragmentTransaction ft = fragMgr.beginTransaction(); + + if (mFragment != null) { + // Remove the fragment + ft.remove(mFragment); + } + + ft.commit(); + } + } + +} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java index 0415087dc..2760df97e 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java @@ -40,6 +40,8 @@ import android.widget.Toast; import com.actionbarsherlock.app.SherlockFragmentActivity; /** + * This implements export key method and delete key method. Used in lists and key view and key edit. + * * TODO: get key type by looking at dataUri! * */ @@ -48,22 +50,11 @@ public class KeyActivity extends SherlockFragmentActivity { protected FileDialogFragment mFileDialog; protected String mExportFilename; - protected void deleteKey(Uri dataUri, final int keyType) { + protected void deleteKey(Uri dataUri, final int keyType, Handler deleteHandler) { long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment()); - // Message is received after key is deleted - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { - setResult(RESULT_CANCELED); - finish(); - } - } - }; - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); + Messenger messenger = new Messenger(deleteHandler); DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, new long[] { keyRingRowId }, keyType); @@ -77,11 +68,8 @@ public class KeyActivity extends SherlockFragmentActivity { * @param keyRingMasterKeyId * if -1 export all keys */ - public void showExportKeysDialog(Uri dataUri, final int keyType, final String exportFilename) { - long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment()); - - // TODO? - final long keyRingMasterKeyId = ProviderHelper.getSecretMasterKeyId(this, keyRingRowId); + public void showExportKeysDialog(final Uri dataUri, final int keyType, + final String exportFilename) { mExportFilename = exportFilename; // Message is received after file is selected @@ -92,6 +80,12 @@ public class KeyActivity extends SherlockFragmentActivity { Bundle data = message.getData(); mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME); + long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment()); + + // TODO? + long keyRingMasterKeyId = ProviderHelper.getSecretMasterKeyId(KeyActivity.this, + keyRingRowId); + exportKeys(keyRingMasterKeyId, keyType); } } @@ -103,7 +97,7 @@ public class KeyActivity extends SherlockFragmentActivity { DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { public void run() { String title = null; - if (keyRingMasterKeyId != -1) { + if (dataUri != null) { // single key export title = getString(R.string.title_export_key); } else { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListActivity.java deleted file mode 100644 index 5b69f9218..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ /dev/null @@ -1,314 +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; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.R; - -import android.app.ProgressDialog; -import android.app.SearchManager; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.widget.Toast; - -import com.actionbarsherlock.app.SherlockFragmentActivity; -import com.actionbarsherlock.view.Menu; -import com.actionbarsherlock.view.MenuItem; - -public class KeyListActivity extends SherlockFragmentActivity { - - protected String mExportFilename = Constants.path.APP_DIR + "/"; - - protected String mImportData; - protected boolean mDeleteAfterImport = false; - - protected int mKeyType; - - FileDialogFragment mFileDialog; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); - - handleActions(getIntent()); - } - - // TODO: needed? - // @Override - // protected void onNewIntent(Intent intent) { - // super.onNewIntent(intent); - // handleActions(intent); - // } - - protected void handleActions(Intent intent) { - String action = intent.getAction(); - Bundle extras = intent.getExtras(); - - if (extras == null) { - extras = new Bundle(); - } - - /** - * Android Standard Actions - */ - String searchString = null; - if (Intent.ACTION_SEARCH.equals(action)) { - searchString = extras.getString(SearchManager.QUERY); - if (searchString != null && searchString.trim().length() == 0) { - searchString = null; - } - } - - // if (searchString == null) { - // mFilterLayout.setVisibility(View.GONE); - // } else { - // mFilterLayout.setVisibility(View.VISIBLE); - // mFilterInfo.setText(getString(R.string.filterInfo, searchString)); - // } - // - // if (mListAdapter != null) { - // mListAdapter.cleanup(); - // } - // mListAdapter = new KeyListAdapter(this, searchString); - // mList.setAdapter(mListAdapter); - - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case Id.request.filename: { - if (resultCode == RESULT_OK && data != null) { - try { - String path = data.getData().getPath(); - Log.d(Constants.TAG, "path=" + path); - - // set filename used in export/import dialogs - mFileDialog.setFilename(path); - } catch (NullPointerException e) { - Log.e(Constants.TAG, "Nullpointer while retrieving path!", e); - } - } - return; - } - - default: { - break; - } - } - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - // TODO: reimplement! - // menu.add(3, Id.menu.option.search, 0, R.string.menu_search) - // .setIcon(R.drawable.ic_menu_search).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - menu.add(0, Id.menu.option.import_from_file, 5, R.string.menu_import_from_file) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER | MenuItem.SHOW_AS_ACTION_WITH_TEXT); - menu.add(0, Id.menu.option.export_keys, 6, R.string.menu_export_keys).setShowAsAction( - MenuItem.SHOW_AS_ACTION_NEVER | MenuItem.SHOW_AS_ACTION_WITH_TEXT); - - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - - case android.R.id.home: - // app icon in Action Bar clicked; go home - Intent intent = new Intent(this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - - case Id.menu.option.import_from_file: { - Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class); - intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE); - startActivityForResult(intentImportFromFile, 0); - return true; - } - - case Id.menu.option.export_keys: { - showExportKeysDialog(-1); - return true; - } - - // case Id.menu.option.search: - // startSearch("", false, null, false); - // return true; - - default: { - return super.onOptionsItemSelected(item); - } - } - } - - /** - * Show dialog where to export keys - * - * @param keyRingMasterKeyId - * if -1 export all keys - */ - public void showExportKeysDialog(final long keyRingMasterKeyId) { - // Message is received after file is selected - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == FileDialogFragment.MESSAGE_OKAY) { - Bundle data = message.getData(); - mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME); - - exportKeys(keyRingMasterKeyId); - } - } - }; - - // Create a new Messenger for the communication back - final Messenger messenger = new Messenger(returnHandler); - - DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { - public void run() { - String title = null; - if (keyRingMasterKeyId != -1) { - // single key export - title = getString(R.string.title_export_key); - } else { - title = getString(R.string.title_export_keys); - } - - String message = null; - if (mKeyType == Id.type.public_key) { - message = getString(R.string.specify_file_to_export_to); - } else { - message = getString(R.string.specify_file_to_export_secret_keys_to); - } - - mFileDialog = FileDialogFragment.newInstance(messenger, title, message, - mExportFilename, null, Id.request.filename); - - mFileDialog.show(getSupportFragmentManager(), "fileDialog"); - } - }); - } - - /** - * Show dialog to delete key - * - * @param keyRingIds - */ - public void showDeleteKeyDialog(long[] keyRingIds) { - // Message is received after key is deleted - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { - // no further actions needed - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - - DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, - keyRingIds, mKeyType); - - deleteKeyDialog.show(getSupportFragmentManager(), "deleteKeyDialog"); - } - - /** - * Export keys - * - * @param keyRingMasterKeyId - * if -1 export all keys - */ - public void exportKeys(long keyRingMasterKeyId) { - Log.d(Constants.TAG, "exportKeys started"); - - // Send all information needed to service to export key in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_EXPORT_KEYRING); - - // fill values for this action - Bundle data = new Bundle(); - - data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename); - data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, mKeyType); - - if (keyRingMasterKeyId == -1) { - data.putBoolean(KeychainIntentService.EXPORT_ALL, true); - } else { - data.putLong(KeychainIntentService.EXPORT_KEY_RING_MASTER_KEY_ID, keyRingMasterKeyId); - } - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after exporting is done in ApgService - KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(this, - R.string.progress_exporting, ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard ApgHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - // get returned data bundle - Bundle returnData = message.getData(); - - int exported = returnData.getInt(KeychainIntentService.RESULT_EXPORT); - String toastMessage; - if (exported == 1) { - toastMessage = getString(R.string.key_exported); - } else if (exported > 0) { - toastMessage = getString(R.string.keys_exported, exported); - } else { - toastMessage = getString(R.string.no_keys_exported); - } - Toast.makeText(KeyListActivity.this, toastMessage, Toast.LENGTH_SHORT).show(); - - } - }; - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(exportHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - exportHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } -} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java index 95a3dd3b1..d281d1559 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.ActionBarHelper; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; @@ -27,72 +28,49 @@ import com.actionbarsherlock.view.MenuItem; import android.content.Intent; import android.os.Bundle; -public class KeyListPublicActivity extends KeyListActivity { +public class KeyListPublicActivity extends KeyActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mKeyType = Id.type.public_key; - setContentView(R.layout.key_list_public_activity); - mExportFilename = Constants.path.APP_DIR + "/pubexport.asc"; + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeButtonEnabled(true); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); - menu.add(1, Id.menu.option.key_server, 1, R.string.menu_key_server) - .setIcon(R.drawable.ic_menu_search_list) - .setShowAsAction( - MenuItem.SHOW_AS_ACTION_ALWAYS); - menu.add(1, Id.menu.option.import_from_qr_code, 2, R.string.menu_import_from_qr_code) - .setShowAsAction( - MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); - menu.add(1, Id.menu.option.import_from_nfc, 3, R.string.menu_import_from_nfc) - .setShowAsAction( - MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); - + getSupportMenuInflater().inflate(R.menu.key_list_public, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case Id.menu.option.key_server: { - startActivityForResult(new Intent(this, KeyServerQueryActivity.class), 0); + case android.R.id.home: + // app icon in Action Bar clicked; go home + Intent intent = new Intent(this, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); return true; - } - case Id.menu.option.import_from_file: { - Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class); - intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE); - startActivityForResult(intentImportFromFile, 0); - - return true; - } - - case Id.menu.option.import_from_qr_code: { + case R.id.menu_key_list_public_import: Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class); - intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_QR_CODE); + intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY); startActivityForResult(intentImportFromFile, Id.request.import_from_qr_code); return true; - } - - case Id.menu.option.import_from_nfc: { - Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class); - intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_NFC); - startActivityForResult(intentImportFromFile, 0); + case R.id.menu_key_list_public_export: + showExportKeysDialog(null, Id.type.public_key, Constants.path.APP_DIR + + "/pubexport.asc"); return true; - } - - default: { + default: return super.onOptionsItemSelected(item); } - } } // @Override diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index fde90bb32..a21fa7ebd 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -56,7 +56,7 @@ import android.widget.ListView; public class KeyListPublicFragment extends Fragment implements AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks { - private KeyListPublicActivity mKeyListPublicActivity; +// private KeyListPublicActivity mKeyListPublicActivity; private KeyListPublicAdapter mAdapter; private StickyListHeadersListView mStickyList; @@ -77,7 +77,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - mKeyListPublicActivity = (KeyListPublicActivity) getActivity(); +// mKeyListPublicActivity = (KeyListPublicActivity) getActivity(); mStickyList = (StickyListHeadersListView) getActivity().findViewById(R.id.list); mStickyList.setOnItemClickListener(this); @@ -164,7 +164,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte // setListShown(false); // Create an empty adapter we will use to display the loaded data. - mAdapter = new KeyListPublicAdapter(mKeyListPublicActivity, null, Id.type.public_key, + mAdapter = new KeyListPublicAdapter(getActivity(), null, Id.type.public_key, USER_ID_INDEX); mStickyList.setAdapter(mAdapter); @@ -222,7 +222,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte */ @Override public void onItemClick(AdapterView adapterView, View view, int position, long id) { - Intent detailsIntent = new Intent(mKeyListPublicActivity, KeyViewActivity.class); + Intent detailsIntent = new Intent(getActivity(), KeyViewActivity.class); detailsIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long.toString(id))); startActivity(detailsIntent); } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java index c19cdeea5..4db20e6b7 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java @@ -27,47 +27,57 @@ import android.os.Bundle; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; -public class KeyListSecretActivity extends KeyListActivity { +public class KeyListSecretActivity extends KeyActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mKeyType = Id.type.secret_key; - setContentView(R.layout.key_list_secret_activity); - mExportFilename = Constants.path.APP_DIR + "/secexport.asc"; + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeButtonEnabled(true); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); - menu.add(1, Id.menu.option.create, 1, R.string.menu_create_key).setShowAsAction( - MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); - menu.add(1, Id.menu.option.createExpert, 2, R.string.menu_create_key_expert) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - + getSupportMenuInflater().inflate(R.menu.key_list_secret, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case Id.menu.option.create: { - createKey(); + case android.R.id.home: + // app icon in Action Bar clicked; go home + Intent intent = new Intent(this, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + return true; - } + case R.id.menu_key_list_secret_create: + createKey(); - case Id.menu.option.createExpert: { + return true; + case R.id.menu_key_list_secret_create_expert: createKeyExpert(); + return true; - } + case R.id.menu_key_list_secret_export: + showExportKeysDialog(null, Id.type.secret_key, Constants.path.APP_DIR + + "/secexport.asc"); + + return true; + case R.id.menu_key_list_secret_import: + Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class); + intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY); + startActivityForResult(intentImportFromFile, Id.request.import_from_qr_code); - default: { + return true; + default: return super.onOptionsItemSelected(item); } - } } private void createKey() { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java index c32a797be..d7e2b8063 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java @@ -31,6 +31,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment; import org.sufficientlysecure.keychain.util.Log; @@ -134,10 +135,21 @@ public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCal case R.id.menu_key_view_share_clipboard: copyToClipboard(mDataUri); return true; - case R.id.menu_key_view_delete: - deleteKey(mDataUri, Id.type.public_key); + case R.id.menu_key_view_delete: { + // Message is received after key is deleted + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { + setResult(RESULT_CANCELED); + finish(); + } + } + }; + + deleteKey(mDataUri, Id.type.public_key, returnHandler); return true; - + } } return super.onOptionsItemSelected(item); } -- cgit v1.2.3 From a2f0667593be2f7ecd5b0e2445321a22a90eea9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 7 Jan 2014 22:59:39 +0100 Subject: action encrypt to contact in view and multi select --- .../keychain/ui/KeyListPublicFragment.java | 49 +++++++++++++++------- .../keychain/ui/KeyViewActivity.java | 20 ++++++++- 2 files changed, 54 insertions(+), 15 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index a21fa7ebd..d9fa0948a 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -22,6 +22,7 @@ import java.util.Set; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.ui.adapter.KeyListPublicAdapter; @@ -56,7 +57,7 @@ import android.widget.ListView; public class KeyListPublicFragment extends Fragment implements AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks { -// private KeyListPublicActivity mKeyListPublicActivity; + // private KeyListPublicActivity mKeyListPublicActivity; private KeyListPublicAdapter mAdapter; private StickyListHeadersListView mStickyList; @@ -77,7 +78,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); -// mKeyListPublicActivity = (KeyListPublicActivity) getActivity(); + // mKeyListPublicActivity = (KeyListPublicActivity) getActivity(); mStickyList = (StickyListHeadersListView) getActivity().findViewById(R.id.list); mStickyList.setOnItemClickListener(this); @@ -105,7 +106,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { android.view.MenuInflater inflater = getActivity().getMenuInflater(); - inflater.inflate(R.menu.key_list_multi_selection, menu); + inflater.inflate(R.menu.key_list_public_multi, menu); return true; } @@ -117,20 +118,27 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { Set positions = mAdapter.getCurrentCheckedPosition(); + + // get IDs for checked positions as long array + long[] ids = new long[positions.size()]; + int i = 0; + for (int pos : positions) { + ids[i] = mAdapter.getItemId(pos); + i++; + } + switch (item.getItemId()) { - case R.id.delete_entry: - - // get IDs for checked positions as long array - long[] ids = new long[positions.size()]; - int i = 0; - for (int pos : positions) { - ids[i] = mAdapter.getItemId(pos); - i++; - } + case R.id.menu_key_list_public_multi_encrypt: { + encrypt(ids); + + break; + } + case R.id.menu_key_list_public_multi_delete: { showDeleteKeyDialog(ids); break; } + } return false; } @@ -164,8 +172,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte // setListShown(false); // Create an empty adapter we will use to display the loaded data. - mAdapter = new KeyListPublicAdapter(getActivity(), null, Id.type.public_key, - USER_ID_INDEX); + mAdapter = new KeyListPublicAdapter(getActivity(), null, Id.type.public_key, USER_ID_INDEX); mStickyList.setAdapter(mAdapter); // Prepare the loader. Either re-connect with an existing one, @@ -227,6 +234,20 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte startActivity(detailsIntent); } + public void encrypt(long[] keyRingRowIds) { + // get master key ids from row ids + long[] keyRingIds = new long[keyRingRowIds.length]; + for (int i = 0; i < keyRingRowIds.length; i++) { + keyRingIds[i] = ProviderHelper.getPublicMasterKeyId(getActivity(), keyRingRowIds[i]); + } + + Intent intent = new Intent(getActivity(), EncryptActivity.class); + intent.setAction(EncryptActivity.ACTION_ENCRYPT); + intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, keyRingIds); + // used instead of startActivity set actionbar based on callingPackage + startActivityForResult(intent, 0); + } + /** * Show dialog to delete key * diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java index d7e2b8063..7d51c2ff4 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java @@ -50,6 +50,9 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.format.DateFormat; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; import android.widget.TextView; import android.widget.Toast; @@ -67,6 +70,7 @@ public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCal private TextView mFingerint; private TextView mExpiry; private TextView mCreation; + private Button mActionEncrypt; // NFC private NfcAdapter mNfcAdapter; @@ -86,6 +90,7 @@ public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCal mExpiry = (TextView) this.findViewById(R.id.expiry); mCreation = (TextView) this.findViewById(R.id.creation); mAlgorithm = (TextView) this.findViewById(R.id.algorithm); + mActionEncrypt = (Button) this.findViewById(R.id.action_encrypt); Intent intent = getIntent(); mDataUri = intent.getData(); @@ -146,7 +151,7 @@ public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCal } } }; - + deleteKey(mDataUri, Id.type.public_key, returnHandler); return true; } @@ -172,6 +177,19 @@ public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCal mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format( PgpKeyHelper.getCreationDate(mPublicKey))); mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(mPublicKey)); + + mActionEncrypt.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + long[] encryptionKeyIds = new long[] { mPublicKey.getKeyID() }; + Intent intent = new Intent(KeyViewActivity.this, EncryptActivity.class); + intent.setAction(EncryptActivity.ACTION_ENCRYPT); + intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); + // used instead of startActivity set actionbar based on callingPackage + startActivityForResult(intent, 0); + } + }); } /** -- cgit v1.2.3 From f76d33d2306d3377ca4fd8a15168176fa121966c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 7 Jan 2014 23:02:23 +0100 Subject: remove unused ids --- .../src/org/sufficientlysecure/keychain/Id.java | 43 ---------------------- 1 file changed, 43 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/Id.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/Id.java index e9b0b67d4..fb7851774 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/Id.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/Id.java @@ -27,18 +27,7 @@ import org.spongycastle.bcpg.CompressionAlgorithmTags; */ public final class Id { - public static final String TAG = "APG"; - public static final class menu { - public static final int export = 0x21070001; - public static final int delete = 0x21070002; - public static final int edit = 0x21070003; - public static final int update = 0x21070004; - public static final int exportToServer = 0x21070005; - public static final int share = 0x21070006; - public static final int share_qr_code = 0x21070007; - public static final int share_nfc = 0x21070008; - public static final int signKey = 0x21070009; public static final class option { public static final int new_pass_phrase = 0x21070001; @@ -82,20 +71,6 @@ public final class Id { public static final int unknown_signature_key = 0x00006011; } - // public static final class message { - // public static final int progress_update = 0x21070001; - // public static final int done = 0x21070002; - // public static final int import_keys = 0x21070003; - // public static final int export_keys = 0x21070004; - // public static final int import_done = 0x21070005; - // public static final int export_done = 0x21070006; - // public static final int create_key = 0x21070007; - // public static final int edit_key = 0x21070008; - // public static final int delete_done = 0x21070009; - // public static final int query_done = 0x21070010; - // public static final int unknown_signature_key = 0x21070011; - // } - // use only lower 16 bits due to compatibility lib public static final class request { public static final int public_keys = 0x00007001; @@ -109,18 +84,6 @@ public final class Id { public static final int sign_key = 0x00007009; } - // public static final class request { - // public static final int public_keys = 0x21070001; - // public static final int secret_keys = 0x21070002; - // public static final int filename = 0x21070003; - // public static final int output_filename = 0x21070004; - // public static final int key_server_preference = 0x21070005; - // public static final int look_up_key_id = 0x21070006; - // public static final int export_to_server = 0x21070007; - // public static final int import_from_qr_code = 0x21070008; - // public static final int sign_key = 0x21070009; - // } - public static final class dialog { public static final int pass_phrase = 0x21070001; public static final int encrypting = 0x21070002; @@ -136,7 +99,6 @@ public final class Id { public static final int export_keys = 0x2107000c; public static final int exporting = 0x2107000d; public static final int new_account = 0x2107000e; - // public static final int about = 0x2107000f; public static final int change_log = 0x21070010; public static final int output_filename = 0x21070011; public static final int delete_file = 0x21070012; @@ -152,11 +114,6 @@ public final class Id { public static final int export_keys = 0x21070002; } - // public static final class database { - // public static final int type_public = 0; - // public static final int type_secret = 1; - // } - public static final class type { public static final int public_key = 0x21070001; public static final int secret_key = 0x21070002; -- cgit v1.2.3 From 2ccfc09f440c3805674f34a599b42e16b430dcc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 7 Jan 2014 23:48:16 +0100 Subject: instructions on empty public key list for first start --- .../keychain/ui/KeyListPublicFragment.java | 32 +++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index d9fa0948a..b5ca0269d 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -46,8 +46,10 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.view.View.OnClickListener; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; +import android.widget.Button; import android.widget.ListView; /** @@ -57,16 +59,44 @@ import android.widget.ListView; public class KeyListPublicFragment extends Fragment implements AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks { - // private KeyListPublicActivity mKeyListPublicActivity; private KeyListPublicAdapter mAdapter; private StickyListHeadersListView mStickyList; + // empty layout + private Button mButtonEmptyCreate; + private Button mButtonEmptyImport; + /** * Load custom layout with StickyListView from library */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.key_list_public_fragment, container, false); + + mButtonEmptyCreate = (Button) view.findViewById(R.id.key_list_empty_button_create); + mButtonEmptyCreate.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + Intent intent = new Intent(getActivity(), EditKeyActivity.class); + intent.setAction(EditKeyActivity.ACTION_CREATE_KEY); + intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true); + intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, ""); // show user id view + startActivityForResult(intent, 0); + } + }); + + mButtonEmptyImport = (Button) view.findViewById(R.id.key_list_empty_button_import); + mButtonEmptyImport.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + Intent intentImportFromFile = new Intent(getActivity(), ImportKeysActivity.class); + intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY); + startActivityForResult(intentImportFromFile, Id.request.import_from_qr_code); + } + }); + return view; } -- cgit v1.2.3 From 1970d4be6eb9d4bd09d3e4a95a344454e497be24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 7 Jan 2014 23:54:12 +0100 Subject: multi selection for secret key list --- .../keychain/ui/KeyListSecretFragment.java | 92 ++++++++++++++++++++++ .../keychain/ui/adapter/KeyListSecretAdapter.java | 51 +++++++++++- 2 files changed, 142 insertions(+), 1 deletion(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java index 40579a3c2..c0b67719e 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java @@ -17,22 +17,32 @@ package org.sufficientlysecure.keychain.ui; +import java.util.Set; + import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.ui.adapter.KeyListSecretAdapter; +import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; +import android.annotation.SuppressLint; import android.content.Intent; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; +import android.view.ActionMode; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView.OnItemClickListener; import com.actionbarsherlock.app.SherlockListFragment; @@ -47,6 +57,7 @@ public class KeyListSecretFragment extends SherlockListFragment implements /** * Define Adapter and Loader on create of Activity */ + @SuppressLint("NewApi") @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); @@ -59,6 +70,75 @@ public class KeyListSecretFragment extends SherlockListFragment implements // application this would come from a resource. setEmptyText(getString(R.string.list_empty)); + /* + * ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only + * available for Android >= 3.0 + */ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); + getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() { + + private int count = 0; + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + android.view.MenuInflater inflater = getActivity().getMenuInflater(); + inflater.inflate(R.menu.key_list_secret_multi, menu); + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + Set positions = mAdapter.getCurrentCheckedPosition(); + + // get IDs for checked positions as long array + long[] ids = new long[positions.size()]; + int i = 0; + for (int pos : positions) { + ids[i] = mAdapter.getItemId(pos); + i++; + } + + switch (item.getItemId()) { + case R.id.menu_key_list_public_multi_delete: { + showDeleteKeyDialog(ids); + + break; + } + } + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + count = 0; + mAdapter.clearSelection(); + } + + @Override + public void onItemCheckedStateChanged(ActionMode mode, int position, long id, + boolean checked) { + if (checked) { + count++; + mAdapter.setNewSelection(position, checked); + } else { + count--; + mAdapter.removeSelection(position); + } + + String keysSelected = getResources().getQuantityString( + R.plurals.key_list_selected_keys, count, count); + mode.setTitle(keysSelected); + } + + }); + } + // We have a menu item to show in action bar. setHasOptionsMenu(true); @@ -123,4 +203,16 @@ public class KeyListSecretFragment extends SherlockListFragment implements editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY); startActivityForResult(editIntent, 0); } + + /** + * Show dialog to delete key + * + * @param keyRingRowIds + */ + public void showDeleteKeyDialog(long[] keyRingRowIds) { + DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(null, + keyRingRowIds, Id.type.secret_key); + + deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog"); + } } 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 2fda8a9f7..f78eaf627 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java @@ -17,12 +17,17 @@ 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; @@ -30,9 +35,11 @@ import android.view.ViewGroup; import android.widget.TextView; public class KeyListSecretAdapter extends CursorAdapter { - private LayoutInflater mInflater; + @SuppressLint("UseSparseArrays") + private HashMap mSelection = new HashMap(); + public KeyListSecretAdapter(Context context, Cursor c, int flags) { super(context, c, flags); @@ -74,4 +81,46 @@ public class KeyListSecretAdapter extends CursorAdapter { return mInflater.inflate(R.layout.key_list_item, null); } + /** -------------------------- MULTI-SELECTION METHODS -------------- */ + public void setNewSelection(int position, boolean value) { + mSelection.put(position, value); + notifyDataSetChanged(); + } + + public boolean isPositionChecked(int position) { + Boolean result = mSelection.get(position); + return result == null ? false : result; + } + + public Set getCurrentCheckedPosition() { + return mSelection.keySet(); + } + + public void removeSelection(int position) { + mSelection.remove(position); + notifyDataSetChanged(); + } + + public void clearSelection() { + mSelection.clear(); + notifyDataSetChanged(); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + // let the adapter handle setting up the row views + View v = super.getView(position, convertView, parent); + + /** + * Change color for multi-selection + */ + // default color + v.setBackgroundColor(Color.TRANSPARENT); + if (mSelection.get(position) != null) { + // this is a selected position, change color! + v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis)); + } + return v; + } + } -- cgit v1.2.3 From 14a8738933bd2bb323ee05a47421881337f6e9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 8 Jan 2014 00:52:09 +0100 Subject: fix import, add missing multi select menu --- .../org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java | 8 +++----- .../org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java | 1 - .../org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java | 1 - 3 files changed, 3 insertions(+), 7 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java index d281d1559..023c8fd9d 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java @@ -20,14 +20,13 @@ package org.sufficientlysecure.keychain.ui; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; - -import com.actionbarsherlock.view.Menu; -import com.actionbarsherlock.view.MenuItem; import android.content.Intent; import android.os.Bundle; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; + public class KeyListPublicActivity extends KeyActivity { @Override @@ -59,7 +58,6 @@ public class KeyListPublicActivity extends KeyActivity { return true; case R.id.menu_key_list_public_import: Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class); - intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY); startActivityForResult(intentImportFromFile, Id.request.import_from_qr_code); return true; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index b5ca0269d..3ce1d08d0 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -92,7 +92,6 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte @Override public void onClick(View v) { Intent intentImportFromFile = new Intent(getActivity(), ImportKeysActivity.class); - intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY); startActivityForResult(intentImportFromFile, Id.request.import_from_qr_code); } }); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java index 4db20e6b7..d95f03ae1 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java @@ -71,7 +71,6 @@ public class KeyListSecretActivity extends KeyActivity { return true; case R.id.menu_key_list_secret_import: Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class); - intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY); startActivityForResult(intentImportFromFile, Id.request.import_from_qr_code); return true; -- cgit v1.2.3 From 2162c85c125a2155f29ddcd436d36ff9a472c3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 9 Jan 2014 15:12:41 +0100 Subject: use bootstrap buttons --- .../keychain/ui/DecryptActivity.java | 6 +-- .../keychain/ui/EditKeyActivity.java | 12 +++--- .../keychain/ui/EncryptActivity.java | 15 ++++--- .../keychain/ui/ImportKeysActivity.java | 27 +++++++++++- .../keychain/ui/ImportKeysClipboardFragment.java | 7 ++-- .../keychain/ui/ImportKeysFileFragment.java | 7 ++-- .../keychain/ui/ImportKeysNFCFragment.java | 7 ++-- .../keychain/ui/ImportKeysQrCodeFragment.java | 6 +-- .../keychain/ui/ImportKeysServerFragment.java | 9 ++-- .../keychain/ui/KeyListPublicFragment.java | 15 +++---- .../keychain/ui/KeyViewActivity.java | 6 +-- .../keychain/ui/dialog/FileDialogFragment.java | 22 +++++----- .../keychain/ui/widget/KeyEditor.java | 48 +++++++++++----------- .../keychain/ui/widget/KeyServerEditor.java | 7 ++-- .../keychain/ui/widget/SectionView.java | 10 ++--- .../keychain/ui/widget/UserIdEditor.java | 7 ++-- 16 files changed, 120 insertions(+), 91 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DecryptActivity.java index 78ad4c9be..f7fc49083 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -60,7 +60,6 @@ import android.view.View.OnClickListener; import android.view.animation.AnimationUtils; import android.widget.CheckBox; import android.widget.EditText; -import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -70,6 +69,7 @@ import android.widget.ViewFlipper; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; +import com.beardedhen.androidbootstrap.BootstrapButton; @SuppressLint("NewApi") public class DecryptActivity extends SherlockFragmentActivity { @@ -107,7 +107,7 @@ public class DecryptActivity extends SherlockFragmentActivity { private EditText mFilename = null; private CheckBox mDeleteAfter = null; - private ImageButton mBrowse = null; + private BootstrapButton mBrowse = null; private String mInputFilename = null; private String mOutputFilename = null; @@ -216,7 +216,7 @@ public class DecryptActivity extends SherlockFragmentActivity { mMessage.setMinimumHeight(height); mFilename = (EditText) findViewById(R.id.filename); - mBrowse = (ImageButton) findViewById(R.id.btn_browse); + mBrowse = (BootstrapButton) findViewById(R.id.btn_browse); mBrowse.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { FileHelper.openFile(DecryptActivity.this, mFilename.getText().toString(), "*/*", diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index d141fbe3a..569a16c41 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -55,7 +55,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; @@ -64,6 +63,7 @@ import android.widget.Toast; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; +import com.beardedhen.androidbootstrap.BootstrapButton; public class EditKeyActivity extends KeyActivity { @@ -91,7 +91,7 @@ public class EditKeyActivity extends KeyActivity { private String mCurrentPassPhrase = null; private String mNewPassPhrase = null; - private Button mChangePassPhrase; + private BootstrapButton mChangePassPhrase; private CheckBox mNoPassphrase; @@ -336,7 +336,7 @@ public class EditKeyActivity extends KeyActivity { } } }; - + deleteKey(mDataUri, Id.type.secret_key, returnHandler); return true; } @@ -426,7 +426,7 @@ public class EditKeyActivity extends KeyActivity { setContentView(R.layout.edit_key); // find views - mChangePassPhrase = (Button) findViewById(R.id.edit_key_btn_change_pass_phrase); + mChangePassPhrase = (BootstrapButton) findViewById(R.id.edit_key_btn_change_pass_phrase); mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase); // Build layout based on given userIds and keys @@ -653,7 +653,7 @@ public class EditKeyActivity extends KeyActivity { } private void updatePassPhraseButtonText() { - mChangePassPhrase.setText(isPassphraseSet() ? R.string.btn_change_passphrase - : R.string.btn_set_passphrase); + mChangePassPhrase.setText(isPassphraseSet() ? getString(R.string.btn_change_passphrase) + : getString(R.string.btn_set_passphrase)); } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 2dfdf254e..681548c9b 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -55,10 +55,8 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.animation.AnimationUtils; import android.widget.ArrayAdapter; -import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; -import android.widget.ImageButton; import android.widget.ImageView; import android.widget.Spinner; import android.widget.TextView; @@ -68,6 +66,7 @@ import android.widget.ViewFlipper; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; +import com.beardedhen.androidbootstrap.BootstrapButton; public class EncryptActivity extends SherlockFragmentActivity { @@ -87,7 +86,7 @@ public class EncryptActivity extends SherlockFragmentActivity { private long mEncryptionKeyIds[] = null; private EditText mMessage = null; - private Button mSelectKeysButton = null; + private BootstrapButton mSelectKeysButton = null; private boolean mEncryptEnabled = false; private String mEncryptString = ""; @@ -117,7 +116,7 @@ public class EncryptActivity extends SherlockFragmentActivity { private EditText mFilename = null; private CheckBox mDeleteAfter = null; - private ImageButton mBrowse = null; + private BootstrapButton mBrowse = null; private String mInputFilename = null; private String mOutputFilename = null; @@ -825,7 +824,7 @@ public class EncryptActivity extends SherlockFragmentActivity { mModeLabel.setOnClickListener(nextModeClickListener); mMessage = (EditText) findViewById(R.id.message); - mSelectKeysButton = (Button) findViewById(R.id.btn_selectEncryptKeys); + mSelectKeysButton = (BootstrapButton) findViewById(R.id.btn_selectEncryptKeys); mSign = (CheckBox) findViewById(R.id.sign); mMainUserId = (TextView) findViewById(R.id.mainUserId); mMainUserIdRest = (TextView) findViewById(R.id.mainUserIdRest); @@ -841,7 +840,7 @@ public class EncryptActivity extends SherlockFragmentActivity { mMessage.setMinimumHeight(height); mFilename = (EditText) findViewById(R.id.filename); - mBrowse = (ImageButton) findViewById(R.id.btn_browse); + mBrowse = (BootstrapButton) findViewById(R.id.btn_browse); mBrowse.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { FileHelper.openFile(EncryptActivity.this, mFilename.getText().toString(), "*/*", @@ -896,9 +895,9 @@ public class EncryptActivity extends SherlockFragmentActivity { private void updateView() { if (mEncryptionKeyIds == null || mEncryptionKeyIds.length == 0) { - mSelectKeysButton.setText(R.string.no_keys_selected); + mSelectKeysButton.setText(getString(R.string.no_keys_selected)); } else if (mEncryptionKeyIds.length == 1) { - mSelectKeysButton.setText(R.string.one_key_selected); + mSelectKeysButton.setText(getString(R.string.one_key_selected)); } else { mSelectKeysButton.setText("" + mEncryptionKeyIds.length + " " + getResources().getString(R.string.n_keys_selected)); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index f83d469ac..94b5304a1 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui; import java.util.ArrayList; import java.util.List; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.ActionBarHelper; @@ -28,6 +29,7 @@ import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; import org.sufficientlysecure.keychain.util.Log; + import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.ProgressDialog; @@ -43,12 +45,15 @@ import android.os.Parcelable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.view.View; +import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Toast; + import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.ActionBar.OnNavigationListener; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.MenuItem; +import com.beardedhen.androidbootstrap.BootstrapButton; public class ImportKeysActivity extends SherlockFragmentActivity implements OnNavigationListener { public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY"; @@ -74,12 +79,30 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa OnNavigationListener mOnNavigationListener; String[] mNavigationStrings; + BootstrapButton mImportButton; + BootstrapButton mImportSignUploadButton; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.import_keys); + mImportButton = (BootstrapButton) findViewById(R.id.import_import); + mImportButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + importKeys(); + } + }); + mImportSignUploadButton = (BootstrapButton) findViewById(R.id.import_sign_and_upload); + mImportSignUploadButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + signAndUploadOnClick(); + } + }); + // set actionbar without home button if called from another app ActionBarHelper.setBackButton(this); @@ -398,11 +421,11 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa } } - public void importOnClick(View view) { + public void importOnClick() { importKeys(); } - public void signAndUploadOnClick(View view) { + public void signAndUploadOnClick() { // first, import! // importOnClick(view); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java index dcb7dbcc6..31f758395 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java @@ -26,12 +26,13 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.Button; + +import com.beardedhen.androidbootstrap.BootstrapButton; public class ImportKeysClipboardFragment extends Fragment { private ImportKeysActivity mImportActivity; - private Button mButton; + private BootstrapButton mButton; /** * Creates new instance of this fragment @@ -52,7 +53,7 @@ public class ImportKeysClipboardFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.import_keys_clipboard_fragment, container, false); - mButton = (Button) view.findViewById(R.id.import_clipboard_button); + mButton = (BootstrapButton) view.findViewById(R.id.import_clipboard_button); mButton.setOnClickListener(new OnClickListener() { @Override diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java index fbca9013b..ea76d2898 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java @@ -31,14 +31,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; -import android.widget.ImageButton; + +import com.beardedhen.androidbootstrap.BootstrapButton; public class ImportKeysFileFragment extends Fragment { public static final String ARG_PATH = "path"; private ImportKeysActivity mImportActivity; private EditText mFilename; - private ImageButton mBrowse; + private BootstrapButton mBrowse; /** * Creates new instance of this fragment @@ -61,7 +62,7 @@ public class ImportKeysFileFragment extends Fragment { View view = inflater.inflate(R.layout.import_keys_file_fragment, container, false); mFilename = (EditText) view.findViewById(R.id.import_keys_file_input); - mBrowse = (ImageButton) view.findViewById(R.id.import_keys_file_browse); + mBrowse = (BootstrapButton) view.findViewById(R.id.import_keys_file_browse); mBrowse.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysNFCFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysNFCFragment.java index 2d756dde6..83af8cf48 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysNFCFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysNFCFragment.java @@ -26,11 +26,12 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.Button; + +import com.beardedhen.androidbootstrap.BootstrapButton; public class ImportKeysNFCFragment extends Fragment { - private Button mButton; + private BootstrapButton mButton; /** * Creates new instance of this fragment @@ -51,7 +52,7 @@ public class ImportKeysNFCFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.import_keys_nfc_fragment, container, false); - mButton = (Button) view.findViewById(R.id.import_nfc_button); + mButton = (BootstrapButton) view.findViewById(R.id.import_nfc_button); mButton.setOnClickListener(new OnClickListener() { @Override diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java index 62b59b4f7..f9ead3a94 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java @@ -30,18 +30,18 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; +import com.beardedhen.androidbootstrap.BootstrapButton; import com.google.zxing.integration.android.IntentIntegratorSupportV4; import com.google.zxing.integration.android.IntentResult; public class ImportKeysQrCodeFragment extends Fragment { private ImportKeysActivity mImportActivity; - private Button mButton; + private BootstrapButton mButton; private TextView mText; private ProgressBar mProgress; @@ -66,7 +66,7 @@ public class ImportKeysQrCodeFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.import_keys_qr_code_fragment, container, false); - mButton = (Button) view.findViewById(R.id.import_qrcode_button); + mButton = (BootstrapButton) view.findViewById(R.id.import_qrcode_button); mText = (TextView) view.findViewById(R.id.import_qrcode_text); mProgress = (ProgressBar) view.findViewById(R.id.import_qrcode_progress); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java index 106c8ebef..c985f1f60 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java @@ -24,12 +24,13 @@ 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.View.OnClickListener; -import android.widget.Button; +import android.view.ViewGroup; + +import com.beardedhen.androidbootstrap.BootstrapButton; public class ImportKeysServerFragment extends Fragment { - private Button mButton; + private BootstrapButton mButton; /** * Creates new instance of this fragment @@ -50,7 +51,7 @@ public class ImportKeysServerFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.import_keys_keyserver_fragment, container, false); - mButton = (Button) view.findViewById(R.id.import_keyserver_button); + mButton = (BootstrapButton) view.findViewById(R.id.import_keyserver_button); mButton.setOnClickListener(new OnClickListener() { @Override diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index 3ce1d08d0..88503a5c4 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -22,9 +22,9 @@ import java.util.Set; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.KeyListPublicAdapter; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; @@ -45,13 +45,14 @@ import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.view.ViewGroup; import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; -import android.widget.Button; import android.widget.ListView; +import com.beardedhen.androidbootstrap.BootstrapButton; + /** * Public key list with sticky list headers. It does _not_ extend ListFragment because it uses * StickyListHeaders library which does not extend upon ListView. @@ -63,8 +64,8 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte private StickyListHeadersListView mStickyList; // empty layout - private Button mButtonEmptyCreate; - private Button mButtonEmptyImport; + private BootstrapButton mButtonEmptyCreate; + private BootstrapButton mButtonEmptyImport; /** * Load custom layout with StickyListView from library @@ -73,7 +74,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.key_list_public_fragment, container, false); - mButtonEmptyCreate = (Button) view.findViewById(R.id.key_list_empty_button_create); + mButtonEmptyCreate = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_create); mButtonEmptyCreate.setOnClickListener(new OnClickListener() { @Override @@ -86,7 +87,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte } }); - mButtonEmptyImport = (Button) view.findViewById(R.id.key_list_empty_button_import); + mButtonEmptyImport = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_import); mButtonEmptyImport.setOnClickListener(new OnClickListener() { @Override diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java index 7d51c2ff4..fb04bb1f8 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java @@ -52,12 +52,12 @@ import android.os.Message; import android.text.format.DateFormat; import android.view.View; import android.view.View.OnClickListener; -import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; +import com.beardedhen.androidbootstrap.BootstrapButton; @SuppressLint("NewApi") public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCallback, @@ -70,7 +70,7 @@ public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCal private TextView mFingerint; private TextView mExpiry; private TextView mCreation; - private Button mActionEncrypt; + private BootstrapButton mActionEncrypt; // NFC private NfcAdapter mNfcAdapter; @@ -90,7 +90,7 @@ public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCal mExpiry = (TextView) this.findViewById(R.id.expiry); mCreation = (TextView) this.findViewById(R.id.creation); mAlgorithm = (TextView) this.findViewById(R.id.algorithm); - mActionEncrypt = (Button) this.findViewById(R.id.action_encrypt); + mActionEncrypt = (BootstrapButton) this.findViewById(R.id.action_encrypt); Intent intent = getIntent(); mDataUri = intent.getData(); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java index 730fcc520..e65da2aa8 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java @@ -18,9 +18,9 @@ package org.sufficientlysecure.keychain.ui.dialog; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.FileHelper; import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.R; import android.app.Activity; import android.app.AlertDialog; @@ -36,7 +36,8 @@ import android.view.LayoutInflater; import android.view.View; import android.widget.CheckBox; import android.widget.EditText; -import android.widget.ImageButton; + +import com.beardedhen.androidbootstrap.BootstrapButton; // TODO: return result from file manager activity to this dialog! not the activity! // do it like in ImportFileFragment! @@ -55,6 +56,10 @@ public class FileDialogFragment extends DialogFragment { private Messenger mMessenger; + private EditText mFilename; + private BootstrapButton mBrowse; + private CheckBox mCheckBox; + /** * Creates new instance of this file dialog fragment */ @@ -90,10 +95,6 @@ public class FileDialogFragment extends DialogFragment { String checkboxText = getArguments().getString(ARG_CHECKBOX_TEXT); final int requestCode = getArguments().getInt(ARG_REQUEST_CODE); - final EditText mFilename; - final ImageButton mBrowse; - final CheckBox mCheckBox; - LayoutInflater inflater = (LayoutInflater) activity .getSystemService(Context.LAYOUT_INFLATER_SERVICE); AlertDialog.Builder alert = new AlertDialog.Builder(activity); @@ -105,13 +106,13 @@ public class FileDialogFragment extends DialogFragment { mFilename = (EditText) view.findViewById(R.id.input); mFilename.setText(defaultFile); - mBrowse = (ImageButton) view.findViewById(R.id.btn_browse); + mBrowse = (BootstrapButton) view.findViewById(R.id.btn_browse); mBrowse.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { // only .asc or .gpg files - // setting it to text/plain prevents Cynaogenmod's file manager from selecting asc or gpg types! - FileHelper.openFile(activity, mFilename.getText().toString(), "*/*", - requestCode); + // setting it to text/plain prevents Cynaogenmod's file manager from selecting asc + // or gpg types! + FileHelper.openFile(activity, mFilename.getText().toString(), "*/*", requestCode); } }); @@ -196,4 +197,3 @@ public class FileDialogFragment extends DialogFragment { } } } - diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java index 5748839bc..0f5d26644 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java @@ -16,12 +16,18 @@ package org.sufficientlysecure.keychain.ui.widget; +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Vector; + import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSecretKey; import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.util.Choice; -import org.sufficientlysecure.keychain.R; import android.app.DatePickerDialog; import android.app.Dialog; @@ -32,18 +38,12 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ArrayAdapter; -import android.widget.Button; import android.widget.DatePicker; -import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; -import java.text.DateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.Vector; +import com.beardedhen.androidbootstrap.BootstrapButton; public class KeyEditor extends LinearLayout implements Editor, OnClickListener { private PGPSecretKey mKey; @@ -51,12 +51,12 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { private EditorListener mEditorListener = null; private boolean mIsMasterKey; - ImageButton mDeleteButton; + BootstrapButton mDeleteButton; TextView mAlgorithm; TextView mKeyId; Spinner mUsage; TextView mCreationDate; - Button mExpiryDateButton; + BootstrapButton mExpiryDateButton; GregorianCalendar mExpiryDate; private int mDatePickerResultCount = 0; @@ -87,7 +87,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { mAlgorithm = (TextView) findViewById(R.id.algorithm); mKeyId = (TextView) findViewById(R.id.keyId); mCreationDate = (TextView) findViewById(R.id.creation); - mExpiryDateButton = (Button) findViewById(R.id.expiry); + mExpiryDateButton = (BootstrapButton) findViewById(R.id.expiry); mUsage = (Spinner) findViewById(R.id.usage); Choice choices[] = { new Choice(Id.choice.usage.sign_only, getResources().getString( @@ -101,7 +101,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mUsage.setAdapter(adapter); - mDeleteButton = (ImageButton) findViewById(R.id.delete); + mDeleteButton = (BootstrapButton) findViewById(R.id.delete); mDeleteButton.setOnClickListener(this); setExpiryDate(null); @@ -118,16 +118,18 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { date.get(Calendar.DAY_OF_MONTH)); mDatePickerResultCount = 0; dialog.setCancelable(true); - dialog.setButton(Dialog.BUTTON_NEGATIVE, getContext() - .getString(R.string.btn_no_date), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if (mDatePickerResultCount++ == 0) // Note: Ignore results after the first - // one - android sends multiples. - { - setExpiryDate(null); - } - } - }); + dialog.setButton(Dialog.BUTTON_NEGATIVE, + getContext().getString(R.string.btn_no_date), + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + if (mDatePickerResultCount++ == 0) // Note: Ignore results after the + // first + // one - android sends multiples. + { + setExpiryDate(null); + } + } + }); dialog.show(); } }); @@ -237,7 +239,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { private void setExpiryDate(GregorianCalendar date) { mExpiryDate = date; if (date == null) { - mExpiryDateButton.setText(R.string.none); + mExpiryDateButton.setText(getContext().getString(R.string.none)); } else { mExpiryDateButton.setText(DateFormat.getDateInstance().format(date.getTime())); } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java index 5fdb2c9c8..01259ccd1 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java @@ -23,14 +23,15 @@ import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; +import com.beardedhen.androidbootstrap.BootstrapButton; + public class KeyServerEditor extends LinearLayout implements Editor, OnClickListener { private EditorListener mEditorListener = null; - ImageButton mDeleteButton; + BootstrapButton mDeleteButton; TextView mServer; public KeyServerEditor(Context context) { @@ -48,7 +49,7 @@ public class KeyServerEditor extends LinearLayout implements Editor, OnClickList mServer = (TextView) findViewById(R.id.server); - mDeleteButton = (ImageButton) findViewById(R.id.delete); + mDeleteButton = (BootstrapButton) findViewById(R.id.delete); mDeleteButton.setOnClickListener(this); super.onFinishInflate(); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java index 99190e9c7..91e3831b7 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java @@ -45,17 +45,16 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ArrayAdapter; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.beardedhen.androidbootstrap.BootstrapButton; public class SectionView extends LinearLayout implements OnClickListener, EditorListener { private LayoutInflater mInflater; - private View mAdd; - private ImageView mPlusButton; + private BootstrapButton mPlusButton; private ViewGroup mEditors; private TextView mTitle; private int mType = 0; @@ -103,7 +102,6 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor public void setCanEdit(boolean bCanEdit) { canEdit = bCanEdit; - mPlusButton = (ImageView) findViewById(R.id.plusbutton); if (!canEdit) { mPlusButton.setVisibility(View.INVISIBLE); } @@ -117,8 +115,8 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor setDrawingCacheEnabled(true); setAlwaysDrawnWithCacheEnabled(true); - mAdd = findViewById(R.id.header); - mAdd.setOnClickListener(this); + mPlusButton = (BootstrapButton) findViewById(R.id.plusbutton); + mPlusButton.setOnClickListener(this); mEditors = (ViewGroup) findViewById(R.id.editors); mTitle = (TextView) findViewById(R.id.title); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java index 6c65e840c..5428b626e 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java @@ -27,14 +27,15 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.EditText; -import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.RadioButton; +import com.beardedhen.androidbootstrap.BootstrapButton; + public class UserIdEditor extends LinearLayout implements Editor, OnClickListener { private EditorListener mEditorListener = null; - private ImageButton mDeleteButton; + private BootstrapButton mDeleteButton; private RadioButton mIsMainUserId; private EditText mName; private EditText mEmail; @@ -95,7 +96,7 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene setDrawingCacheEnabled(true); setAlwaysDrawnWithCacheEnabled(true); - mDeleteButton = (ImageButton) findViewById(R.id.delete); + mDeleteButton = (BootstrapButton) findViewById(R.id.delete); mDeleteButton.setOnClickListener(this); mIsMainUserId = (RadioButton) findViewById(R.id.isMainUserId); mIsMainUserId.setOnClickListener(this); -- cgit v1.2.3 From 10715f7acee9620e8a27b62f1600ee4bcbae1ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 9 Jan 2014 17:02:49 +0100 Subject: add experimental drawer navigation --- .../service/remote/AppSettingsFragment.java | 19 +- .../keychain/ui/DrawerActivity.java | 444 +++++++++++++++++++++ .../keychain/ui/KeyActivity.java | 3 +- .../keychain/ui/KeyListPublicActivity.java | 11 +- 4 files changed, 459 insertions(+), 18 deletions(-) create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java index e592f5d57..bb6e427a4 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java @@ -49,12 +49,13 @@ import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; +import com.beardedhen.androidbootstrap.BootstrapButton; + public class AppSettingsFragment extends Fragment { // model @@ -62,12 +63,12 @@ public class AppSettingsFragment extends Fragment { // view private LinearLayout mAdvancedSettingsContainer; - private Button mAdvancedSettingsButton; + private BootstrapButton mAdvancedSettingsButton; private TextView mAppNameView; private ImageView mAppIconView; private TextView mKeyUserId; private TextView mKeyUserIdRest; - private Button mSelectKeyButton; + private BootstrapButton mSelectKeyButton; private Spinner mEncryptionAlgorithm; private Spinner mHashAlgorithm; private Spinner mCompression; @@ -116,7 +117,8 @@ public class AppSettingsFragment extends Fragment { } private void initView(View view) { - mAdvancedSettingsButton = (Button) view.findViewById(R.id.api_app_settings_advanced_button); + mAdvancedSettingsButton = (BootstrapButton) view + .findViewById(R.id.api_app_settings_advanced_button); mAdvancedSettingsContainer = (LinearLayout) view .findViewById(R.id.api_app_settings_advanced); @@ -124,7 +126,8 @@ public class AppSettingsFragment extends Fragment { mAppIconView = (ImageView) view.findViewById(R.id.api_app_settings_app_icon); mKeyUserId = (TextView) view.findViewById(R.id.api_app_settings_user_id); mKeyUserIdRest = (TextView) view.findViewById(R.id.api_app_settings_user_id_rest); - mSelectKeyButton = (Button) view.findViewById(R.id.api_app_settings_select_key_button); + mSelectKeyButton = (BootstrapButton) view + .findViewById(R.id.api_app_settings_select_key_button); mEncryptionAlgorithm = (Spinner) view .findViewById(R.id.api_app_settings_encryption_algorithm); mHashAlgorithm = (Spinner) view.findViewById(R.id.api_app_settings_hash_algorithm); @@ -204,11 +207,13 @@ public class AppSettingsFragment extends Fragment { if (mAdvancedSettingsContainer.getVisibility() == View.VISIBLE) { mAdvancedSettingsContainer.startAnimation(invisibleAnimation); mAdvancedSettingsContainer.setVisibility(View.GONE); - mAdvancedSettingsButton.setText(R.string.api_settings_show_advanced); + mAdvancedSettingsButton.setText(getString(R.string.api_settings_show_advanced)); + mAdvancedSettingsButton.setLeftIcon("fa-caret-up"); } else { mAdvancedSettingsContainer.startAnimation(visibleAnimation); mAdvancedSettingsContainer.setVisibility(View.VISIBLE); - mAdvancedSettingsButton.setText(R.string.api_settings_hide_advanced); + mAdvancedSettingsButton.setText(getString(R.string.api_settings_hide_advanced)); + mAdvancedSettingsButton.setLeftIcon("fa-caret-down"); } } }); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java new file mode 100644 index 000000000..e278af5e3 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java @@ -0,0 +1,444 @@ +/* + * + * from https://github.com/tobykurien/SherlockNavigationDrawer + * + * Copyright 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.ui; + +import org.sufficientlysecure.keychain.R; + +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.v4.app.ActionBarDrawerToggle; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; +import android.view.ActionProvider; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.SubMenu; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; + +/** + * This example illustrates a common usage of the DrawerLayout widget in the Android support + * library. + *

+ *

+ * When a navigation (left) drawer is present, the host activity should detect presses of the action + * bar's Up affordance as a signal to open and close the navigation drawer. The + * ActionBarDrawerToggle facilitates this behavior. Items within the drawer should fall into one of + * two categories: + *

+ *

+ *

    + *
  • View switches. A view switch follows the same basic policies as list or tab + * navigation in that a view switch does not create navigation history. This pattern should only be + * used at the root activity of a task, leaving some form of Up navigation active for activities + * further down the navigation hierarchy.
  • + *
  • Selective Up. The drawer allows the user to choose an alternate parent for + * Up navigation. This allows a user to jump across an app's navigation hierarchy at will. The + * application should treat this as it treats Up navigation from a different task, replacing the + * current task stack using TaskStackBuilder or similar. This is the only form of navigation drawer + * that should be used outside of the root activity of a task.
  • + *
+ *

+ *

+ * Right side drawers should be used for actions, not navigation. This follows the pattern + * established by the Action Bar that navigation should be to the left and actions to the right. An + * action should be an operation performed on the current contents of the window, for example + * enabling or disabling a data overlay on top of the current content. + *

+ */ +public class DrawerActivity extends SherlockFragmentActivity { + private DrawerLayout mDrawerLayout; + private ListView mDrawerList; + private ActionBarDrawerToggle mDrawerToggle; + + private CharSequence mDrawerTitle; + private CharSequence mTitle; + private String[] mDrawerTitles; + + protected void setupDrawerNavigation(Bundle savedInstanceState) { + // mTitle = mDrawerTitle = getTitle(); + mDrawerTitles = getResources().getStringArray(R.array.drawer_array); + mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); + mDrawerList = (ListView) findViewById(R.id.left_drawer); + + // set a custom shadow that overlays the main content when the drawer + // opens + mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); + // set up the drawer's list view with items and click listener + mDrawerList.setAdapter(new ArrayAdapter(this, R.layout.drawer_list_item, + mDrawerTitles)); + mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); + + // enable ActionBar app icon to behave as action to toggle nav drawer + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeButtonEnabled(true); + + // ActionBarDrawerToggle ties together the the proper interactions + // between the sliding drawer and the action bar app icon + mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */ + mDrawerLayout, /* DrawerLayout object */ + R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */ + R.string.drawer_open, /* "open drawer" description for accessibility */ + R.string.drawer_close /* "close drawer" description for accessibility */ + ) { + public void onDrawerClosed(View view) { + getSupportActionBar().setTitle(mTitle); + supportInvalidateOptionsMenu(); // creates call to + // onPrepareOptionsMenu() + } + + public void onDrawerOpened(View drawerView) { + getSupportActionBar().setTitle(mDrawerTitle); + supportInvalidateOptionsMenu(); // creates call to + // onPrepareOptionsMenu() + } + }; + mDrawerLayout.setDrawerListener(mDrawerToggle); + + if (savedInstanceState == null) { + selectItem(0); + } + } + + /* Called whenever we call invalidateOptionsMenu() */ + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + // If the nav drawer is open, hide action items related to the content + // view + boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList); + // menu.findItem(R.id.action_websearch).setVisible(!drawerOpen); + return super.onPrepareOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + // The action bar home/up action should open or close the drawer. + // ActionBarDrawerToggle will take care of this. + if (mDrawerToggle.onOptionsItemSelected(getMenuItem(item))) { + return true; + } + + // Handle action buttons + switch (item.getItemId()) { + // case R.id.action_websearch: + // // create intent to perform web search for this planet + // Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); + // intent.putExtra(SearchManager.QUERY, getSupportActionBar().getTitle()); + // // catch event that there's no activity to handle intent + // if (intent.resolveActivity(getPackageManager()) != null) { + // startActivity(intent); + // } else { + // Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_LONG).show(); + // } + // return true; + default: + return super.onOptionsItemSelected(item); + } + } + + private android.view.MenuItem getMenuItem(final MenuItem item) { + return new android.view.MenuItem() { + @Override + public int getItemId() { + return item.getItemId(); + } + + public boolean isEnabled() { + return true; + } + + @Override + public boolean collapseActionView() { + return false; + } + + @Override + public boolean expandActionView() { + return false; + } + + @Override + public ActionProvider getActionProvider() { + return null; + } + + @Override + public View getActionView() { + return null; + } + + @Override + public char getAlphabeticShortcut() { + return 0; + } + + @Override + public int getGroupId() { + return 0; + } + + @Override + public Drawable getIcon() { + return null; + } + + @Override + public Intent getIntent() { + return null; + } + + @Override + public ContextMenuInfo getMenuInfo() { + return null; + } + + @Override + public char getNumericShortcut() { + return 0; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public SubMenu getSubMenu() { + return null; + } + + @Override + public CharSequence getTitle() { + return null; + } + + @Override + public CharSequence getTitleCondensed() { + return null; + } + + @Override + public boolean hasSubMenu() { + return false; + } + + @Override + public boolean isActionViewExpanded() { + return false; + } + + @Override + public boolean isCheckable() { + return false; + } + + @Override + public boolean isChecked() { + return false; + } + + @Override + public boolean isVisible() { + return false; + } + + @Override + public android.view.MenuItem setActionProvider(ActionProvider actionProvider) { + return null; + } + + @Override + public android.view.MenuItem setActionView(View view) { + return null; + } + + @Override + public android.view.MenuItem setActionView(int resId) { + return null; + } + + @Override + public android.view.MenuItem setAlphabeticShortcut(char alphaChar) { + return null; + } + + @Override + public android.view.MenuItem setCheckable(boolean checkable) { + return null; + } + + @Override + public android.view.MenuItem setChecked(boolean checked) { + return null; + } + + @Override + public android.view.MenuItem setEnabled(boolean enabled) { + return null; + } + + @Override + public android.view.MenuItem setIcon(Drawable icon) { + return null; + } + + @Override + public android.view.MenuItem setIcon(int iconRes) { + return null; + } + + @Override + public android.view.MenuItem setIntent(Intent intent) { + return null; + } + + @Override + public android.view.MenuItem setNumericShortcut(char numericChar) { + return null; + } + + @Override + public android.view.MenuItem setOnActionExpandListener(OnActionExpandListener listener) { + return null; + } + + @Override + public android.view.MenuItem setOnMenuItemClickListener( + OnMenuItemClickListener menuItemClickListener) { + return null; + } + + @Override + public android.view.MenuItem setShortcut(char numericChar, char alphaChar) { + return null; + } + + @Override + public void setShowAsAction(int actionEnum) { + } + + @Override + public android.view.MenuItem setShowAsActionFlags(int actionEnum) { + return null; + } + + @Override + public android.view.MenuItem setTitle(CharSequence title) { + return null; + } + + @Override + public android.view.MenuItem setTitle(int title) { + return null; + } + + @Override + public android.view.MenuItem setTitleCondensed(CharSequence title) { + return null; + } + + @Override + public android.view.MenuItem setVisible(boolean visible) { + return null; + } + }; + } + + /* The click listner for ListView in the navigation drawer */ + private class DrawerItemClickListener implements ListView.OnItemClickListener { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + selectItem(position); + } + } + + private void selectItem(int position) { + // update the main content by replacing fragments + // Fragment fragment = new PlanetFragment(); + // Bundle args = new Bundle(); + // args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position); + // fragment.setArguments(args); + + // FragmentManager fragmentManager = getSupportFragmentManager(); + // fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit(); + + // update selected item and title, then close the drawer + mDrawerList.setItemChecked(position, true); + // setTitle(mDrawerTitles[position]); + mDrawerLayout.closeDrawer(mDrawerList); + } + + // @Override + // public void setTitle(CharSequence title) { + // mTitle = title; + // getSupportActionBar().setTitle(mTitle); + // } + + /** + * When using the ActionBarDrawerToggle, you must call it during onPostCreate() and + * onConfigurationChanged()... + */ + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + // Sync the toggle state after onRestoreInstanceState has occurred. + mDrawerToggle.syncState(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + // Pass any configuration change to the drawer toggles + mDrawerToggle.onConfigurationChanged(newConfig); + } + + /** + * Fragment that appears in the "content_frame", shows a planet + */ + // public static class PlanetFragment extends SherlockFragment { + // public static final String ARG_PLANET_NUMBER = "planet_number"; + // + // public PlanetFragment() { + // // Empty constructor required for fragment subclasses + // } + // + // @Override + // public View onCreateView(LayoutInflater inflater, ViewGroup container, + // Bundle savedInstanceState) { + // View rootView = inflater.inflate(R.layout.fragment_planet, container, false); + // int i = getArguments().getInt(ARG_PLANET_NUMBER); + // String planet = getResources().getStringArray(R.array.drawer_array)[i]; + // + // int imageId = getResources().getIdentifier(planet.toLowerCase(Locale.getDefault()), + // "drawable", getActivity().getPackageName()); + // ((ImageView) rootView.findViewById(R.id.image)).setImageResource(imageId); + // getActivity().setTitle(planet); + // return rootView; + // } + // } +} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java index 2760df97e..3766b1c42 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java @@ -45,8 +45,7 @@ import com.actionbarsherlock.app.SherlockFragmentActivity; * TODO: get key type by looking at dataUri! * */ -public class KeyActivity extends SherlockFragmentActivity { - +public class KeyActivity extends DrawerActivity { protected FileDialogFragment mFileDialog; protected String mExportFilename; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java index 023c8fd9d..476d3c96c 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java @@ -35,8 +35,8 @@ public class KeyListPublicActivity extends KeyActivity { setContentView(R.layout.key_list_public_activity); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); + // now setup navigation drawer in DrawerActivity... + setupDrawerNavigation(savedInstanceState); } @Override @@ -49,13 +49,6 @@ public class KeyListPublicActivity extends KeyActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case android.R.id.home: - // app icon in Action Bar clicked; go home - Intent intent = new Intent(this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - - return true; case R.id.menu_key_list_public_import: Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class); startActivityForResult(intentImportFromFile, Id.request.import_from_qr_code); -- cgit v1.2.3 From bb161d5fa9d56c5fc7369c979d6fd4eeff187987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 9 Jan 2014 22:58:52 +0100 Subject: implement navigation drawer --- .../service/remote/RegisteredAppsListActivity.java | 31 +-- .../keychain/ui/DecryptActivity.java | 27 ++- .../keychain/ui/DrawerActivity.java | 224 ++++++++++++--------- .../keychain/ui/EncryptActivity.java | 34 ++-- .../keychain/ui/EncryptDecryptActivity.java | 175 ---------------- .../keychain/ui/HelpActivity.java | 44 +--- .../keychain/ui/ImportKeysActivity.java | 29 +-- .../keychain/ui/KeyActivity.java | 4 +- .../keychain/ui/KeyListPublicActivity.java | 4 +- .../keychain/ui/KeyListSecretActivity.java | 15 +- .../keychain/ui/MainActivity.java | 109 ---------- .../keychain/ui/PreferencesActivity.java | 26 +-- .../keychain/ui/SelectSecretKeyActivity.java | 17 -- .../keychain/ui/widget/DashboardLayout.java | 186 ----------------- 14 files changed, 186 insertions(+), 739 deletions(-) delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptDecryptActivity.java delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/MainActivity.java delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/DashboardLayout.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListActivity.java index 4530ac2fc..3c553fff5 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListActivity.java @@ -18,44 +18,19 @@ package org.sufficientlysecure.keychain.service.remote; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.MainActivity; +import org.sufficientlysecure.keychain.ui.DrawerActivity; -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.SherlockFragmentActivity; -import com.actionbarsherlock.view.MenuItem; - -import android.content.Intent; import android.os.Bundle; -public class RegisteredAppsListActivity extends SherlockFragmentActivity { - private ActionBar mActionBar; +public class RegisteredAppsListActivity extends DrawerActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mActionBar = getSupportActionBar(); - setContentView(R.layout.api_apps_list_activity); - mActionBar.setDisplayShowTitleEnabled(true); - mActionBar.setDisplayHomeAsUpEnabled(true); + setupDrawerNavigation(savedInstanceState); } - /** - * Menu Options - */ - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - // app icon in Action Bar clicked; go home - Intent intent = new Intent(this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - default: - return super.onOptionsItemSelected(item); - } - } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DecryptActivity.java index f7fc49083..87229f6c3 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -66,13 +66,12 @@ import android.widget.TextView; import android.widget.Toast; import android.widget.ViewFlipper; -import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; import com.beardedhen.androidbootstrap.BootstrapButton; @SuppressLint("NewApi") -public class DecryptActivity extends SherlockFragmentActivity { +public class DecryptActivity extends DrawerActivity { /* Intents */ // without permission @@ -144,13 +143,6 @@ public class DecryptActivity extends SherlockFragmentActivity { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case android.R.id.home: - // app icon in Action Bar clicked; go home - Intent intent = new Intent(this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - case Id.menu.option.decrypt: { decryptClicked(); @@ -245,6 +237,8 @@ public class DecryptActivity extends SherlockFragmentActivity { initView(); + setupDrawerNavigation(savedInstanceState); + // Handle intent actions handleActions(getIntent()); @@ -262,7 +256,8 @@ public class DecryptActivity extends SherlockFragmentActivity { if (matcher.matches()) { data = matcher.group(1); mMessage.setText(data); - Toast.makeText(this, R.string.using_clipboard_content, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.using_clipboard_content, Toast.LENGTH_SHORT) + .show(); } } } @@ -472,8 +467,9 @@ public class DecryptActivity extends SherlockFragmentActivity { if (!file.exists() || !file.isFile()) { Toast.makeText( this, - getString(R.string.error_message, getString(R.string.error_file_not_found)), - Toast.LENGTH_SHORT).show(); + getString(R.string.error_message, + getString(R.string.error_file_not_found)), Toast.LENGTH_SHORT) + .show(); return; } } @@ -592,7 +588,8 @@ public class DecryptActivity extends SherlockFragmentActivity { } mSecretKeyId = Id.key.symmetric; if (!PgpOperation.hasSymmetricEncryption(this, inStream)) { - throw new PgpGeneralException(getString(R.string.error_no_known_encryption_found)); + throw new PgpGeneralException( + getString(R.string.error_no_known_encryption_found)); } mAssumeSymmetricEncryption = true; } @@ -790,8 +787,8 @@ public class DecryptActivity extends SherlockFragmentActivity { .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN)) { mSignatureStatusImage.setImageResource(R.drawable.overlay_error); Toast.makeText(DecryptActivity.this, - R.string.unknown_signature_key_touch_to_look_up, Toast.LENGTH_LONG) - .show(); + R.string.unknown_signature_key_touch_to_look_up, + Toast.LENGTH_LONG).show(); } else { mSignatureStatusImage.setImageResource(R.drawable.overlay_error); } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java index e278af5e3..db6a3a155 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java @@ -1,26 +1,27 @@ /* - * - * from https://github.com/tobykurien/SherlockNavigationDrawer - * - * Copyright 2013 The Android Open Source Project + * Copyright (C) 2014 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 + * 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.ui; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity; +import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.graphics.drawable.Drawable; @@ -30,45 +31,24 @@ import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.view.ActionProvider; import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; import android.view.SubMenu; import android.view.View; +import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; +import android.widget.TextView; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; +import com.beardedhen.androidbootstrap.FontAwesomeText; /** - * This example illustrates a common usage of the DrawerLayout widget in the Android support - * library. - *

- *

- * When a navigation (left) drawer is present, the host activity should detect presses of the action - * bar's Up affordance as a signal to open and close the navigation drawer. The - * ActionBarDrawerToggle facilitates this behavior. Items within the drawer should fall into one of - * two categories: - *

- *

- *

    - *
  • View switches. A view switch follows the same basic policies as list or tab - * navigation in that a view switch does not create navigation history. This pattern should only be - * used at the root activity of a task, leaving some form of Up navigation active for activities - * further down the navigation hierarchy.
  • - *
  • Selective Up. The drawer allows the user to choose an alternate parent for - * Up navigation. This allows a user to jump across an app's navigation hierarchy at will. The - * application should treat this as it treats Up navigation from a different task, replacing the - * current task stack using TaskStackBuilder or similar. This is the only form of navigation drawer - * that should be used outside of the root activity of a task.
  • - *
- *

- *

- * Right side drawers should be used for actions, not navigation. This follows the pattern - * established by the Action Bar that navigation should be to the left and actions to the right. An - * action should be an operation performed on the current contents of the window, for example - * enabling or disabling a data overlay on top of the current content. - *

+ * some fundamental ideas from https://github.com/tobykurien/SherlockNavigationDrawer + * + * */ public class DrawerActivity extends SherlockFragmentActivity { private DrawerLayout mDrawerLayout; @@ -77,11 +57,14 @@ public class DrawerActivity extends SherlockFragmentActivity { private CharSequence mDrawerTitle; private CharSequence mTitle; - private String[] mDrawerTitles; + + private static Class[] mItemsClass = new Class[] { KeyListPublicActivity.class, + EncryptActivity.class, DecryptActivity.class, ImportKeysActivity.class, + KeyListSecretActivity.class, PreferencesActivity.class, + RegisteredAppsListActivity.class, HelpActivity.class }; protected void setupDrawerNavigation(Bundle savedInstanceState) { - // mTitle = mDrawerTitle = getTitle(); - mDrawerTitles = getResources().getStringArray(R.array.drawer_array); + mDrawerTitle = getString(R.string.app_name); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerList = (ListView) findViewById(R.id.left_drawer); @@ -89,10 +72,31 @@ public class DrawerActivity extends SherlockFragmentActivity { // opens mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); // set up the drawer's list view with items and click listener - mDrawerList.setAdapter(new ArrayAdapter(this, R.layout.drawer_list_item, - mDrawerTitles)); + // mDrawerList + // .setAdapter(new ArrayAdapter(this, R.layout.drawer_list_item, mItemsText)); + + NavItem mItemIconTexts[] = new NavItem[] { + new NavItem("fa-user", getString(R.string.nav_contacts)), + new NavItem("fa-lock", getString(R.string.nav_encrypt)), + new NavItem("fa-unlock", getString(R.string.nav_decrypt)), + new NavItem("fa-download", getString(R.string.nav_import)), + new NavItem("fa-key", getString(R.string.nav_secret_keys)), + new NavItem("fa-wrench", getString(R.string.nav_settings)), + new NavItem("fa-android", getString(R.string.nav_apps)), + new NavItem("fa-question", getString(R.string.nav_help)), }; + + mDrawerList.setAdapter(new NavigationDrawerAdapter(this, R.layout.drawer_list_item, + mItemIconTexts)); + mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); + // + // enable ActionBar app icon to behave as action to toggle nav drawer getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); @@ -107,21 +111,22 @@ public class DrawerActivity extends SherlockFragmentActivity { ) { public void onDrawerClosed(View view) { getSupportActionBar().setTitle(mTitle); - supportInvalidateOptionsMenu(); // creates call to - // onPrepareOptionsMenu() + // creates call to onPrepareOptionsMenu() + supportInvalidateOptionsMenu(); } public void onDrawerOpened(View drawerView) { + mTitle = getSupportActionBar().getTitle(); getSupportActionBar().setTitle(mDrawerTitle); - supportInvalidateOptionsMenu(); // creates call to - // onPrepareOptionsMenu() + // creates call to onPrepareOptionsMenu() + supportInvalidateOptionsMenu(); } }; mDrawerLayout.setDrawerListener(mDrawerToggle); - if (savedInstanceState == null) { - selectItem(0); - } + // if (savedInstanceState == null) { + // selectItem(0); + // } } /* Called whenever we call invalidateOptionsMenu() */ @@ -142,8 +147,10 @@ public class DrawerActivity extends SherlockFragmentActivity { return true; } + return super.onOptionsItemSelected(item); + // Handle action buttons - switch (item.getItemId()) { + // switch (item.getItemId()) { // case R.id.action_websearch: // // create intent to perform web search for this planet // Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); @@ -155,9 +162,9 @@ public class DrawerActivity extends SherlockFragmentActivity { // Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_LONG).show(); // } // return true; - default: - return super.onOptionsItemSelected(item); - } + // default: + // return super.onOptionsItemSelected(item); + // } } private android.view.MenuItem getMenuItem(final MenuItem item) { @@ -377,32 +384,24 @@ public class DrawerActivity extends SherlockFragmentActivity { } private void selectItem(int position) { - // update the main content by replacing fragments - // Fragment fragment = new PlanetFragment(); - // Bundle args = new Bundle(); - // args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position); - // fragment.setArguments(args); - - // FragmentManager fragmentManager = getSupportFragmentManager(); - // fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit(); - // update selected item and title, then close the drawer mDrawerList.setItemChecked(position, true); // setTitle(mDrawerTitles[position]); mDrawerLayout.closeDrawer(mDrawerList); - } - // @Override - // public void setTitle(CharSequence title) { - // mTitle = title; - // getSupportActionBar().setTitle(mTitle); - // } + finish(); + overridePendingTransition(0, 0); + + Intent intent = new Intent(this, mItemsClass[position]); + startActivity(intent); + // disable animation of activity start + overridePendingTransition(0, 0); + } /** * When using the ActionBarDrawerToggle, you must call it during onPostCreate() and * onConfigurationChanged()... */ - @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); @@ -417,28 +416,59 @@ public class DrawerActivity extends SherlockFragmentActivity { mDrawerToggle.onConfigurationChanged(newConfig); } - /** - * Fragment that appears in the "content_frame", shows a planet - */ - // public static class PlanetFragment extends SherlockFragment { - // public static final String ARG_PLANET_NUMBER = "planet_number"; - // - // public PlanetFragment() { - // // Empty constructor required for fragment subclasses - // } - // - // @Override - // public View onCreateView(LayoutInflater inflater, ViewGroup container, - // Bundle savedInstanceState) { - // View rootView = inflater.inflate(R.layout.fragment_planet, container, false); - // int i = getArguments().getInt(ARG_PLANET_NUMBER); - // String planet = getResources().getStringArray(R.array.drawer_array)[i]; - // - // int imageId = getResources().getIdentifier(planet.toLowerCase(Locale.getDefault()), - // "drawable", getActivity().getPackageName()); - // ((ImageView) rootView.findViewById(R.id.image)).setImageResource(imageId); - // getActivity().setTitle(planet); - // return rootView; - // } - // } + private class NavItem { + public String icon; + public String title; + + public NavItem(String icon, String title) { + super(); + this.icon = icon; + this.title = title; + } + } + + private class NavigationDrawerAdapter extends ArrayAdapter { + Context context; + int layoutResourceId; + NavItem data[] = null; + + public NavigationDrawerAdapter(Context context, int layoutResourceId, NavItem[] data) { + super(context, layoutResourceId, data); + this.layoutResourceId = layoutResourceId; + this.context = context; + this.data = data; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View row = convertView; + NavItemHolder holder = null; + + if (row == null) { + LayoutInflater inflater = ((Activity) context).getLayoutInflater(); + row = inflater.inflate(layoutResourceId, parent, false); + + holder = new NavItemHolder(); + holder.img = (FontAwesomeText) row.findViewById(R.id.drawer_item_icon); + holder.txtTitle = (TextView) row.findViewById(R.id.drawer_item_text); + + row.setTag(holder); + } else { + holder = (NavItemHolder) row.getTag(); + } + + NavItem item = data[position]; + holder.txtTitle.setText(item.title); + holder.img.setIcon(item.icon); + + return row; + } + + } + + static class NavItemHolder { + FontAwesomeText img; + TextView txtTitle; + } + } \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 681548c9b..24caebb3a 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -63,12 +63,11 @@ import android.widget.TextView; import android.widget.Toast; import android.widget.ViewFlipper; -import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; import com.beardedhen.androidbootstrap.BootstrapButton; -public class EncryptActivity extends SherlockFragmentActivity { +public class EncryptActivity extends DrawerActivity { /* Intents */ public static final String ACTION_ENCRYPT = Constants.INTENT_PREFIX + "ENCRYPT"; @@ -153,13 +152,6 @@ public class EncryptActivity extends SherlockFragmentActivity { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case android.R.id.home: - // app icon in Action Bar clicked; go home - Intent intent = new Intent(this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - case Id.menu.option.encrypt_to_clipboard: encryptToClipboardClicked(); @@ -187,6 +179,8 @@ public class EncryptActivity extends SherlockFragmentActivity { initView(); + setupDrawerNavigation(savedInstanceState); + // Handle intent actions handleActions(getIntent()); @@ -491,8 +485,9 @@ public class EncryptActivity extends SherlockFragmentActivity { if (!file.exists() || !file.isFile()) { Toast.makeText( this, - getString(R.string.error_message, getString(R.string.error_file_not_found)), - Toast.LENGTH_SHORT).show(); + getString(R.string.error_message, + getString(R.string.error_file_not_found)), Toast.LENGTH_SHORT) + .show(); return; } } @@ -510,7 +505,8 @@ public class EncryptActivity extends SherlockFragmentActivity { gotPassPhrase = (passPhrase.length() != 0); if (!gotPassPhrase) { - Toast.makeText(this, R.string.passphrase_must_not_be_empty, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.passphrase_must_not_be_empty, Toast.LENGTH_SHORT) + .show(); return; } } else { @@ -522,8 +518,8 @@ public class EncryptActivity extends SherlockFragmentActivity { } if (!encryptIt && mSecretKeyId == 0) { - Toast.makeText(this, R.string.select_encryption_or_signature_key, Toast.LENGTH_SHORT) - .show(); + Toast.makeText(this, R.string.select_encryption_or_signature_key, + Toast.LENGTH_SHORT).show(); return; } @@ -852,10 +848,12 @@ public class EncryptActivity extends SherlockFragmentActivity { Choice[] choices = new Choice[] { new Choice(Id.choice.compression.none, getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")"), - new Choice(Id.choice.compression.zip, "ZIP (" + getString(R.string.compression_fast) + ")"), - new Choice(Id.choice.compression.zlib, "ZLIB (" + getString(R.string.compression_fast) + ")"), - new Choice(Id.choice.compression.bzip2, "BZIP2 (" + getString(R.string.compression_very_slow) - + ")"), }; + new Choice(Id.choice.compression.zip, "ZIP (" + + getString(R.string.compression_fast) + ")"), + new Choice(Id.choice.compression.zlib, "ZLIB (" + + getString(R.string.compression_fast) + ")"), + new Choice(Id.choice.compression.bzip2, "BZIP2 (" + + getString(R.string.compression_very_slow) + ")"), }; ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, choices); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptDecryptActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptDecryptActivity.java deleted file mode 100644 index 7f0184381..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptDecryptActivity.java +++ /dev/null @@ -1,175 +0,0 @@ -package org.sufficientlysecure.keychain.ui; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Log; - -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.ActionBar.Tab; -import com.actionbarsherlock.app.SherlockFragmentActivity; -import com.actionbarsherlock.view.Menu; -import com.actionbarsherlock.view.MenuInflater; -import com.actionbarsherlock.view.MenuItem; - -import android.app.Activity; -import android.content.Intent; -import android.content.res.Configuration; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; - -public class EncryptDecryptActivity extends SherlockFragmentActivity { - private FragmentActivity mActivity; - private ActionBar mActionBar; - private ActionBar.Tab mTab1; - private ActionBar.Tab mTab2; - private ActionBar.Tab mTab3; - - // @Override - // public boolean onCreateOptionsMenu(Menu menu) { - // MenuInflater inflater = getSupportMenuInflater(); - // inflater.inflate(R.menu.lists_activity, menu); - // return true; - // } - - /** - * Menu item to go back home in ActionBar, other menu items are defined in Fragments - */ - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - // app icon in Action Bar clicked; go home - Intent intent = new Intent(mActivity, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - - // case R.id.menu_import: - // ImportExportHelper.openFileStream(mActivity); - // return true; - // - // case R.id.menu_export: - // ImportExportHelper.exportLists(mActivity); - // return true; - - default: - return super.onOptionsItemSelected(item); - } - } - - /** - * Set up Tabs on create - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mActivity = this; - - setContentView(R.layout.lists_activity); - - mActionBar = getSupportActionBar(); - mActionBar.setDisplayShowTitleEnabled(true); - mActionBar.setDisplayHomeAsUpEnabled(true); - - mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); - - mTab1 = getSupportActionBar().newTab(); - mTab2 = getSupportActionBar().newTab(); - mTab3 = getSupportActionBar().newTab(); - - mTab1.setTabListener(new TabListener(this, "publicList", - KeyListPublicFragment.class)); - mTab2.setTabListener(new TabListener(this, "import", - KeyListPublicFragment.class)); - - setTabTextBasedOnOrientation(getResources().getConfiguration()); - - mActionBar.addTab(mTab1); - mActionBar.addTab(mTab2); - // mActionBar.addTab(mTab3); - } - - private void setTabTextBasedOnOrientation(Configuration config) { - // longer names for landscape mode or tablets - // if (config.orientation == Configuration.ORIENTATION_LANDSCAPE - // || config.screenLayout == Configuration.SCREENLAYOUT_SIZE_XLARGE) { - mTab1.setText(getString(R.string.dashboard_manage_keys)); - mTab2.setText(getString(R.string.dashboard_manage_keys)); - - // } else { - // mTab1.setText(getString(R.string.lists_tab_blacklist_short)); - // mTab2.setText(getString(R.string.lists_tab_whitelist_short)); - // mTab3.setText(getString(R.string.lists_tab_redirection_list_short)); - // } - } - - /** - * Change text on orientation change - */ - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - setTabTextBasedOnOrientation(newConfig); - } - - public static class TabListener implements ActionBar.TabListener { - private Fragment mFragment; - private final Activity mActivity; - private final String mTag; - private final Class mClass; - - /** - * Constructor used each time a new tab is created. - * - * @param activity - * The host Activity, used to instantiate the fragment - * @param tag - * The identifier tag for the fragment - * @param clz - * The fragment's Class, used to instantiate the fragment - */ - public TabListener(Activity activity, String tag, Class clz) { - mActivity = activity; - mTag = tag; - mClass = clz; - } - - @Override - public void onTabReselected(Tab tab, FragmentTransaction ft) { - } - - /** - * Open Fragment based on selected Tab - */ - @Override - public void onTabSelected(Tab tab, FragmentTransaction ignoredFt) { - // bug in compatibility lib: - // http://stackoverflow.com/questions/8645549/null-fragmenttransaction-being-passed-to-tablistener-ontabselected - FragmentManager fragMgr = ((FragmentActivity) mActivity).getSupportFragmentManager(); - FragmentTransaction ft = fragMgr.beginTransaction(); - - mFragment = Fragment.instantiate(mActivity, mClass.getName()); - ft.replace(R.id.lists_tabs_container, mFragment, mTag); - ft.commit(); - } - - @Override - public void onTabUnselected(Tab tab, FragmentTransaction ignoredFt) { - FragmentManager fragMgr = ((FragmentActivity) mActivity).getSupportFragmentManager(); - FragmentTransaction ft = fragMgr.beginTransaction(); - - if (mFragment != null) { - // Remove the fragment - ft.remove(mFragment); - } - - ft.commit(); - } - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/HelpActivity.java index 13350b6c6..7407564a9 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/HelpActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/HelpActivity.java @@ -17,27 +17,24 @@ package org.sufficientlysecure.keychain.ui; +import java.util.ArrayList; + import org.sufficientlysecure.keychain.R; +import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.app.FragmentTransaction; +import android.support.v4.view.ViewPager; import android.widget.TextView; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.ActionBar.Tab; -import com.actionbarsherlock.view.MenuItem; - -import java.util.ArrayList; - -import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentPagerAdapter; -import android.support.v4.view.ViewPager; - import com.actionbarsherlock.app.SherlockFragmentActivity; -public class HelpActivity extends SherlockFragmentActivity { +public class HelpActivity extends DrawerActivity { public static final String EXTRA_SELECTED_TAB = "selectedTab"; ViewPager mViewPager; @@ -45,37 +42,18 @@ public class HelpActivity extends SherlockFragmentActivity { TextView tabCenter; TextView tabText; - /** - * Menu Items - */ - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - // app icon in Action Bar clicked; go home - Intent intent = new Intent(this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + setContentView(R.layout.help_activity); - mViewPager = new ViewPager(this); - mViewPager.setId(R.id.pager); + mViewPager = (ViewPager) findViewById(R.id.pager); + + setupDrawerNavigation(savedInstanceState); - setContentView(mViewPager); ActionBar bar = getSupportActionBar(); bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); - bar.setDisplayShowTitleEnabled(true); - bar.setDisplayHomeAsUpEnabled(true); mTabsAdapter = new TabsAdapter(this, mViewPager); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 94b5304a1..1842364e7 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -22,7 +22,6 @@ import java.util.List; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; @@ -51,11 +50,9 @@ import android.widget.Toast; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.ActionBar.OnNavigationListener; -import com.actionbarsherlock.app.SherlockFragmentActivity; -import com.actionbarsherlock.view.MenuItem; import com.beardedhen.androidbootstrap.BootstrapButton; -public class ImportKeysActivity extends SherlockFragmentActivity implements OnNavigationListener { +public class ImportKeysActivity extends DrawerActivity implements OnNavigationListener { public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY"; public static final String ACTION_IMPORT_KEY_FROM_QR_CODE = Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_QR_CODE"; @@ -103,8 +100,12 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa } }); + getSupportActionBar().setDisplayShowTitleEnabled(false); + + setupDrawerNavigation(savedInstanceState); + // set actionbar without home button if called from another app - ActionBarHelper.setBackButton(this); + // ActionBarHelper.setBackButton(this); // set drop down navigation mNavigationStrings = getResources().getStringArray(R.array.import_action_list); @@ -114,7 +115,6 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa list.setDropDownViewResource(R.layout.sherlock_spinner_dropdown_item); getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); getSupportActionBar().setListNavigationCallbacks(list, this); - getSupportActionBar().setDisplayShowTitleEnabled(false); handleActions(savedInstanceState, getIntent()); } @@ -240,23 +240,6 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa mListFragment.loadNew(importData, importFilename); } - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - - case android.R.id.home: - // app icon in Action Bar clicked; go home - Intent intent = new Intent(this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - - default: - return super.onOptionsItemSelected(item); - - } - } - // private void importAndSignOld(final long keyId, final String expectedFingerprint) { // if (expectedFingerprint != null && expectedFingerprint.length() > 0) { // diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java index 3766b1c42..91481d2b4 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Dominik Schürmann + * Copyright (C) 2013-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 @@ -37,8 +37,6 @@ import android.os.Message; import android.os.Messenger; import android.widget.Toast; -import com.actionbarsherlock.app.SherlockFragmentActivity; - /** * This implements export key method and delete key method. Used in lists and key view and key edit. * diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java index 476d3c96c..cb04ddf0d 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java @@ -50,8 +50,8 @@ public class KeyListPublicActivity extends KeyActivity { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_key_list_public_import: - Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class); - startActivityForResult(intentImportFromFile, Id.request.import_from_qr_code); + Intent intentImport = new Intent(this, ImportKeysActivity.class); + startActivityForResult(intentImport, Id.request.import_from_qr_code); return true; case R.id.menu_key_list_public_export: diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java index d95f03ae1..747055a47 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java @@ -35,8 +35,8 @@ public class KeyListSecretActivity extends KeyActivity { setContentView(R.layout.key_list_secret_activity); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); + // now setup navigation drawer in DrawerActivity... + setupDrawerNavigation(savedInstanceState); } @Override @@ -49,13 +49,6 @@ public class KeyListSecretActivity extends KeyActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case android.R.id.home: - // app icon in Action Bar clicked; go home - Intent intent = new Intent(this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - - return true; case R.id.menu_key_list_secret_create: createKey(); @@ -70,8 +63,8 @@ public class KeyListSecretActivity extends KeyActivity { return true; case R.id.menu_key_list_secret_import: - Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class); - startActivityForResult(intentImportFromFile, Id.request.import_from_qr_code); + Intent intentImport = new Intent(this, ImportKeysActivity.class); + startActivityForResult(intentImport, Id.request.import_from_qr_code); return true; default: diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/MainActivity.java deleted file mode 100644 index 9a270e60b..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/MainActivity.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2012-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; - -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity; - -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.SherlockActivity; -import com.actionbarsherlock.view.Menu; -import com.actionbarsherlock.view.MenuItem; - -import android.content.Intent; -import android.os.Bundle; -import android.view.View; - -public class MainActivity extends SherlockActivity { - - public void manageKeysOnClick(View view) { - // used instead of startActivity set actionbar based on callingPackage - startActivityForResult(new Intent(this, KeyListPublicActivity.class), 0); - } - - public void myKeysOnClick(View view) { - // used instead of startActivity set actionbar based on callingPackage - startActivityForResult(new Intent(this, KeyListSecretActivity.class), 0); - } - - public void encryptOnClick(View view) { - Intent intent = new Intent(MainActivity.this, EncryptActivity.class); - intent.setAction(EncryptActivity.ACTION_ENCRYPT); - // used instead of startActivity set actionbar based on callingPackage - startActivityForResult(intent, 0); - } - - public void decryptOnClick(View view) { - Intent intent = new Intent(MainActivity.this, DecryptActivity.class); - intent.setAction(DecryptActivity.ACTION_DECRYPT); - // used instead of startActivity set actionbar based on callingPackage - startActivityForResult(intent, 0); - } - - public void scanQrcodeOnClick(View view) { - Intent intent = new Intent(this, ImportKeysActivity.class); - startActivityForResult(intent, 0); - } - - public void helpOnClick(View view) { - startActivity(new Intent(this, HelpActivity.class)); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main); - - final ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(false); - actionBar.setHomeButtonEnabled(false); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - menu.add(0, Id.menu.option.preferences, 0, R.string.menu_preferences) - .setIcon(R.drawable.ic_menu_settings) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - menu.add(0, Id.menu.option.crypto_consumers, 0, R.string.menu_api_app_settings) - .setIcon(R.drawable.ic_menu_settings) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_WITH_TEXT); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - - case Id.menu.option.preferences: - startActivity(new Intent(this, PreferencesActivity.class)); - return true; - - case Id.menu.option.crypto_consumers: - startActivity(new Intent(this, RegisteredAppsListActivity.class)); - return true; - - default: - break; - - } - return false; - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/PreferencesActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/PreferencesActivity.java index 6607ab4d5..43ad0c93d 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/PreferencesActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/PreferencesActivity.java @@ -20,13 +20,9 @@ import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.openpgp.PGPEncryptedData; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference; -import org.sufficientlysecure.keychain.R; - -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.SherlockPreferenceActivity; -import com.actionbarsherlock.view.MenuItem; import android.content.Intent; import android.os.Bundle; @@ -34,6 +30,9 @@ import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.PreferenceScreen; +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.SherlockPreferenceActivity; + public class PreferencesActivity extends SherlockPreferenceActivity { private IntegerListPreference mPassPhraseCacheTtl = null; private IntegerListPreference mEncryptionAlgorithm = null; @@ -220,21 +219,4 @@ public class PreferencesActivity extends SherlockPreferenceActivity { } } - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - - case android.R.id.home: - // app icon in Action Bar clicked; go home - Intent intent = new Intent(this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - - default: - break; - - } - return false; - } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/SelectSecretKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/SelectSecretKeyActivity.java index b0711ed31..83669a523 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/SelectSecretKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/SelectSecretKeyActivity.java @@ -137,21 +137,4 @@ public class SelectSecretKeyActivity extends SherlockFragmentActivity { return true; } - /** - * Menu Options - */ - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - // app icon in Action Bar clicked; go home - Intent intent = new Intent(this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - - default: - return super.onOptionsItemSelected(item); - } - } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/DashboardLayout.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/DashboardLayout.java deleted file mode 100644 index 158a271bc..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/DashboardLayout.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * 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.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; - -/** - * Custom layout that arranges children in a grid-like manner, optimizing for even horizontal and - * vertical whitespace. - */ -public class DashboardLayout extends ViewGroup { - private static final int UNEVEN_GRID_PENALTY_MULTIPLIER = 10; - - private int mMaxChildWidth = 0; - private int mMaxChildHeight = 0; - - public DashboardLayout(Context context) { - super(context, null); - } - - public DashboardLayout(Context context, AttributeSet attrs) { - super(context, attrs, 0); - } - - public DashboardLayout(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - mMaxChildWidth = 0; - mMaxChildHeight = 0; - - // Measure once to find the maximum child size. - - int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( - MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST); - int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( - MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.AT_MOST); - - final int count = getChildCount(); - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.getVisibility() == GONE) { - continue; - } - - child.measure(childWidthMeasureSpec, childHeightMeasureSpec); - - mMaxChildWidth = Math.max(mMaxChildWidth, child.getMeasuredWidth()); - mMaxChildHeight = Math.max(mMaxChildHeight, child.getMeasuredHeight()); - } - - // Measure again for each child to be exactly the same size. - - childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxChildWidth, MeasureSpec.EXACTLY); - childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxChildHeight, MeasureSpec.EXACTLY); - - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.getVisibility() == GONE) { - continue; - } - - child.measure(childWidthMeasureSpec, childHeightMeasureSpec); - } - - setMeasuredDimension(resolveSize(mMaxChildWidth, widthMeasureSpec), - resolveSize(mMaxChildHeight, heightMeasureSpec)); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - int width = r - l; - int height = b - t; - - final int count = getChildCount(); - - // Calculate the number of visible children. - int visibleCount = 0; - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.getVisibility() == GONE) { - continue; - } - ++visibleCount; - } - - if (visibleCount == 0) { - return; - } - - // Calculate what number of rows and columns will optimize for even horizontal and - // vertical whitespace between items. Start with a 1 x N grid, then try 2 x N, and so on. - int bestSpaceDifference = Integer.MAX_VALUE; - int spaceDifference; - - // Horizontal and vertical space between items - int hSpace = 0; - int vSpace = 0; - - int cols = 1; - int rows; - - while (true) { - rows = (visibleCount - 1) / cols + 1; - - hSpace = ((width - mMaxChildWidth * cols) / (cols + 1)); - vSpace = ((height - mMaxChildHeight * rows) / (rows + 1)); - - spaceDifference = Math.abs(vSpace - hSpace); - if (rows * cols != visibleCount) { - spaceDifference *= UNEVEN_GRID_PENALTY_MULTIPLIER; - } else if (rows * mMaxChildHeight > height || cols * mMaxChildWidth > width) { - spaceDifference *= UNEVEN_GRID_PENALTY_MULTIPLIER; - } - - if (spaceDifference < bestSpaceDifference) { - // Found a better whitespace squareness/ratio - bestSpaceDifference = spaceDifference; - - // If we found a better whitespace squareness and there's only 1 row, this is - // the best we can do. - if (rows == 1) { - break; - } - } else { - // This is a worse whitespace ratio, use the previous value of cols and exit. - --cols; - rows = (visibleCount - 1) / cols + 1; - hSpace = ((width - mMaxChildWidth * cols) / (cols + 1)); - vSpace = ((height - mMaxChildHeight * rows) / (rows + 1)); - break; - } - - ++cols; - } - - // Lay out children based on calculated best-fit number of rows and cols. - - // If we chose a layout that has negative horizontal or vertical space, force it to zero. - hSpace = Math.max(0, hSpace); - vSpace = Math.max(0, vSpace); - - // Re-use width/height variables to be child width/height. - width = (width - hSpace * (cols + 1)) / cols; - height = (height - vSpace * (rows + 1)) / rows; - - int left, top; - int col, row; - int visibleIndex = 0; - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.getVisibility() == GONE) { - continue; - } - - row = visibleIndex / cols; - col = visibleIndex % cols; - - left = hSpace * (col + 1) + width * col; - top = vSpace * (row + 1) + height * row; - - child.layout(left, top, (hSpace == 0 && col == cols - 1) ? r : (left + width), - (vSpace == 0 && row == rows - 1) ? b : (top + height)); - ++visibleIndex; - } - } -} \ No newline at end of file -- cgit v1.2.3 From 37fd7dbbc70d6fc033db4101eaf89bad627fe499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 9 Jan 2014 23:13:23 +0100 Subject: fix bad crashes --- .../keychain/ui/DrawerActivity.java | 10 - .../keychain/ui/EditKeyActivity.java | 19 +- .../keychain/ui/KeyActivity.java | 208 --------------------- .../keychain/ui/KeyListPublicActivity.java | 58 +++--- .../keychain/ui/KeyListSecretActivity.java | 16 +- .../keychain/ui/KeyViewActivity.java | 20 +- 6 files changed, 80 insertions(+), 251 deletions(-) delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java index db6a3a155..2190388b0 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java @@ -71,9 +71,6 @@ public class DrawerActivity extends SherlockFragmentActivity { // set a custom shadow that overlays the main content when the drawer // opens mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); - // set up the drawer's list view with items and click listener - // mDrawerList - // .setAdapter(new ArrayAdapter(this, R.layout.drawer_list_item, mItemsText)); NavItem mItemIconTexts[] = new NavItem[] { new NavItem("fa-user", getString(R.string.nav_contacts)), @@ -90,13 +87,6 @@ public class DrawerActivity extends SherlockFragmentActivity { mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); - // - // enable ActionBar app icon to behave as action to toggle nav drawer getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 569a16c41..b79200ba1 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -27,6 +27,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.ActionBarHelper; +import org.sufficientlysecure.keychain.helper.ExportHelper; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; @@ -61,11 +62,12 @@ import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.LinearLayout; import android.widget.Toast; +import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; import com.beardedhen.androidbootstrap.BootstrapButton; -public class EditKeyActivity extends KeyActivity { +public class EditKeyActivity extends SherlockFragmentActivity { // Actions for internal use only: public static final String ACTION_CREATE_KEY = Constants.INTENT_PREFIX + "CREATE_KEY"; @@ -100,10 +102,14 @@ public class EditKeyActivity extends KeyActivity { Vector mKeysUsages; boolean masterCanSign = true; + ExportHelper mExportHelper; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mExportHelper = new ExportHelper(this); + mUserIds = new Vector(); mKeys = new Vector(); mKeysUsages = new Vector(); @@ -322,7 +328,7 @@ public class EditKeyActivity extends KeyActivity { cancelClicked(); return true; case R.id.menu_key_edit_export_file: - showExportKeysDialog(mDataUri, Id.type.secret_key, Constants.path.APP_DIR + mExportHelper.showExportKeysDialog(mDataUri, Id.type.secret_key, Constants.path.APP_DIR + "/secexport.asc"); return true; case R.id.menu_key_edit_delete: { @@ -337,7 +343,7 @@ public class EditKeyActivity extends KeyActivity { } }; - deleteKey(mDataUri, Id.type.secret_key, returnHandler); + mExportHelper.deleteKey(mDataUri, Id.type.secret_key, returnHandler); return true; } } @@ -656,4 +662,11 @@ public class EditKeyActivity extends KeyActivity { mChangePassPhrase.setText(isPassphraseSet() ? getString(R.string.btn_change_passphrase) : getString(R.string.btn_set_passphrase)); } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (!mExportHelper.handleActivityResult(requestCode, resultCode, data)) { + super.onActivityResult(requestCode, resultCode, data); + } + } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java deleted file mode 100644 index 91481d2b4..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyActivity.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2013-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 org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; -import org.sufficientlysecure.keychain.util.Log; - -import android.app.ProgressDialog; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.widget.Toast; - -/** - * This implements export key method and delete key method. Used in lists and key view and key edit. - * - * TODO: get key type by looking at dataUri! - * - */ -public class KeyActivity extends DrawerActivity { - protected FileDialogFragment mFileDialog; - protected String mExportFilename; - - protected void deleteKey(Uri dataUri, final int keyType, Handler deleteHandler) { - long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment()); - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(deleteHandler); - - DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, - new long[] { keyRingRowId }, keyType); - - deleteKeyDialog.show(getSupportFragmentManager(), "deleteKeyDialog"); - } - - /** - * Show dialog where to export keys - * - * @param keyRingMasterKeyId - * if -1 export all keys - */ - public void showExportKeysDialog(final Uri dataUri, final int keyType, - final String exportFilename) { - mExportFilename = exportFilename; - - // Message is received after file is selected - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == FileDialogFragment.MESSAGE_OKAY) { - Bundle data = message.getData(); - mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME); - - long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment()); - - // TODO? - long keyRingMasterKeyId = ProviderHelper.getSecretMasterKeyId(KeyActivity.this, - keyRingRowId); - - exportKeys(keyRingMasterKeyId, keyType); - } - } - }; - - // Create a new Messenger for the communication back - final Messenger messenger = new Messenger(returnHandler); - - DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { - public void run() { - String title = null; - if (dataUri != null) { - // single key export - title = getString(R.string.title_export_key); - } else { - title = getString(R.string.title_export_keys); - } - - String message = null; - if (keyType == Id.type.public_key) { - message = getString(R.string.specify_file_to_export_to); - } else { - message = getString(R.string.specify_file_to_export_secret_keys_to); - } - - mFileDialog = FileDialogFragment.newInstance(messenger, title, message, - exportFilename, null, Id.request.filename); - - mFileDialog.show(getSupportFragmentManager(), "fileDialog"); - } - }); - } - - /** - * Export keys - * - * @param keyRingMasterKeyId - * if -1 export all keys - */ - public void exportKeys(long keyRingMasterKeyId, int keyType) { - Log.d(Constants.TAG, "exportKeys started"); - - // Send all information needed to service to export key in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_EXPORT_KEYRING); - - // fill values for this action - Bundle data = new Bundle(); - - data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename); - data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, keyType); - - if (keyRingMasterKeyId == -1) { - data.putBoolean(KeychainIntentService.EXPORT_ALL, true); - } else { - data.putLong(KeychainIntentService.EXPORT_KEY_RING_MASTER_KEY_ID, keyRingMasterKeyId); - } - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after exporting is done in ApgService - KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(this, - R.string.progress_exporting, ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard ApgHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - // get returned data bundle - Bundle returnData = message.getData(); - - int exported = returnData.getInt(KeychainIntentService.RESULT_EXPORT); - String toastMessage; - if (exported == 1) { - toastMessage = getString(R.string.key_exported); - } else if (exported > 0) { - toastMessage = getString(R.string.keys_exported, exported); - } else { - toastMessage = getString(R.string.no_keys_exported); - } - Toast.makeText(KeyActivity.this, toastMessage, Toast.LENGTH_SHORT).show(); - - } - }; - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(exportHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - exportHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case Id.request.filename: { - if (resultCode == RESULT_OK && data != null) { - try { - String path = data.getData().getPath(); - Log.d(Constants.TAG, "path=" + path); - - // set filename used in export/import dialogs - mFileDialog.setFilename(path); - } catch (NullPointerException e) { - Log.e(Constants.TAG, "Nullpointer while retrieving path!", e); - } - } - return; - } - - default: { - break; - } - } - super.onActivityResult(requestCode, resultCode, data); - } -} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java index cb04ddf0d..204939610 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.ExportHelper; import android.content.Intent; import android.os.Bundle; @@ -27,12 +28,16 @@ import android.os.Bundle; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; -public class KeyListPublicActivity extends KeyActivity { +public class KeyListPublicActivity extends DrawerActivity { + + ExportHelper mExportHelper; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mExportHelper = new ExportHelper(this); + setContentView(R.layout.key_list_public_activity); // now setup navigation drawer in DrawerActivity... @@ -55,7 +60,7 @@ public class KeyListPublicActivity extends KeyActivity { return true; case R.id.menu_key_list_public_export: - showExportKeysDialog(null, Id.type.public_key, Constants.path.APP_DIR + mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.path.APP_DIR + "/pubexport.asc"); return true; @@ -64,27 +69,30 @@ public class KeyListPublicActivity extends KeyActivity { } } - // @Override - // protected void onActivityResult(int requestCode, int resultCode, Intent data) { - // switch (requestCode) { - // case Id.request.look_up_key_id: { - // if (resultCode == RESULT_CANCELED || data == null - // || data.getStringExtra(KeyServerQueryActivity.RESULT_EXTRA_TEXT) == null) { - // return; - // } - // - // Intent intent = new Intent(this, KeyListPublicActivity.class); - // intent.setAction(KeyListPublicActivity.ACTION_IMPORT); - // intent.putExtra(KeyListPublicActivity.EXTRA_TEXT, - // data.getStringExtra(KeyListActivity.EXTRA_TEXT)); - // handleActions(intent); - // break; - // } - // - // default: { - // super.onActivityResult(requestCode, resultCode, data); - // break; - // } - // } - // } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (!mExportHelper.handleActivityResult(requestCode, resultCode, data)) { + super.onActivityResult(requestCode, resultCode, data); + } + // switch (requestCode) { + // case Id.request.look_up_key_id: { + // if (resultCode == RESULT_CANCELED || data == null + // || data.getStringExtra(KeyServerQueryActivity.RESULT_EXTRA_TEXT) == null) { + // return; + // } + // + // Intent intent = new Intent(this, KeyListPublicActivity.class); + // intent.setAction(KeyListPublicActivity.ACTION_IMPORT); + // intent.putExtra(KeyListPublicActivity.EXTRA_TEXT, + // data.getStringExtra(KeyListActivity.EXTRA_TEXT)); + // handleActions(intent); + // break; + // } + // + // default: { + // super.onActivityResult(requestCode, resultCode, data); + // break; + // } + // } + } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java index 747055a47..34a053d25 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.ExportHelper; import android.content.Intent; import android.os.Bundle; @@ -27,12 +28,16 @@ import android.os.Bundle; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; -public class KeyListSecretActivity extends KeyActivity { +public class KeyListSecretActivity extends DrawerActivity { + + ExportHelper mExportHelper; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mExportHelper = new ExportHelper(this); + setContentView(R.layout.key_list_secret_activity); // now setup navigation drawer in DrawerActivity... @@ -58,7 +63,7 @@ public class KeyListSecretActivity extends KeyActivity { return true; case R.id.menu_key_list_secret_export: - showExportKeysDialog(null, Id.type.secret_key, Constants.path.APP_DIR + mExportHelper.showExportKeysDialog(null, Id.type.secret_key, Constants.path.APP_DIR + "/secexport.asc"); return true; @@ -86,4 +91,11 @@ public class KeyListSecretActivity extends KeyActivity { startActivityForResult(intent, 0); } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (!mExportHelper.handleActivityResult(requestCode, resultCode, data)) { + super.onActivityResult(requestCode, resultCode, data); + } + } + } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java index fb04bb1f8..0e1e20cce 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java @@ -29,6 +29,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; 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.ProviderHelper; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; @@ -55,13 +56,17 @@ import android.view.View.OnClickListener; import android.widget.TextView; import android.widget.Toast; +import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; import com.beardedhen.androidbootstrap.BootstrapButton; @SuppressLint("NewApi") -public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCallback, +public class KeyViewActivity extends SherlockFragmentActivity implements CreateNdefMessageCallback, OnNdefPushCompleteCallback { + + ExportHelper mExportHelper; + private Uri mDataUri; private PGPPublicKey mPublicKey; @@ -81,6 +86,8 @@ public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCal protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mExportHelper = new ExportHelper(this); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); @@ -125,7 +132,7 @@ public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCal uploadToKeyserver(mDataUri); return true; case R.id.menu_key_view_export_file: - showExportKeysDialog(mDataUri, Id.type.public_key, Constants.path.APP_DIR + mExportHelper.showExportKeysDialog(mDataUri, Id.type.public_key, Constants.path.APP_DIR + "/pubexport.asc"); return true; case R.id.menu_key_view_share_default: @@ -152,7 +159,7 @@ public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCal } }; - deleteKey(mDataUri, Id.type.public_key, returnHandler); + mExportHelper.deleteKey(mDataUri, Id.type.public_key, returnHandler); return true; } } @@ -373,4 +380,11 @@ public class KeyViewActivity extends KeyActivity implements CreateNdefMessageCal } }; + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (!mExportHelper.handleActivityResult(requestCode, resultCode, data)) { + super.onActivityResult(requestCode, resultCode, data); + } + } + } -- cgit v1.2.3 From 3abad09cb0f755a53b47a239c4738b4d1718abfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 9 Jan 2014 23:51:23 +0100 Subject: preferences and help into menu not drawer according to guidelines and google apps --- .../keychain/helper/ExportHelper.java | 205 +++++++++++++++++++++ .../keychain/ui/DrawerActivity.java | 35 +++- .../keychain/ui/HelpActivity.java | 19 +- .../keychain/ui/PreferencesActivity.java | 5 +- 4 files changed, 245 insertions(+), 19 deletions(-) create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/ExportHelper.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/ExportHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/ExportHelper.java new file mode 100644 index 000000000..261e26be6 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/ExportHelper.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2014 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.helper; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; +import org.sufficientlysecure.keychain.util.Log; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; +import android.widget.Toast; + +import com.actionbarsherlock.app.SherlockFragmentActivity; + +public class ExportHelper { + protected FileDialogFragment mFileDialog; + protected String mExportFilename; + + SherlockFragmentActivity activity; + + public ExportHelper(SherlockFragmentActivity activity) { + super(); + this.activity = activity; + } + + public void deleteKey(Uri dataUri, final int keyType, Handler deleteHandler) { + long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment()); + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(deleteHandler); + + DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, + new long[] { keyRingRowId }, keyType); + + deleteKeyDialog.show(activity.getSupportFragmentManager(), "deleteKeyDialog"); + } + + /** + * Show dialog where to export keys + * + * @param keyRingMasterKeyId + * if -1 export all keys + */ + public void showExportKeysDialog(final Uri dataUri, final int keyType, + final String exportFilename) { + mExportFilename = exportFilename; + + // Message is received after file is selected + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == FileDialogFragment.MESSAGE_OKAY) { + Bundle data = message.getData(); + mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME); + + long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment()); + + // TODO? + long keyRingMasterKeyId = ProviderHelper.getSecretMasterKeyId(activity, + keyRingRowId); + + exportKeys(keyRingMasterKeyId, keyType); + } + } + }; + + // Create a new Messenger for the communication back + final Messenger messenger = new Messenger(returnHandler); + + DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { + public void run() { + String title = null; + if (dataUri != null) { + // single key export + title = activity.getString(R.string.title_export_key); + } else { + title = activity.getString(R.string.title_export_keys); + } + + String message = null; + if (keyType == Id.type.public_key) { + message = activity.getString(R.string.specify_file_to_export_to); + } else { + message = activity.getString(R.string.specify_file_to_export_secret_keys_to); + } + + mFileDialog = FileDialogFragment.newInstance(messenger, title, message, + exportFilename, null, Id.request.filename); + + mFileDialog.show(activity.getSupportFragmentManager(), "fileDialog"); + } + }); + } + + /** + * Export keys + * + * @param keyRingMasterKeyId + * if -1 export all keys + */ + public void exportKeys(long keyRingMasterKeyId, int keyType) { + Log.d(Constants.TAG, "exportKeys started"); + + // Send all information needed to service to export key in other thread + Intent intent = new Intent(activity, KeychainIntentService.class); + + intent.setAction(KeychainIntentService.ACTION_EXPORT_KEYRING); + + // fill values for this action + Bundle data = new Bundle(); + + data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename); + data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, keyType); + + if (keyRingMasterKeyId == -1) { + data.putBoolean(KeychainIntentService.EXPORT_ALL, true); + } else { + data.putLong(KeychainIntentService.EXPORT_KEY_RING_MASTER_KEY_ID, keyRingMasterKeyId); + } + + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Message is received after exporting is done in ApgService + KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(activity, + R.string.progress_exporting, ProgressDialog.STYLE_HORIZONTAL) { + public void handleMessage(Message message) { + // handle messages by standard ApgHandler first + super.handleMessage(message); + + if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { + // get returned data bundle + Bundle returnData = message.getData(); + + int exported = returnData.getInt(KeychainIntentService.RESULT_EXPORT); + String toastMessage; + if (exported == 1) { + toastMessage = activity.getString(R.string.key_exported); + } else if (exported > 0) { + toastMessage = activity.getString(R.string.keys_exported, exported); + } else { + toastMessage = activity.getString(R.string.no_keys_exported); + } + Toast.makeText(activity, toastMessage, Toast.LENGTH_SHORT).show(); + + } + }; + }; + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(exportHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // show progress dialog + exportHandler.showProgressDialog(activity); + + // start service with intent + activity.startService(intent); + } + + public boolean handleActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == Id.request.filename) { + if (resultCode == Activity.RESULT_OK && data != null) { + try { + String path = data.getData().getPath(); + Log.d(Constants.TAG, "path=" + path); + + // set filename used in export/import dialogs + mFileDialog.setFilename(path); + } catch (NullPointerException e) { + Log.e(Constants.TAG, "Nullpointer while retrieving path!", e); + } + } + return true; + } + + return false; + } +} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java index 2190388b0..ee8a01432 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DrawerActivity.java @@ -60,8 +60,10 @@ public class DrawerActivity extends SherlockFragmentActivity { private static Class[] mItemsClass = new Class[] { KeyListPublicActivity.class, EncryptActivity.class, DecryptActivity.class, ImportKeysActivity.class, - KeyListSecretActivity.class, PreferencesActivity.class, - RegisteredAppsListActivity.class, HelpActivity.class }; + KeyListSecretActivity.class, RegisteredAppsListActivity.class }; + + private static final int MENU_ID_PREFERENCE = 222; + private static final int MENU_ID_HELP = 223; protected void setupDrawerNavigation(Bundle savedInstanceState) { mDrawerTitle = getString(R.string.app_name); @@ -78,9 +80,7 @@ public class DrawerActivity extends SherlockFragmentActivity { new NavItem("fa-unlock", getString(R.string.nav_decrypt)), new NavItem("fa-download", getString(R.string.nav_import)), new NavItem("fa-key", getString(R.string.nav_secret_keys)), - new NavItem("fa-wrench", getString(R.string.nav_settings)), - new NavItem("fa-android", getString(R.string.nav_apps)), - new NavItem("fa-question", getString(R.string.nav_help)), }; + new NavItem("fa-android", getString(R.string.nav_apps)) }; mDrawerList.setAdapter(new NavigationDrawerAdapter(this, R.layout.drawer_list_item, mItemIconTexts)); @@ -119,6 +119,14 @@ public class DrawerActivity extends SherlockFragmentActivity { // } } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + menu.add(42, MENU_ID_PREFERENCE, 100, R.string.menu_preferences); + menu.add(42, MENU_ID_HELP, 101, R.string.menu_help); + + return super.onCreateOptionsMenu(menu); + } + /* Called whenever we call invalidateOptionsMenu() */ @Override public boolean onPrepareOptionsMenu(Menu menu) { @@ -137,7 +145,20 @@ public class DrawerActivity extends SherlockFragmentActivity { return true; } - return super.onOptionsItemSelected(item); + switch (item.getItemId()) { + case MENU_ID_PREFERENCE: { + Intent intent = new Intent(this, PreferencesActivity.class); + startActivity(intent); + return true; + } + case MENU_ID_HELP: { + Intent intent = new Intent(this, HelpActivity.class); + startActivity(intent); + return true; + } + default: + return super.onOptionsItemSelected(item); + } // Handle action buttons // switch (item.getItemId()) { @@ -365,7 +386,7 @@ public class DrawerActivity extends SherlockFragmentActivity { }; } - /* The click listner for ListView in the navigation drawer */ + /* The click listener for ListView in the navigation drawer */ private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/HelpActivity.java index 7407564a9..d604c1c86 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/HelpActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/HelpActivity.java @@ -34,7 +34,7 @@ import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.ActionBar.Tab; import com.actionbarsherlock.app.SherlockFragmentActivity; -public class HelpActivity extends DrawerActivity { +public class HelpActivity extends SherlockFragmentActivity { public static final String EXTRA_SELECTED_TAB = "selectedTab"; ViewPager mViewPager; @@ -50,10 +50,11 @@ public class HelpActivity extends DrawerActivity { mViewPager = (ViewPager) findViewById(R.id.pager); - setupDrawerNavigation(savedInstanceState); - - ActionBar bar = getSupportActionBar(); - bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + final ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(false); + actionBar.setHomeButtonEnabled(false); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); mTabsAdapter = new TabsAdapter(this, mViewPager); @@ -65,20 +66,20 @@ public class HelpActivity extends DrawerActivity { Bundle startBundle = new Bundle(); startBundle.putInt(HelpFragmentHtml.ARG_HTML_FILE, R.raw.help_start); - mTabsAdapter.addTab(bar.newTab().setText(getString(R.string.help_tab_start)), + mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_start)), HelpFragmentHtml.class, startBundle, (selectedTab == 0 ? true : false)); Bundle nfcBundle = new Bundle(); nfcBundle.putInt(HelpFragmentHtml.ARG_HTML_FILE, R.raw.help_nfc_beam); - mTabsAdapter.addTab(bar.newTab().setText(getString(R.string.help_tab_nfc_beam)), + mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_nfc_beam)), HelpFragmentHtml.class, nfcBundle, (selectedTab == 1 ? true : false)); Bundle changelogBundle = new Bundle(); changelogBundle.putInt(HelpFragmentHtml.ARG_HTML_FILE, R.raw.help_changelog); - mTabsAdapter.addTab(bar.newTab().setText(getString(R.string.help_tab_changelog)), + mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_changelog)), HelpFragmentHtml.class, changelogBundle, (selectedTab == 2 ? true : false)); - mTabsAdapter.addTab(bar.newTab().setText(getString(R.string.help_tab_about)), + mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_about)), HelpFragmentAbout.class, null, (selectedTab == 3 ? true : false)); } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/PreferencesActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/PreferencesActivity.java index 43ad0c93d..46bbd05c9 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/PreferencesActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/PreferencesActivity.java @@ -51,8 +51,8 @@ public class PreferencesActivity extends SherlockPreferenceActivity { final ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayShowTitleEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setHomeButtonEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(false); + actionBar.setHomeButtonEnabled(false); addPreferencesFromResource(R.xml.preferences); @@ -218,5 +218,4 @@ public class PreferencesActivity extends SherlockPreferenceActivity { } } } - } -- cgit v1.2.3 From 100ae50e02ef3dfd0330a6e1e7084726ddea69a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 12 Jan 2014 21:33:37 +0100 Subject: cleanup layouts, prepare layouts for new key view --- .../keychain/ui/DecryptActivity.java | 2 +- .../keychain/ui/EditKeyActivity.java | 2 +- .../keychain/ui/EncryptActivity.java | 2 +- .../keychain/ui/HelpFragmentAbout.java | 2 +- .../keychain/ui/ImportKeysActivity.java | 2 +- .../keychain/ui/KeyListPublicFragment.java | 2 +- .../keychain/ui/KeyServerQueryActivity.java | 2 +- .../keychain/ui/KeyServerUploadActivity.java | 2 +- .../keychain/ui/KeyViewActivity.java | 390 -------------------- .../keychain/ui/SignKeyActivity.java | 2 +- .../keychain/ui/ViewKeyActivity.java | 396 +++++++++++++++++++++ .../keychain/ui/adapter/KeyListPublicAdapter.java | 2 +- .../keychain/ui/adapter/ViewKeyUserIdsAdapter.java | 81 +++++ .../ui/dialog/PassphraseDialogFragment.java | 2 +- .../ui/dialog/SetPassphraseDialogFragment.java | 2 +- .../keychain/ui/widget/SectionView.java | 2 +- 16 files changed, 490 insertions(+), 403 deletions(-) delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DecryptActivity.java index 87229f6c3..6cc0b3b5a 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -230,7 +230,7 @@ public class DecryptActivity extends DrawerActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.decrypt); + setContentView(R.layout.decrypt_activity); // set actionbar without home button if called from another app ActionBarHelper.setBackButton(this); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index b79200ba1..be2e4115b 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -429,7 +429,7 @@ public class EditKeyActivity extends SherlockFragmentActivity { * id and key. */ private void buildLayout() { - setContentView(R.layout.edit_key); + setContentView(R.layout.edit_key_activity); // find views mChangePassPhrase = (BootstrapButton) findViewById(R.id.edit_key_btn_change_pass_phrase); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 24caebb3a..c974dfd46 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -172,7 +172,7 @@ public class EncryptActivity extends DrawerActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.encrypt); + setContentView(R.layout.encrypt_activity); // set actionbar without home button if called from another app ActionBarHelper.setBackButton(this); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/HelpFragmentAbout.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/HelpFragmentAbout.java index e7a977707..840ebb650 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/HelpFragmentAbout.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/HelpFragmentAbout.java @@ -48,7 +48,7 @@ public class HelpFragmentAbout extends SherlockFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.help_fragment_about, container, false); + View view = inflater.inflate(R.layout.help_about_fragment, container, false); TextView versionText = (TextView) view.findViewById(R.id.help_about_version); versionText.setText(getString(R.string.help_about_version) + " " + getVersion()); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 1842364e7..7d8f4154f 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -83,7 +83,7 @@ public class ImportKeysActivity extends DrawerActivity implements OnNavigationLi protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.import_keys); + setContentView(R.layout.import_keys_activity); mImportButton = (BootstrapButton) findViewById(R.id.import_import); mImportButton.setOnClickListener(new OnClickListener() { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index 88503a5c4..ea088efca 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -259,7 +259,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte */ @Override public void onItemClick(AdapterView adapterView, View view, int position, long id) { - Intent detailsIntent = new Intent(getActivity(), KeyViewActivity.class); + Intent detailsIntent = new Intent(getActivity(), ViewKeyActivity.class); detailsIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long.toString(id))); startActivity(detailsIntent); } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyServerQueryActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyServerQueryActivity.java index b4679f9d5..6073e6b80 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyServerQueryActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyServerQueryActivity.java @@ -111,7 +111,7 @@ public class KeyServerQueryActivity extends SherlockFragmentActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.key_server_query_layout); + setContentView(R.layout.key_server_query); mQuery = (EditText)findViewById(R.id.query); mSearch = (Button)findViewById(R.id.btn_search); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyServerUploadActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyServerUploadActivity.java index 996637c7a..8a32ea513 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyServerUploadActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyServerUploadActivity.java @@ -76,7 +76,7 @@ public class KeyServerUploadActivity extends SherlockFragmentActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.key_server_export_layout); + setContentView(R.layout.key_server_export); export = (Button) findViewById(R.id.btn_export_to_server); keyServer = (Spinner) findViewById(R.id.keyServer); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java deleted file mode 100644 index 0e1e20cce..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyViewActivity.java +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * Copyright (C) 2013 Bahtiar 'kalkin' Gadimov - * - * 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 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; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -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.ProviderHelper; -import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment; -import org.sufficientlysecure.keychain.util.Log; - -import android.annotation.SuppressLint; -import android.content.Intent; -import android.net.Uri; -import android.nfc.NdefMessage; -import android.nfc.NdefRecord; -import android.nfc.NfcAdapter; -import android.nfc.NfcAdapter.CreateNdefMessageCallback; -import android.nfc.NfcAdapter.OnNdefPushCompleteCallback; -import android.nfc.NfcEvent; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.text.format.DateFormat; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.TextView; -import android.widget.Toast; - -import com.actionbarsherlock.app.SherlockFragmentActivity; -import com.actionbarsherlock.view.Menu; -import com.actionbarsherlock.view.MenuItem; -import com.beardedhen.androidbootstrap.BootstrapButton; - -@SuppressLint("NewApi") -public class KeyViewActivity extends SherlockFragmentActivity implements CreateNdefMessageCallback, - OnNdefPushCompleteCallback { - - ExportHelper mExportHelper; - - private Uri mDataUri; - - private PGPPublicKey mPublicKey; - - private TextView mAlgorithm; - private TextView mFingerint; - private TextView mExpiry; - private TextView mCreation; - private BootstrapButton mActionEncrypt; - - // NFC - private NfcAdapter mNfcAdapter; - private byte[] mSharedKeyringBytes; - private static final int NFC_SENT = 1; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mExportHelper = new ExportHelper(this); - - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); - - setContentView(R.layout.key_view_activity); - - mFingerint = (TextView) this.findViewById(R.id.fingerprint); - mExpiry = (TextView) this.findViewById(R.id.expiry); - mCreation = (TextView) this.findViewById(R.id.creation); - mAlgorithm = (TextView) this.findViewById(R.id.algorithm); - mActionEncrypt = (BootstrapButton) this.findViewById(R.id.action_encrypt); - - Intent intent = getIntent(); - mDataUri = intent.getData(); - if (mDataUri == null) { - Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!"); - finish(); - return; - } else { - Log.d(Constants.TAG, "uri: " + mDataUri); - loadData(mDataUri); - initNfc(mDataUri); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getSupportMenuInflater().inflate(R.menu.key_view, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_key_view_update: - updateFromKeyserver(mDataUri); - return true; - case R.id.menu_key_view_sign: - signKey(mDataUri); - return true; - case R.id.menu_key_view_export_keyserver: - uploadToKeyserver(mDataUri); - return true; - case R.id.menu_key_view_export_file: - mExportHelper.showExportKeysDialog(mDataUri, Id.type.public_key, Constants.path.APP_DIR - + "/pubexport.asc"); - return true; - case R.id.menu_key_view_share_default: - shareKey(mDataUri); - return true; - case R.id.menu_key_view_share_qr_code: - shareKeyQrCode(mDataUri); - return true; - case R.id.menu_key_view_share_nfc: - shareNfc(); - return true; - case R.id.menu_key_view_share_clipboard: - copyToClipboard(mDataUri); - return true; - case R.id.menu_key_view_delete: { - // Message is received after key is deleted - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { - setResult(RESULT_CANCELED); - finish(); - } - } - }; - - mExportHelper.deleteKey(mDataUri, Id.type.public_key, returnHandler); - return true; - } - } - return super.onOptionsItemSelected(item); - } - - private void loadData(Uri dataUri) { - PGPPublicKeyRing ring = (PGPPublicKeyRing) ProviderHelper.getPGPKeyRing(this, dataUri); - mPublicKey = ring.getPublicKey(); - - mFingerint.setText(PgpKeyHelper.shortifyFingerprint(PgpKeyHelper - .convertFingerprintToHex(mPublicKey.getFingerprint()))); - String[] mainUserId = splitUserId(""); - - Date expiryDate = PgpKeyHelper.getExpiryDate(mPublicKey); - if (expiryDate == null) { - mExpiry.setText(""); - } else { - mExpiry.setText(DateFormat.getDateFormat(getApplicationContext()).format(expiryDate)); - } - - mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format( - PgpKeyHelper.getCreationDate(mPublicKey))); - mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(mPublicKey)); - - mActionEncrypt.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - long[] encryptionKeyIds = new long[] { mPublicKey.getKeyID() }; - Intent intent = new Intent(KeyViewActivity.this, EncryptActivity.class); - intent.setAction(EncryptActivity.ACTION_ENCRYPT); - intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); - // used instead of startActivity set actionbar based on callingPackage - startActivityForResult(intent, 0); - } - }); - } - - /** - * TODO: does this duplicate functionality from elsewhere? put in helper! - */ - 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; - } - - 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) { - long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment()); - - Intent uploadIntent = new Intent(this, KeyServerUploadActivity.class); - uploadIntent.setAction(KeyServerUploadActivity.ACTION_EXPORT_KEY_TO_SERVER); - uploadIntent.putExtra(KeyServerUploadActivity.EXTRA_KEYRING_ROW_ID, (int) keyRingRowId); - startActivityForResult(uploadIntent, Id.request.export_to_server); - } - - private void updateFromKeyserver(Uri dataUri) { - long updateKeyId = 0; - PGPPublicKeyRing updateRing = (PGPPublicKeyRing) ProviderHelper - .getPGPKeyRing(this, dataUri); - - if (updateRing != null) { - updateKeyId = PgpKeyHelper.getMasterKey(updateRing).getKeyID(); - } - if (updateKeyId == 0) { - Log.e(Constants.TAG, "this shouldn't happen. KeyId == 0!"); - return; - } - - Intent signIntent = new Intent(this, SignKeyActivity.class); - signIntent.putExtra(SignKeyActivity.EXTRA_KEY_ID, updateKeyId); - startActivity(signIntent); - - Intent queryIntent = new Intent(this, KeyServerQueryActivity.class); - queryIntent.setAction(KeyServerQueryActivity.ACTION_LOOK_UP_KEY_ID_AND_RETURN); - queryIntent.putExtra(KeyServerQueryActivity.EXTRA_KEY_ID, updateKeyId); - - // TODO: lookup?? - startActivityForResult(queryIntent, Id.request.look_up_key_id); - } - - private void signKey(Uri dataUri) { - long keyId = 0; - PGPPublicKeyRing signKey = (PGPPublicKeyRing) ProviderHelper.getPGPKeyRing(this, dataUri); - - if (signKey != null) { - keyId = PgpKeyHelper.getMasterKey(signKey).getKeyID(); - } - if (keyId == 0) { - Log.e(Constants.TAG, "this shouldn't happen. KeyId == 0!"); - return; - } - - Intent signIntent = new Intent(this, SignKeyActivity.class); - signIntent.putExtra(SignKeyActivity.EXTRA_KEY_ID, keyId); - startActivity(signIntent); - } - - private void shareKey(Uri dataUri) { - // get public keyring as ascii armored string - long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); - ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, dataUri, - new long[] { masterKeyId }); - - // let user choose application - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_TEXT, keyringArmored.get(0)); - sendIntent.setType("text/plain"); - startActivity(Intent.createChooser(sendIntent, - getResources().getText(R.string.action_share_key_with))); - } - - private void shareKeyQrCode(Uri dataUri) { - // get public keyring as ascii armored string - long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); - ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, dataUri, - new long[] { masterKeyId }); - - ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(keyringArmored - .get(0)); - dialog.show(getSupportFragmentManager(), "shareQrCodeDialog"); - } - - private void copyToClipboard(Uri dataUri) { - // get public keyring as ascii armored string - long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); - ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, dataUri, - new long[] { masterKeyId }); - - ClipboardReflection.copyToClipboard(this, keyringArmored.get(0)); - } - - private void shareNfc() { - ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); - dialog.show(getSupportFragmentManager(), "shareNfcDialog"); - } - - /** - * NFC: Initialize NFC sharing if OS and device supports it - */ - private void initNfc(Uri dataUri) { - // check if NFC Beam is supported (>= Android 4.1) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - // Check for available NFC Adapter - mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - if (mNfcAdapter != null) { - // init nfc - - // get public keyring as byte array - long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); - mSharedKeyringBytes = ProviderHelper.getKeyRingsAsByteArray(this, dataUri, - new long[] { masterKeyId }); - - // Register callback to set NDEF message - mNfcAdapter.setNdefPushMessageCallback(this, this); - // Register callback to listen for message-sent success - mNfcAdapter.setOnNdefPushCompleteCallback(this, this); - } - } - } - - /** - * NFC: Implementation for the CreateNdefMessageCallback interface - */ - @Override - public NdefMessage createNdefMessage(NfcEvent event) { - /** - * When a device receives a push with an AAR in it, the application specified in the AAR is - * guaranteed to run. The AAR overrides the tag dispatch system. You can add it back in to - * guarantee that this activity starts when receiving a beamed message. For now, this code - * uses the tag dispatch system. - */ - NdefMessage msg = new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME, - mSharedKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME)); - return msg; - } - - /** - * NFC: Implementation for the OnNdefPushCompleteCallback interface - */ - @Override - public void onNdefPushComplete(NfcEvent arg0) { - // A handler is needed to send messages to the activity when this - // callback occurs, because it happens from a binder thread - mNfcHandler.obtainMessage(NFC_SENT).sendToTarget(); - } - - /** - * NFC: This handler receives a message from onNdefPushComplete - */ - private final Handler mNfcHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case NFC_SENT: - Toast.makeText(getApplicationContext(), R.string.nfc_successfull, Toast.LENGTH_LONG) - .show(); - break; - } - } - }; - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (!mExportHelper.handleActivityResult(requestCode, resultCode, data)) { - super.onActivityResult(requestCode, resultCode, data); - } - } - -} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/SignKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/SignKeyActivity.java index c2fe1315b..6abdddee6 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/SignKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/SignKeyActivity.java @@ -68,7 +68,7 @@ public class SignKeyActivity extends SherlockFragmentActivity { super.onCreate(savedInstanceState); // check we havent already signed it - setContentView(R.layout.sign_key_layout); + setContentView(R.layout.sign_key_activity); final ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayShowTitleEnabled(true); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java new file mode 100644 index 000000000..5bc30ccc5 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * Copyright (C) 2013 Bahtiar 'kalkin' Gadimov + * + * 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 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; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.Id; +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.ProviderHelper; +import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment; +import org.sufficientlysecure.keychain.util.Log; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.net.Uri; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.nfc.NfcAdapter.CreateNdefMessageCallback; +import android.nfc.NfcAdapter.OnNdefPushCompleteCallback; +import android.nfc.NfcEvent; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.text.format.DateFormat; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; +import com.beardedhen.androidbootstrap.BootstrapButton; + +@SuppressLint("NewApi") +public class ViewKeyActivity extends SherlockFragmentActivity implements CreateNdefMessageCallback, + OnNdefPushCompleteCallback { + + ExportHelper mExportHelper; + + private Uri mDataUri; + + private PGPPublicKey mPublicKey; + + private TextView mAlgorithm; + private TextView mFingerint; + private TextView mExpiry; + private TextView mCreation; + private BootstrapButton mActionEncrypt; + + private ListView mUserIds; + private ListView mKeys; + + // NFC + private NfcAdapter mNfcAdapter; + private byte[] mSharedKeyringBytes; + private static final int NFC_SENT = 1; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mExportHelper = new ExportHelper(this); + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + 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); + mAlgorithm = (TextView) findViewById(R.id.algorithm); + mActionEncrypt = (BootstrapButton) findViewById(R.id.action_encrypt); + mUserIds = (ListView) findViewById(R.id.user_ids); + mKeys = (ListView) findViewById(R.id.keys); + + Intent intent = getIntent(); + mDataUri = intent.getData(); + if (mDataUri == null) { + Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!"); + finish(); + return; + } else { + Log.d(Constants.TAG, "uri: " + mDataUri); + loadData(mDataUri); + initNfc(mDataUri); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + getSupportMenuInflater().inflate(R.menu.key_view, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_key_view_update: + updateFromKeyserver(mDataUri); + return true; + case R.id.menu_key_view_sign: + signKey(mDataUri); + return true; + case R.id.menu_key_view_export_keyserver: + uploadToKeyserver(mDataUri); + return true; + case R.id.menu_key_view_export_file: + mExportHelper.showExportKeysDialog(mDataUri, Id.type.public_key, Constants.path.APP_DIR + + "/pubexport.asc"); + return true; + case R.id.menu_key_view_share_default: + shareKey(mDataUri); + return true; + case R.id.menu_key_view_share_qr_code: + shareKeyQrCode(mDataUri); + return true; + case R.id.menu_key_view_share_nfc: + shareNfc(); + return true; + case R.id.menu_key_view_share_clipboard: + copyToClipboard(mDataUri); + return true; + case R.id.menu_key_view_delete: { + // Message is received after key is deleted + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { + setResult(RESULT_CANCELED); + finish(); + } + } + }; + + mExportHelper.deleteKey(mDataUri, Id.type.public_key, returnHandler); + return true; + } + } + return super.onOptionsItemSelected(item); + } + + private void loadData(Uri dataUri) { + PGPPublicKeyRing ring = (PGPPublicKeyRing) ProviderHelper.getPGPKeyRing(this, dataUri); + mPublicKey = ring.getPublicKey(); + + mFingerint.setText(PgpKeyHelper.shortifyFingerprint(PgpKeyHelper + .convertFingerprintToHex(mPublicKey.getFingerprint()))); + String[] mainUserId = splitUserId(""); + + Date expiryDate = PgpKeyHelper.getExpiryDate(mPublicKey); + if (expiryDate == null) { + mExpiry.setText(""); + } else { + mExpiry.setText(DateFormat.getDateFormat(getApplicationContext()).format(expiryDate)); + } + + mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format( + PgpKeyHelper.getCreationDate(mPublicKey))); + mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(mPublicKey)); + + mActionEncrypt.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + long[] encryptionKeyIds = new long[] { mPublicKey.getKeyID() }; + Intent intent = new Intent(ViewKeyActivity.this, EncryptActivity.class); + intent.setAction(EncryptActivity.ACTION_ENCRYPT); + intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); + // used instead of startActivity set actionbar based on callingPackage + startActivityForResult(intent, 0); + } + }); + } + + /** + * TODO: does this duplicate functionality from elsewhere? put in helper! + */ + 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; + } + + 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) { + long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment()); + + Intent uploadIntent = new Intent(this, KeyServerUploadActivity.class); + uploadIntent.setAction(KeyServerUploadActivity.ACTION_EXPORT_KEY_TO_SERVER); + uploadIntent.putExtra(KeyServerUploadActivity.EXTRA_KEYRING_ROW_ID, (int) keyRingRowId); + startActivityForResult(uploadIntent, Id.request.export_to_server); + } + + private void updateFromKeyserver(Uri dataUri) { + long updateKeyId = 0; + PGPPublicKeyRing updateRing = (PGPPublicKeyRing) ProviderHelper + .getPGPKeyRing(this, dataUri); + + if (updateRing != null) { + updateKeyId = PgpKeyHelper.getMasterKey(updateRing).getKeyID(); + } + if (updateKeyId == 0) { + Log.e(Constants.TAG, "this shouldn't happen. KeyId == 0!"); + return; + } + + Intent signIntent = new Intent(this, SignKeyActivity.class); + signIntent.putExtra(SignKeyActivity.EXTRA_KEY_ID, updateKeyId); + startActivity(signIntent); + + Intent queryIntent = new Intent(this, KeyServerQueryActivity.class); + queryIntent.setAction(KeyServerQueryActivity.ACTION_LOOK_UP_KEY_ID_AND_RETURN); + queryIntent.putExtra(KeyServerQueryActivity.EXTRA_KEY_ID, updateKeyId); + + // TODO: lookup?? + startActivityForResult(queryIntent, Id.request.look_up_key_id); + } + + private void signKey(Uri dataUri) { + long keyId = 0; + PGPPublicKeyRing signKey = (PGPPublicKeyRing) ProviderHelper.getPGPKeyRing(this, dataUri); + + if (signKey != null) { + keyId = PgpKeyHelper.getMasterKey(signKey).getKeyID(); + } + if (keyId == 0) { + Log.e(Constants.TAG, "this shouldn't happen. KeyId == 0!"); + return; + } + + Intent signIntent = new Intent(this, SignKeyActivity.class); + signIntent.putExtra(SignKeyActivity.EXTRA_KEY_ID, keyId); + startActivity(signIntent); + } + + private void shareKey(Uri dataUri) { + // get public keyring as ascii armored string + long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); + ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, dataUri, + new long[] { masterKeyId }); + + // let user choose application + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, keyringArmored.get(0)); + sendIntent.setType("text/plain"); + startActivity(Intent.createChooser(sendIntent, + getResources().getText(R.string.action_share_key_with))); + } + + private void shareKeyQrCode(Uri dataUri) { + // get public keyring as ascii armored string + long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); + ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, dataUri, + new long[] { masterKeyId }); + + ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(keyringArmored + .get(0)); + dialog.show(getSupportFragmentManager(), "shareQrCodeDialog"); + } + + private void copyToClipboard(Uri dataUri) { + // get public keyring as ascii armored string + long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); + ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, dataUri, + new long[] { masterKeyId }); + + ClipboardReflection.copyToClipboard(this, keyringArmored.get(0)); + } + + private void shareNfc() { + ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); + dialog.show(getSupportFragmentManager(), "shareNfcDialog"); + } + + /** + * NFC: Initialize NFC sharing if OS and device supports it + */ + private void initNfc(Uri dataUri) { + // check if NFC Beam is supported (>= Android 4.1) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + // Check for available NFC Adapter + mNfcAdapter = NfcAdapter.getDefaultAdapter(this); + if (mNfcAdapter != null) { + // init nfc + + // get public keyring as byte array + long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); + mSharedKeyringBytes = ProviderHelper.getKeyRingsAsByteArray(this, dataUri, + new long[] { masterKeyId }); + + // Register callback to set NDEF message + mNfcAdapter.setNdefPushMessageCallback(this, this); + // Register callback to listen for message-sent success + mNfcAdapter.setOnNdefPushCompleteCallback(this, this); + } + } + } + + /** + * NFC: Implementation for the CreateNdefMessageCallback interface + */ + @Override + public NdefMessage createNdefMessage(NfcEvent event) { + /** + * When a device receives a push with an AAR in it, the application specified in the AAR is + * guaranteed to run. The AAR overrides the tag dispatch system. You can add it back in to + * guarantee that this activity starts when receiving a beamed message. For now, this code + * uses the tag dispatch system. + */ + NdefMessage msg = new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME, + mSharedKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME)); + return msg; + } + + /** + * NFC: Implementation for the OnNdefPushCompleteCallback interface + */ + @Override + public void onNdefPushComplete(NfcEvent arg0) { + // A handler is needed to send messages to the activity when this + // callback occurs, because it happens from a binder thread + mNfcHandler.obtainMessage(NFC_SENT).sendToTarget(); + } + + /** + * NFC: This handler receives a message from onNdefPushComplete + */ + private final Handler mNfcHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case NFC_SENT: + Toast.makeText(getApplicationContext(), R.string.nfc_successfull, Toast.LENGTH_LONG) + .show(); + break; + } + } + }; + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (!mExportHelper.handleActivityResult(requestCode, resultCode, data)) { + super.onActivityResult(requestCode, resultCode, data); + } + } + +} 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 5f71c9805..140781b4f 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java @@ -105,7 +105,7 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea HeaderViewHolder holder; if (convertView == null) { holder = new HeaderViewHolder(); - convertView = mInflater.inflate(R.layout.stickylist_header, parent, false); + convertView = mInflater.inflate(R.layout.key_list_public_header, parent, false); holder.text = (TextView) convertView.findViewById(R.id.stickylist_header_text); convertView.setTag(holder); } else { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java new file mode 100644 index 000000000..55821b11e --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java @@ -0,0 +1,81 @@ +/* + * 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 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; +import android.view.ViewGroup; +import android.widget.TextView; + +public class ViewKeyUserIdsAdapter extends CursorAdapter { + private LayoutInflater mInflater; + + public ViewKeyUserIdsAdapter(Context context, Cursor c, int flags) { + super(context, c, flags); + + mInflater = LayoutInflater.from(context); + } + + @Override + 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 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); + } + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mInflater.inflate(R.layout.key_list_item, null); + } + +} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java index aba7e974e..e88271240 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java @@ -141,7 +141,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor } LayoutInflater inflater = activity.getLayoutInflater(); - View view = inflater.inflate(R.layout.passphrase, null); + View view = inflater.inflate(R.layout.passphrase_dialog, null); alert.setView(view); mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java index 797b28829..79d577c58 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java @@ -90,7 +90,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi alert.setMessage(R.string.enter_passphrase_twice); LayoutInflater inflater = activity.getLayoutInflater(); - View view = inflater.inflate(R.layout.passphrase_repeat, null); + View view = inflater.inflate(R.layout.passphrase_repeat_dialogf, null); alert.setView(view); mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java index 91e3831b7..b33dbe4c5 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java @@ -153,7 +153,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor case Id.type.key: { AlertDialog.Builder dialog = new AlertDialog.Builder(getContext()); - View view = mInflater.inflate(R.layout.create_key, null); + View view = mInflater.inflate(R.layout.create_key_dialog, null); dialog.setView(view); dialog.setTitle(R.string.title_create_key); -- cgit v1.2.3 From c740d409c4f8977da22738f98f16f6b3f624ea73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 12 Jan 2014 22:26:55 +0100 Subject: fix compile --- .../keychain/ui/adapter/KeyListAdapterOLD.java | 40 +++++++++++++--------- .../ui/dialog/SetPassphraseDialogFragment.java | 2 +- 2 files changed, 24 insertions(+), 18 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapterOLD.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapterOLD.java index 0c709d25a..8f745bdd3 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapterOLD.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListAdapterOLD.java @@ -18,12 +18,12 @@ 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 org.sufficientlysecure.keychain.R; import android.content.Context; import android.database.Cursor; @@ -36,7 +36,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.CursorTreeAdapter; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; public class KeyListAdapterOLD extends CursorTreeAdapter { @@ -97,27 +96,27 @@ public class KeyListAdapterOLD extends CursorTreeAdapter { } } - /** - * 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); - } +// /** +// * 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); +// 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); +// keyLayout.setVisibility(View.GONE); +// userIdLayout.setVisibility(View.VISIBLE); String fingerprint = PgpKeyHelper.getFingerPrint(context, cursor.getLong(cursor.getColumnIndex(Keys.KEY_ID))); @@ -131,8 +130,8 @@ public class KeyListAdapterOLD extends CursorTreeAdapter { } else { // differentiate between keys and userIds in MergeCursor if (cursor.getColumnIndex(Keys.KEY_ID) != -1) { - keyLayout.setVisibility(View.VISIBLE); - userIdLayout.setVisibility(View.GONE); +// keyLayout.setVisibility(View.VISIBLE); +// userIdLayout.setVisibility(View.GONE); String keyIdStr = PgpKeyHelper.convertKeyIdToHex(cursor.getLong(cursor .getColumnIndex(Keys.KEY_ID))); @@ -174,8 +173,8 @@ public class KeyListAdapterOLD extends CursorTreeAdapter { signIcon.setVisibility(View.VISIBLE); } } else { - keyLayout.setVisibility(View.GONE); - userIdLayout.setVisibility(View.VISIBLE); +// keyLayout.setVisibility(View.GONE); +// userIdLayout.setVisibility(View.VISIBLE); String userIdStr = cursor.getString(cursor.getColumnIndex(UserIds.USER_ID)); @@ -270,4 +269,11 @@ public class KeyListAdapterOLD extends CursorTreeAdapter { 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/dialog/SetPassphraseDialogFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java index 79d577c58..d5c366bed 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java @@ -90,7 +90,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi alert.setMessage(R.string.enter_passphrase_twice); LayoutInflater inflater = activity.getLayoutInflater(); - View view = inflater.inflate(R.layout.passphrase_repeat_dialogf, null); + View view = inflater.inflate(R.layout.passphrase_repeat_dialog, null); alert.setView(view); mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase); -- cgit v1.2.3 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: key view is working --- .../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 +++++++++++--- .../keychain/ui/adapter/KeyListAdapterOLD.java | 279 --------------------- .../keychain/ui/adapter/KeyListPublicAdapter.java | 6 +- .../keychain/ui/adapter/KeyListSecretAdapter.java | 4 +- .../ui/adapter/SelectKeyCursorAdapter.java | 5 +- .../keychain/ui/adapter/ViewKeyKeysAdapter.java | 90 +++++++ .../keychain/ui/adapter/ViewKeyUserIdsAdapter.java | 36 +-- .../keychain/ui/widget/FixedListView.java | 55 ++++ 12 files changed, 360 insertions(+), 376 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 (limited to 'OpenPGP-Keychain/src') 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); } - /** - * TODO: does this duplicate functionality from elsewhere? put in helper! - */ - 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; + 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; + } + } - Pattern withoutComment = Pattern.compile("^(.*) <(.*)>$"); - matcher = withoutComment.matcher(userId); - if (matcher.matches()) { - result[0] = matcher.group(1); - result[1] = matcher.group(2); - return result; + 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; + } + } + + /** + * 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_KEYRING: + // TODO? + break; + case LOADER_ID_USER_IDS: + mUserIdsAdapter.swapCursor(null); + break; + case LOADER_ID_KEYS: + mKeysAdapter.swapCursor(null); + break; + default: + break; } - 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 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); - } + String userIdStr = cursor.getString(userIdIndex); - 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 -- cgit v1.2.3