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 --- OpenPGP-Keychain/AndroidManifest.xml | 5 +- OpenPGP-Keychain/project.properties | 1 - OpenPGP-Keychain/res/layout/key_view.xml | 116 ----- OpenPGP-Keychain/res/layout/key_view_activity.xml | 116 +++++ OpenPGP-Keychain/res/menu/key_view.xml | 38 ++ .../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 +++++++++++ README.md | 11 +- libraries/pinned-section-listview/.gitignore | 6 - libraries/pinned-section-listview/README.md | 75 --- .../example/AndroidManifest.xml | 27 -- .../example/assets/.gitignore | 1 - .../example/ic_launcher-web.png | Bin 45500 -> 0 bytes .../example/libs/android-support-v4.jar | Bin 393154 -> 0 bytes .../example/proguard-project.txt | 20 - .../example/project.properties | 15 - .../example/res/drawable-hdpi/ic_launcher.png | Bin 5819 -> 0 bytes .../example/res/drawable-mdpi/ic_launcher.png | Bin 3479 -> 0 bytes .../example/res/drawable-xhdpi/ic_launcher.png | Bin 7534 -> 0 bytes .../example/res/drawable-xxhdpi/ic_launcher.png | Bin 11732 -> 0 bytes .../example/res/layout/activity_main.xml | 8 - .../example/res/menu/main.xml | 27 -- .../example/res/values-v11/styles.xml | 11 - .../example/res/values-v14/styles.xml | 12 - .../example/res/values/colors.xml | 10 - .../example/res/values/strings.xml | 10 - .../example/res/values/styles.xml | 20 - .../com/hb/examples/PinnedSectionListActivity.java | 285 ------------ .../library/AndroidManifest.xml | 13 - .../library/assets/.gitignore | 1 - .../pinned-section-listview/library/build.gradle | 24 - .../library/proguard-project.txt | 20 - .../library/project.properties | 15 - .../pinned-section-listview/library/res/.gitignore | 1 - .../src/com/hb/views/PinnedSectionListView.java | 513 --------------------- libraries/pinned-section-listview/screen1.png | Bin 23124 -> 0 bytes libraries/pinned-section-listview/screen2.png | Bin 22743 -> 0 bytes libraries/pinned-section-listview/screen3.png | Bin 22885 -> 0 bytes settings.gradle | 3 +- 49 files changed, 919 insertions(+), 1688 deletions(-) delete mode 100644 OpenPGP-Keychain/res/layout/key_view.xml create mode 100644 OpenPGP-Keychain/res/layout/key_view_activity.xml create mode 100644 OpenPGP-Keychain/res/menu/key_view.xml 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 delete mode 100644 libraries/pinned-section-listview/.gitignore delete mode 100644 libraries/pinned-section-listview/README.md delete mode 100644 libraries/pinned-section-listview/example/AndroidManifest.xml delete mode 100644 libraries/pinned-section-listview/example/assets/.gitignore delete mode 100644 libraries/pinned-section-listview/example/ic_launcher-web.png delete mode 100644 libraries/pinned-section-listview/example/libs/android-support-v4.jar delete mode 100644 libraries/pinned-section-listview/example/proguard-project.txt delete mode 100644 libraries/pinned-section-listview/example/project.properties delete mode 100644 libraries/pinned-section-listview/example/res/drawable-hdpi/ic_launcher.png delete mode 100644 libraries/pinned-section-listview/example/res/drawable-mdpi/ic_launcher.png delete mode 100644 libraries/pinned-section-listview/example/res/drawable-xhdpi/ic_launcher.png delete mode 100644 libraries/pinned-section-listview/example/res/drawable-xxhdpi/ic_launcher.png delete mode 100644 libraries/pinned-section-listview/example/res/layout/activity_main.xml delete mode 100644 libraries/pinned-section-listview/example/res/menu/main.xml delete mode 100644 libraries/pinned-section-listview/example/res/values-v11/styles.xml delete mode 100644 libraries/pinned-section-listview/example/res/values-v14/styles.xml delete mode 100644 libraries/pinned-section-listview/example/res/values/colors.xml delete mode 100644 libraries/pinned-section-listview/example/res/values/strings.xml delete mode 100644 libraries/pinned-section-listview/example/res/values/styles.xml delete mode 100644 libraries/pinned-section-listview/example/src/com/hb/examples/PinnedSectionListActivity.java delete mode 100644 libraries/pinned-section-listview/library/AndroidManifest.xml delete mode 100644 libraries/pinned-section-listview/library/assets/.gitignore delete mode 100644 libraries/pinned-section-listview/library/build.gradle delete mode 100644 libraries/pinned-section-listview/library/proguard-project.txt delete mode 100644 libraries/pinned-section-listview/library/project.properties delete mode 100644 libraries/pinned-section-listview/library/res/.gitignore delete mode 100644 libraries/pinned-section-listview/library/src/com/hb/views/PinnedSectionListView.java delete mode 100644 libraries/pinned-section-listview/screen1.png delete mode 100644 libraries/pinned-section-listview/screen2.png delete mode 100644 libraries/pinned-section-listview/screen3.png diff --git a/OpenPGP-Keychain/AndroidManifest.xml b/OpenPGP-Keychain/AndroidManifest.xml index 4b843bc01..be9fe222c 100644 --- a/OpenPGP-Keychain/AndroidManifest.xml +++ b/OpenPGP-Keychain/AndroidManifest.xml @@ -123,11 +123,10 @@ android:uiOptions="splitActionBarWhenNarrow" android:windowSoftInputMode="stateHidden" /> + android:parentActivityName=".ui.KeyListPublicActivity" > diff --git a/OpenPGP-Keychain/project.properties b/OpenPGP-Keychain/project.properties index 7347abfcd..7acfa6b58 100644 --- a/OpenPGP-Keychain/project.properties +++ b/OpenPGP-Keychain/project.properties @@ -11,4 +11,3 @@ target=android-19 android.library.reference.1=../libraries/ActionBarSherlock android.library.reference.2=../libraries/HtmlTextView -android.library.reference.3=../libraries/pinned-section-listview/library diff --git a/OpenPGP-Keychain/res/layout/key_view.xml b/OpenPGP-Keychain/res/layout/key_view.xml deleted file mode 100644 index 326959e97..000000000 --- a/OpenPGP-Keychain/res/layout/key_view.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/OpenPGP-Keychain/res/layout/key_view_activity.xml b/OpenPGP-Keychain/res/layout/key_view_activity.xml new file mode 100644 index 000000000..326959e97 --- /dev/null +++ b/OpenPGP-Keychain/res/layout/key_view_activity.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenPGP-Keychain/res/menu/key_view.xml b/OpenPGP-Keychain/res/menu/key_view.xml new file mode 100644 index 000000000..ac5c96c5d --- /dev/null +++ b/OpenPGP-Keychain/res/menu/key_view.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + \ No newline at end of file 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 diff --git a/README.md b/README.md index 0bea8d377..80b34ab05 100644 --- a/README.md +++ b/README.md @@ -107,13 +107,6 @@ TODO # Libraries -All JAR-Libraries are provided in this repository under "libs", all Android Library projects are under "libraries". - -* ActionBarSherlock to provide an ActionBar for Android < 3.0 -* HtmlTextView for non-crashing TextViews with HTML content -* forked Spongy Castle Crypto Lib (Android version of Bouncy Castle) -* barcodescanner-android-integration-supportv4.jar: Barcode Scanner Integration - ## Build Barcode Scanner Integration 1. Checkout their SVN (see http://code.google.com/p/zxing/source/checkout) @@ -212,8 +205,8 @@ Some parts (older parts and some libraries are Apache License v2, MIT X11 Licens http://code.google.com/p/zxing/ Apache License v2 -* pinned-section-listview - https://github.com/beworker/pinned-section-listview +* android-section-adapter + https://github.com/monxalo/android-section-adapter Apache License v2 diff --git a/libraries/pinned-section-listview/.gitignore b/libraries/pinned-section-listview/.gitignore deleted file mode 100644 index ba354bcae..000000000 --- a/libraries/pinned-section-listview/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -bin -gen -.project -.classpath -.settings -.DS_Store diff --git a/libraries/pinned-section-listview/README.md b/libraries/pinned-section-listview/README.md deleted file mode 100644 index e89cde3bb..000000000 --- a/libraries/pinned-section-listview/README.md +++ /dev/null @@ -1,75 +0,0 @@ -Introduction -============ - -Easy to use ListView with pinned sections for Android. Pinned section is a header view which sticks to the top -of the list until at least one item of that section is visible. - -![Alt text](screen1.png)  -![Alt text](screen2.png)  -![Alt text](screen3.png) - -Features -======== -This list properly implements many features which are missing from other implementations. These are - * Fast scroll - * Headers and footers - * Clickable pinned sections - -Besides this it doesn't create any unnecessary views, layouts etc. It's really lean. - -Watch [this video][1] to see `PinnedSectionListView` in action. - -Usage -===== - 1. Replace standard `ListView` with `com.hb.views.PinnedSectionListView` in your `layout.xml` file. - - - - 2. Extend your `ListAdapter` in a way that it implements `PinnedSectionListAdapter` interface, in addition to - what it already implements. Basically you need to add a single `isItemViewTypePinned(int viewType)` - method. This method must return `true` for all view types which have to be pinned. - - // Our adapter class implements 'PinnedSectionListAdapter' interface - class MyPinnedSectionListAdapter extends BaseAdapter implements PinnedSectionListAdapter { - - ... - - // We implement this method to return 'true' for all view types we want to pin - @Override - public boolean isItemViewTypePinned(int viewType) { - return viewType == ; - } - } - -That's all. You are done! A working example can also be found in `example` folder. - -Used by -======= -Let us know if you use this library in your application and we will mention it here. - -[Grocery Sum][2] - -License -======= - - Copyright 2013 Sergej Shafarenka, halfbit.de - - 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. - - -[1]: http://www.youtube.com/watch?v=mI3DpuoIIhQ -[2]: https://play.google.com/store/apps/details?id=org.codechimp.grocerysum diff --git a/libraries/pinned-section-listview/example/AndroidManifest.xml b/libraries/pinned-section-listview/example/AndroidManifest.xml deleted file mode 100644 index 56621893d..000000000 --- a/libraries/pinned-section-listview/example/AndroidManifest.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libraries/pinned-section-listview/example/assets/.gitignore b/libraries/pinned-section-listview/example/assets/.gitignore deleted file mode 100644 index fdffa2a0f..000000000 --- a/libraries/pinned-section-listview/example/assets/.gitignore +++ /dev/null @@ -1 +0,0 @@ -# placeholder diff --git a/libraries/pinned-section-listview/example/ic_launcher-web.png b/libraries/pinned-section-listview/example/ic_launcher-web.png deleted file mode 100644 index 8bd40412e..000000000 Binary files a/libraries/pinned-section-listview/example/ic_launcher-web.png and /dev/null differ diff --git a/libraries/pinned-section-listview/example/libs/android-support-v4.jar b/libraries/pinned-section-listview/example/libs/android-support-v4.jar deleted file mode 100644 index 65ebaf8dc..000000000 Binary files a/libraries/pinned-section-listview/example/libs/android-support-v4.jar and /dev/null differ diff --git a/libraries/pinned-section-listview/example/proguard-project.txt b/libraries/pinned-section-listview/example/proguard-project.txt deleted file mode 100644 index f2fe1559a..000000000 --- a/libraries/pinned-section-listview/example/proguard-project.txt +++ /dev/null @@ -1,20 +0,0 @@ -# To enable ProGuard in your project, edit project.properties -# to define the proguard.config property as described in that file. -# -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in ${sdk.dir}/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the ProGuard -# include property in project.properties. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/libraries/pinned-section-listview/example/project.properties b/libraries/pinned-section-listview/example/project.properties deleted file mode 100644 index 1561d7a9a..000000000 --- a/libraries/pinned-section-listview/example/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-17 -android.library.reference.1=../library diff --git a/libraries/pinned-section-listview/example/res/drawable-hdpi/ic_launcher.png b/libraries/pinned-section-listview/example/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index 3841c3408..000000000 Binary files a/libraries/pinned-section-listview/example/res/drawable-hdpi/ic_launcher.png and /dev/null differ diff --git a/libraries/pinned-section-listview/example/res/drawable-mdpi/ic_launcher.png b/libraries/pinned-section-listview/example/res/drawable-mdpi/ic_launcher.png deleted file mode 100644 index e65953cce..000000000 Binary files a/libraries/pinned-section-listview/example/res/drawable-mdpi/ic_launcher.png and /dev/null differ diff --git a/libraries/pinned-section-listview/example/res/drawable-xhdpi/ic_launcher.png b/libraries/pinned-section-listview/example/res/drawable-xhdpi/ic_launcher.png deleted file mode 100644 index 4ea093d86..000000000 Binary files a/libraries/pinned-section-listview/example/res/drawable-xhdpi/ic_launcher.png and /dev/null differ diff --git a/libraries/pinned-section-listview/example/res/drawable-xxhdpi/ic_launcher.png b/libraries/pinned-section-listview/example/res/drawable-xxhdpi/ic_launcher.png deleted file mode 100644 index 87e928a35..000000000 Binary files a/libraries/pinned-section-listview/example/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/libraries/pinned-section-listview/example/res/layout/activity_main.xml b/libraries/pinned-section-listview/example/res/layout/activity_main.xml deleted file mode 100644 index b641f4c80..000000000 --- a/libraries/pinned-section-listview/example/res/layout/activity_main.xml +++ /dev/null @@ -1,8 +0,0 @@ - \ No newline at end of file diff --git a/libraries/pinned-section-listview/example/res/menu/main.xml b/libraries/pinned-section-listview/example/res/menu/main.xml deleted file mode 100644 index 091b6c770..000000000 --- a/libraries/pinned-section-listview/example/res/menu/main.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/libraries/pinned-section-listview/example/res/values-v11/styles.xml b/libraries/pinned-section-listview/example/res/values-v11/styles.xml deleted file mode 100644 index 541752f6e..000000000 --- a/libraries/pinned-section-listview/example/res/values-v11/styles.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/libraries/pinned-section-listview/example/res/values-v14/styles.xml b/libraries/pinned-section-listview/example/res/values-v14/styles.xml deleted file mode 100644 index f20e01501..000000000 --- a/libraries/pinned-section-listview/example/res/values-v14/styles.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/libraries/pinned-section-listview/example/res/values/colors.xml b/libraries/pinned-section-listview/example/res/values/colors.xml deleted file mode 100644 index b4da27c93..000000000 --- a/libraries/pinned-section-listview/example/res/values/colors.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - #ffff4444 - #ff99cc00 - #ffffbb33 - #ff33b5e5 - - - - \ No newline at end of file diff --git a/libraries/pinned-section-listview/example/res/values/strings.xml b/libraries/pinned-section-listview/example/res/values/strings.xml deleted file mode 100644 index e9d43a4aa..000000000 --- a/libraries/pinned-section-listview/example/res/values/strings.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - Pinned Section Demo - Fast scroll - Add padding - Show shadow - Show Header & Footer - - \ No newline at end of file diff --git a/libraries/pinned-section-listview/example/res/values/styles.xml b/libraries/pinned-section-listview/example/res/values/styles.xml deleted file mode 100644 index 4a10ca492..000000000 --- a/libraries/pinned-section-listview/example/res/values/styles.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/libraries/pinned-section-listview/example/src/com/hb/examples/PinnedSectionListActivity.java b/libraries/pinned-section-listview/example/src/com/hb/examples/PinnedSectionListActivity.java deleted file mode 100644 index 223718a06..000000000 --- a/libraries/pinned-section-listview/example/src/com/hb/examples/PinnedSectionListActivity.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (C) 2013 Sergej Shafarenka, halfbit.de - * - * 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.hb.examples; - -import java.util.Locale; - -import android.annotation.SuppressLint; -import android.app.ListActivity; -import android.content.Context; -import android.graphics.Color; -import android.os.Build; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.widget.SectionIndexer; -import android.widget.TextView; -import android.widget.Toast; - -import com.hb.examples.pinnedsection.R; -import com.hb.views.PinnedSectionListView; -import com.hb.views.PinnedSectionListView.PinnedSectionListAdapter; - -public class PinnedSectionListActivity extends ListActivity implements OnClickListener { - - static class SimpleAdapter extends ArrayAdapter implements PinnedSectionListAdapter { - - private static final int[] COLORS = new int[] { - R.color.green_light, R.color.orange_light, - R.color.blue_light, R.color.red_light }; - - public SimpleAdapter(Context context, int resource, int textViewResourceId) { - super(context, resource, textViewResourceId); - - final int sectionsNumber = 'Z' - 'A' + 1; - prepareSections(sectionsNumber); - - int sectionPosition = 0, listPosition = 0; - for (char i=0; i= sections.length) { - section = sections.length - 1; - } - return sections[section].listPosition; - } - - @Override public int getSectionForPosition(int position) { - if (position >= getCount()) { - position = getCount() - 1; - } - return getItem(position).sectionPosition; - } - - } - - static class Item { - - public static final int ITEM = 0; - public static final int SECTION = 1; - - public final int type; - public final String text; - - public int sectionPosition; - public int listPosition; - - public Item(int type, String text) { - this.type = type; - this.text = text; - } - - @Override public String toString() { - return text; - } - - } - - private boolean hasHeaderAndFooter; - private boolean isFastScroll; - private boolean addPadding; - private boolean isShadowVisible = true; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - if (savedInstanceState != null) { - isFastScroll = savedInstanceState.getBoolean("isFastScroll"); - addPadding = savedInstanceState.getBoolean("addPadding"); - isShadowVisible = savedInstanceState.getBoolean("isShadowVisible"); - hasHeaderAndFooter = savedInstanceState.getBoolean("hasHeaderAndFooter"); - } - initializeHeaderAndFooter(); - initializeAdapter(); - initializePadding(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putBoolean("isFastScroll", isFastScroll); - outState.putBoolean("addPadding", addPadding); - outState.putBoolean("isShadowVisible", isShadowVisible); - outState.putBoolean("hasHeaderAndFooter", hasHeaderAndFooter); - } - - @Override - protected void onListItemClick(ListView l, View v, int position, long id) { - Item item = (Item) getListView().getAdapter().getItem(position); - if (item != null) { - Toast.makeText(this, "Item " + position + ": " + item.text, Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(this, "Item " + position, Toast.LENGTH_SHORT).show(); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.main, menu); - menu.getItem(0).setChecked(isFastScroll); - menu.getItem(1).setChecked(addPadding); - menu.getItem(2).setChecked(isShadowVisible); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_fastscroll: - isFastScroll = !isFastScroll; - item.setChecked(isFastScroll); - initializeAdapter(); - break; - case R.id.action_addpadding: - addPadding = !addPadding; - item.setChecked(addPadding); - initializePadding(); - break; - case R.id.action_showShadow: - isShadowVisible = !isShadowVisible; - item.setChecked(isShadowVisible); - ((PinnedSectionListView)getListView()).setShadowVisible(isShadowVisible); - break; - case R.id.action_showHeaderAndFooter: - hasHeaderAndFooter = !hasHeaderAndFooter; - item.setChecked(hasHeaderAndFooter); - initializeHeaderAndFooter(); - break; - } - return true; - } - - private void initializePadding() { - float density = getResources().getDisplayMetrics().density; - int padding = addPadding ? (int) (16 * density) : 0; - getListView().setPadding(padding, padding, padding, padding); - } - - private void initializeHeaderAndFooter() { - setListAdapter(null); - if (hasHeaderAndFooter) { - ListView list = getListView(); - - LayoutInflater inflater = LayoutInflater.from(this); - TextView header1 = (TextView) inflater.inflate(android.R.layout.simple_list_item_1, list, false); - header1.setText("First header"); - list.addHeaderView(header1); - - TextView header2 = (TextView) inflater.inflate(android.R.layout.simple_list_item_1, list, false); - header2.setText("Second header"); - list.addHeaderView(header2); - - TextView footer = (TextView) inflater.inflate(android.R.layout.simple_list_item_1, list, false); - footer.setText("Single footer"); - list.addFooterView(footer); - } - initializeAdapter(); - } - - @SuppressLint("NewApi") - private void initializeAdapter() { - getListView().setFastScrollEnabled(isFastScroll); - if (isFastScroll) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - getListView().setFastScrollAlwaysVisible(true); - } - setListAdapter(new FastScrollAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1)); - } else { - setListAdapter(new SimpleAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1)); - } - } - - @Override - public void onClick(View v) { - Toast.makeText(this, "Item: " + v.getTag() , Toast.LENGTH_SHORT).show(); - } - -} \ No newline at end of file diff --git a/libraries/pinned-section-listview/library/AndroidManifest.xml b/libraries/pinned-section-listview/library/AndroidManifest.xml deleted file mode 100644 index 2e2ee9173..000000000 --- a/libraries/pinned-section-listview/library/AndroidManifest.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/libraries/pinned-section-listview/library/assets/.gitignore b/libraries/pinned-section-listview/library/assets/.gitignore deleted file mode 100644 index fdffa2a0f..000000000 --- a/libraries/pinned-section-listview/library/assets/.gitignore +++ /dev/null @@ -1 +0,0 @@ -# placeholder diff --git a/libraries/pinned-section-listview/library/build.gradle b/libraries/pinned-section-listview/library/build.gradle deleted file mode 100644 index d77f4746f..000000000 --- a/libraries/pinned-section-listview/library/build.gradle +++ /dev/null @@ -1,24 +0,0 @@ -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:0.6.3' - } -} - -apply plugin: 'android-library' - - -android { - compileSdkVersion 17 - buildToolsVersion '19' - - sourceSets { - main { - manifest.srcFile 'AndroidManifest.xml' - java.srcDirs = ['src'] - res.srcDirs = ['res'] - } - } -} diff --git a/libraries/pinned-section-listview/library/proguard-project.txt b/libraries/pinned-section-listview/library/proguard-project.txt deleted file mode 100644 index f2fe1559a..000000000 --- a/libraries/pinned-section-listview/library/proguard-project.txt +++ /dev/null @@ -1,20 +0,0 @@ -# To enable ProGuard in your project, edit project.properties -# to define the proguard.config property as described in that file. -# -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in ${sdk.dir}/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the ProGuard -# include property in project.properties. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/libraries/pinned-section-listview/library/project.properties b/libraries/pinned-section-listview/library/project.properties deleted file mode 100644 index 484dab075..000000000 --- a/libraries/pinned-section-listview/library/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-17 -android.library=true diff --git a/libraries/pinned-section-listview/library/res/.gitignore b/libraries/pinned-section-listview/library/res/.gitignore deleted file mode 100644 index fdffa2a0f..000000000 --- a/libraries/pinned-section-listview/library/res/.gitignore +++ /dev/null @@ -1 +0,0 @@ -# placeholder diff --git a/libraries/pinned-section-listview/library/src/com/hb/views/PinnedSectionListView.java b/libraries/pinned-section-listview/library/src/com/hb/views/PinnedSectionListView.java deleted file mode 100644 index 8100ad693..000000000 --- a/libraries/pinned-section-listview/library/src/com/hb/views/PinnedSectionListView.java +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Copyright (C) 2013 Sergej Shafarenka, halfbit.de - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file kt 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.hb.views; - -import android.content.Context; -import android.database.DataSetObserver; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.PointF; -import android.graphics.Rect; -import android.graphics.drawable.GradientDrawable; -import android.graphics.drawable.GradientDrawable.Orientation; -import android.os.Parcelable; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.SoundEffectConstants; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.accessibility.AccessibilityEvent; -import android.widget.AbsListView; -import android.widget.HeaderViewListAdapter; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.SectionIndexer; - -import com.hb.views.pinnedsection.BuildConfig; - -/** - * ListView, which is capable to pin section views at its top while the rest is still scrolled. - */ -public class PinnedSectionListView extends ListView { - - //-- inner classes - - /** List adapter to be implemented for being used with PinnedSectionListView adapter. */ - public static interface PinnedSectionListAdapter extends ListAdapter { - /** This method shall return 'true' if views of given type has to be pinned. */ - boolean isItemViewTypePinned(int viewType); - } - - /** Wrapper class for pinned section view and its position in the list. */ - static class PinnedSection { - public View view; - public int position; - public long id; - } - - //-- class fields - - // fields used for handling touch events - private final Rect mTouchRect = new Rect(); - private final PointF mTouchPoint = new PointF(); - private int mTouchSlop; - private View mTouchTarget; - private MotionEvent mDownEvent; - - // fields used for drawing shadow under a pinned section - private GradientDrawable mShadowDrawable; - private int mSectionsDistanceY; - private int mShadowHeight; - - /** Delegating listener, can be null. */ - OnScrollListener mDelegateOnScrollListener; - - /** Shadow for being recycled, can be null. */ - PinnedSection mRecycleSection; - - /** shadow instance with a pinned view, can be null. */ - PinnedSection mPinnedSection; - - /** Pinned view Y-translation. We use it to stick pinned view to the next section. */ - int mTranslateY; - - /** Scroll listener which does the magic */ - private final OnScrollListener mOnScrollListener = new OnScrollListener() { - - @Override public void onScrollStateChanged(AbsListView view, int scrollState) { - if (mDelegateOnScrollListener != null) { // delegate - mDelegateOnScrollListener.onScrollStateChanged(view, scrollState); - } - } - - @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - - if (mDelegateOnScrollListener != null) { // delegate - mDelegateOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); - } - - // get expected adapter or fail fast - ListAdapter adapter = getAdapter(); - if (adapter == null || visibleItemCount == 0) return; // nothing to do - - final boolean isFirstVisibleItemSection = - isItemViewTypePinned(adapter, adapter.getItemViewType(firstVisibleItem)); - - if (isFirstVisibleItemSection) { - View sectionView = getChildAt(0); - if (sectionView.getTop() == getPaddingTop()) { // view sticks to the top, no need for pinned shadow - destroyPinnedShadow(); - } else { // section doesn't stick to the top, make sure we have a pinned shadow - ensureShadowForPosition(firstVisibleItem, firstVisibleItem, visibleItemCount); - } - - } else { // section is not at the first visible position - int sectionPosition = findCurrentSectionPosition(firstVisibleItem); - if (sectionPosition > -1) { // we have section position - ensureShadowForPosition(sectionPosition, firstVisibleItem, visibleItemCount); - } else { // there is no section for the first visible item, destroy shadow - destroyPinnedShadow(); - } - } - }; - - }; - - /** Default change observer. */ - private final DataSetObserver mDataSetObserver = new DataSetObserver() { - @Override public void onChanged() { - recreatePinnedShadow(); - }; - @Override public void onInvalidated() { - recreatePinnedShadow(); - } - }; - - //-- constructors - - public PinnedSectionListView(Context context, AttributeSet attrs) { - super(context, attrs); - initView(); - } - - public PinnedSectionListView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - initView(); - } - - private void initView() { - setOnScrollListener(mOnScrollListener); - mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); - initShadow(true); - } - - //-- public API methods - - public void setShadowVisible(boolean visible) { - initShadow(visible); - if (mPinnedSection != null) { - View v = mPinnedSection.view; - invalidate(v.getLeft(), v.getTop(), v.getRight(), v.getBottom() + mShadowHeight); - } - } - - //-- pinned section drawing methods - - public void initShadow(boolean visible) { - if (visible) { - if (mShadowDrawable == null) { - mShadowDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, - new int[] { Color.parseColor("#ffa0a0a0"), Color.parseColor("#50a0a0a0"), Color.parseColor("#00a0a0a0")}); - mShadowHeight = (int) (8 * getResources().getDisplayMetrics().density); - } - } else { - if (mShadowDrawable != null) { - mShadowDrawable = null; - mShadowHeight = 0; - } - } - } - - /** Create shadow wrapper with a pinned view for a view at given position */ - void createPinnedShadow(int position) { - - // try to recycle shadow - PinnedSection pinnedShadow = mRecycleSection; - mRecycleSection = null; - - // create new shadow, if needed - if (pinnedShadow == null) pinnedShadow = new PinnedSection(); - // request new view using recycled view, if such - View pinnedView = getAdapter().getView(position, pinnedShadow.view, PinnedSectionListView.this); - - // read layout parameters - LayoutParams layoutParams = (LayoutParams) pinnedView.getLayoutParams(); - if (layoutParams == null) { // create default layout params - layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - } - - int heightMode = MeasureSpec.getMode(layoutParams.height); - int heightSize = MeasureSpec.getSize(layoutParams.height); - - if (heightMode == MeasureSpec.UNSPECIFIED) heightMode = MeasureSpec.EXACTLY; - - int maxHeight = getHeight() - getListPaddingTop() - getListPaddingBottom(); - if (heightSize > maxHeight) heightSize = maxHeight; - - // measure & layout - int ws = MeasureSpec.makeMeasureSpec(getWidth() - getListPaddingLeft() - getListPaddingRight(), MeasureSpec.EXACTLY); - int hs = MeasureSpec.makeMeasureSpec(heightSize, heightMode); - pinnedView.measure(ws, hs); - pinnedView.layout(0, 0, pinnedView.getMeasuredWidth(), pinnedView.getMeasuredHeight()); - mTranslateY = 0; - - // initialize pinned shadow - pinnedShadow.view = pinnedView; - pinnedShadow.position = position; - pinnedShadow.id = getAdapter().getItemId(position); - - // store pinned shadow - mPinnedSection = pinnedShadow; - } - - /** Destroy shadow wrapper for currently pinned view */ - void destroyPinnedShadow() { - if (mPinnedSection != null) { - // keep shadow for being recycled later - mRecycleSection = mPinnedSection; - mPinnedSection = null; - } - } - - /** Makes sure we have an actual pinned shadow for given position. */ - void ensureShadowForPosition(int sectionPosition, int firstVisibleItem, int visibleItemCount) { - if (visibleItemCount < 2) { // no need for creating shadow at all, we have a single visible item - destroyPinnedShadow(); - return; - } - - if (mPinnedSection != null - && mPinnedSection.position != sectionPosition) { // invalidate shadow, if required - destroyPinnedShadow(); - } - - if (mPinnedSection == null) { // create shadow, if empty - createPinnedShadow(sectionPosition); - } - - // align shadow according to next section position, if needed - int nextPosition = sectionPosition + 1; - if (nextPosition < getCount()) { - int nextSectionPosition = findFirstVisibleSectionPosition(nextPosition, - visibleItemCount - (nextPosition - firstVisibleItem)); - if (nextSectionPosition > -1) { - View nextSectionView = getChildAt(nextSectionPosition - firstVisibleItem); - final int bottom = mPinnedSection.view.getBottom() + getPaddingTop(); - mSectionsDistanceY = nextSectionView.getTop() - bottom; - if (mSectionsDistanceY < 0) { - // next section overlaps pinned shadow, move it up - mTranslateY = mSectionsDistanceY; - } else { - // next section does not overlap with pinned, stick to top - mTranslateY = 0; - } - } else { - // no other sections are visible, stick to top - mTranslateY = 0; - mSectionsDistanceY = Integer.MAX_VALUE; - } - } - - } - - int findFirstVisibleSectionPosition(int firstVisibleItem, int visibleItemCount) { - ListAdapter adapter = getAdapter(); - for (int childIndex = 0; childIndex < visibleItemCount; childIndex++) { - int position = firstVisibleItem + childIndex; - int viewType = adapter.getItemViewType(position); - if (isItemViewTypePinned(adapter, viewType)) return position; - } - return -1; - } - - int findCurrentSectionPosition(int fromPosition) { - ListAdapter adapter = getAdapter(); - - if (adapter instanceof SectionIndexer) { - // try fast way by asking section indexer - SectionIndexer indexer = (SectionIndexer) adapter; - int sectionPosition = indexer.getSectionForPosition(fromPosition); - int itemPosition = indexer.getPositionForSection(sectionPosition); - int typeView = adapter.getItemViewType(itemPosition); - if (isItemViewTypePinned(adapter, typeView)) { - return itemPosition; - } // else, no luck - } - - // try slow way by looking through to the next section item above - for (int position=fromPosition; position>=0; position--) { - int viewType = adapter.getItemViewType(position); - if (isItemViewTypePinned(adapter, viewType)) return position; - } - return -1; // no candidate found - } - - void recreatePinnedShadow() { - destroyPinnedShadow(); - ListAdapter adapter = getAdapter(); - if (adapter != null && adapter.getCount() > 0) { - int firstVisiblePosition = getFirstVisiblePosition(); - int sectionPosition = findCurrentSectionPosition(firstVisiblePosition); - if (sectionPosition == -1) return; // no views to pin, exit - ensureShadowForPosition(sectionPosition, - firstVisiblePosition, getLastVisiblePosition() - firstVisiblePosition); - } - } - - @Override - public void setOnScrollListener(OnScrollListener listener) { - if (listener == mOnScrollListener) { - super.setOnScrollListener(listener); - } else { - mDelegateOnScrollListener = listener; - } - } - - @Override - public void onRestoreInstanceState(Parcelable state) { - super.onRestoreInstanceState(state); - post(new Runnable() { - @Override public void run() { // restore pinned view after configuration change - recreatePinnedShadow(); - } - }); - } - - @Override - public void setAdapter(ListAdapter adapter) { - - // assert adapter in debug mode - if (BuildConfig.DEBUG && adapter != null) { - if (!(adapter instanceof PinnedSectionListAdapter)) - throw new IllegalArgumentException("Does your adapter implement PinnedSectionListAdapter?"); - if (adapter.getViewTypeCount() < 2) - throw new IllegalArgumentException("Does your adapter handle at least two types" + - " of views in getViewTypeCount() method: items and sections?"); - } - - // unregister observer at old adapter and register on new one - ListAdapter oldAdapter = getAdapter(); - if (oldAdapter != null) oldAdapter.unregisterDataSetObserver(mDataSetObserver); - if (adapter != null) adapter.registerDataSetObserver(mDataSetObserver); - - // destroy pinned shadow, if new adapter is not same as old one - if (oldAdapter != adapter) destroyPinnedShadow(); - - super.setAdapter(adapter); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - if (mPinnedSection != null) { - int parentWidth = r - l - getPaddingLeft() - getPaddingRight(); - int shadowWidth = mPinnedSection.view.getWidth(); - if (parentWidth != shadowWidth) { - recreatePinnedShadow(); - } - } - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - - if (mPinnedSection != null) { - - // prepare variables - int pLeft = getListPaddingLeft(); - int pTop = getListPaddingTop(); - View view = mPinnedSection.view; - - // draw child - canvas.save(); - - int clipHeight = view.getHeight() + - (mShadowDrawable == null ? 0 : Math.min(mShadowHeight, mSectionsDistanceY)); - canvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight); - - canvas.translate(pLeft, pTop + mTranslateY); - drawChild(canvas, mPinnedSection.view, getDrawingTime()); - - if (mShadowDrawable != null && mSectionsDistanceY > 0) { - mShadowDrawable.setBounds(mPinnedSection.view.getLeft(), - mPinnedSection.view.getBottom(), - mPinnedSection.view.getRight(), - mPinnedSection.view.getBottom() + mShadowHeight); - mShadowDrawable.draw(canvas); - } - - canvas.restore(); - } - } - - //-- touch handling methods - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - - final float x = ev.getX(); - final float y = ev.getY(); - final int action = ev.getAction(); - - if (action == MotionEvent.ACTION_DOWN - && mTouchTarget == null - && mPinnedSection != null - && isPinnedViewTouched(mPinnedSection.view, x, y)) { // create touch target - - // user touched pinned view - mTouchTarget = mPinnedSection.view; - mTouchPoint.x = x; - mTouchPoint.y = y; - - // copy down event for eventually be used later - mDownEvent = MotionEvent.obtain(ev); - } - - if (mTouchTarget != null) { - if (isPinnedViewTouched(mTouchTarget, x, y)) { // forward event to pinned view - mTouchTarget.dispatchTouchEvent(ev); - } - - if (action == MotionEvent.ACTION_UP) { // perform onClick on pinned view - super.dispatchTouchEvent(ev); - performPinnedItemClick(); - clearTouchTarget(); - - } else if (action == MotionEvent.ACTION_CANCEL) { // cancel - clearTouchTarget(); - - } else if (action == MotionEvent.ACTION_MOVE) { - if (Math.abs(y - mTouchPoint.y) > mTouchSlop) { - - // cancel sequence on touch target - MotionEvent event = MotionEvent.obtain(ev); - event.setAction(MotionEvent.ACTION_CANCEL); - mTouchTarget.dispatchTouchEvent(event); - event.recycle(); - - // provide correct sequence to super class for further handling - super.dispatchTouchEvent(mDownEvent); - super.dispatchTouchEvent(ev); - clearTouchTarget(); - - } - } - - return true; - } - - // call super if this was not our pinned view - return super.dispatchTouchEvent(ev); - } - - private boolean isPinnedViewTouched(View view, float x, float y) { - view.getHitRect(mTouchRect); - - // by taping top or bottom padding, the list performs on click on a border item. - // we don't add top padding here to keep behavior consistent. - mTouchRect.top += mTranslateY; - - mTouchRect.bottom += mTranslateY + getPaddingTop(); - mTouchRect.left += getPaddingLeft(); - mTouchRect.right -= getPaddingRight(); - return mTouchRect.contains((int)x, (int)y); - } - - private void clearTouchTarget() { - mTouchTarget = null; - if (mDownEvent != null) { - mDownEvent.recycle(); - mDownEvent = null; - } - } - - private boolean performPinnedItemClick() { - if (mPinnedSection == null) return false; - - OnItemClickListener listener = getOnItemClickListener(); - if (listener != null) { - View view = mPinnedSection.view; - playSoundEffect(SoundEffectConstants.CLICK); - if (view != null) { - view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); - } - listener.onItemClick(this, view, mPinnedSection.position, mPinnedSection.id); - return true; - } - return false; - } - - public static boolean isItemViewTypePinned(ListAdapter adapter, int viewType) { - if (adapter instanceof HeaderViewListAdapter) { - adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter(); - } - return ((PinnedSectionListAdapter) adapter).isItemViewTypePinned(viewType); - } - -} diff --git a/libraries/pinned-section-listview/screen1.png b/libraries/pinned-section-listview/screen1.png deleted file mode 100644 index 9cca20109..000000000 Binary files a/libraries/pinned-section-listview/screen1.png and /dev/null differ diff --git a/libraries/pinned-section-listview/screen2.png b/libraries/pinned-section-listview/screen2.png deleted file mode 100644 index ad59f6f2f..000000000 Binary files a/libraries/pinned-section-listview/screen2.png and /dev/null differ diff --git a/libraries/pinned-section-listview/screen3.png b/libraries/pinned-section-listview/screen3.png deleted file mode 100644 index 0fd528fa9..000000000 Binary files a/libraries/pinned-section-listview/screen3.png and /dev/null differ diff --git a/settings.gradle b/settings.gradle index 2e582798c..08454c958 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,3 @@ include ':OpenPGP-Keychain' include ':libraries:ActionBarSherlock' -include ':libraries:HtmlTextView' -include ':libraries:pinned-section-listview:library' \ No newline at end of file +include ':libraries:HtmlTextView' \ No newline at end of file -- cgit v1.2.3