diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java index b5a400408..276598f4b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -128,6 +128,9 @@ public class KeychainContract { public static final String BASE_API_APPS = "api_apps"; public static final String PATH_ALLOWED_KEYS = "allowed_keys"; + public static final String PATH_BY_PACKAGE_NAME = "by_package_name"; + public static final String PATH_BY_KEY_ID = "by_key_id"; + public static final String BASE_TRUST_IDENTITIES = "trust_ids"; public static class KeyRings implements BaseColumns, KeysColumns, UserPacketsColumns { @@ -345,24 +348,12 @@ public class KeychainContract { public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() .appendPath(BASE_TRUST_IDENTITIES).build(); - /** - * Use if multiple items get returned - */ - public static final String CONTENT_TYPE - = "vnd.android.cursor.dir/vnd.org.sufficientlysecure.keychain.provider.trust_ids"; - - /** - * Use if a single item is returned - */ - public static final String CONTENT_ITEM_TYPE - = "vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.provider.trust_ids"; - - public static Uri buildByPackageNameUri(String packageName) { - return CONTENT_URI.buildUpon().appendEncodedPath(packageName).build(); + public static Uri buildByKeyUri(Uri uri) { + return CONTENT_URI.buildUpon().appendPath(PATH_BY_KEY_ID).appendPath(uri.getPathSegments().get(1)).build(); } - public static Uri buildByPackageNameAndTrustIdUri(String packageName, String trustId) { - return CONTENT_URI.buildUpon().appendEncodedPath(packageName).appendEncodedPath(trustId).build(); + public static Uri buildByPackageNameAndTrustId(String packageName, String trustId) { + return CONTENT_URI.buildUpon().appendPath(PATH_BY_PACKAGE_NAME).appendPath(packageName).appendPath(trustId).build(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 672a00134..fc7c93eea 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -79,6 +79,10 @@ public class KeychainProvider extends ContentProvider { private static final int UPDATED_KEYS = 500; private static final int UPDATED_KEYS_SPECIFIC = 501; + private static final int TRUST_IDS_BY_MASTER_KEY_ID = 601; + private static final int TRUST_IDS_BY_PACKAGE_NAME = 602; + private static final int TRUST_IDS_BY_PACKAGE_NAME_AND_TRUST_ID = 603; + protected UriMatcher mUriMatcher; /** @@ -191,6 +195,22 @@ public class KeychainProvider extends ContentProvider { matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/" + KeychainContract.PATH_ALLOWED_KEYS, API_ALLOWED_KEYS); + /** + * Trust Identity access + * + *
+         * trust_ids/by_key_id/_
+         *
+         * 
+ */ + matcher.addURI(authority, KeychainContract.BASE_TRUST_IDENTITIES + "/" + + KeychainContract.PATH_BY_KEY_ID + "/*", TRUST_IDS_BY_MASTER_KEY_ID); + matcher.addURI(authority, KeychainContract.BASE_TRUST_IDENTITIES + "/" + + KeychainContract.PATH_BY_PACKAGE_NAME + "/*", TRUST_IDS_BY_PACKAGE_NAME); + matcher.addURI(authority, KeychainContract.BASE_TRUST_IDENTITIES + "/" + + KeychainContract.PATH_BY_PACKAGE_NAME + "/*/*", TRUST_IDS_BY_PACKAGE_NAME_AND_TRUST_ID); + + /** * to access table containing last updated dates of keys */ @@ -636,6 +656,45 @@ public class KeychainProvider extends ContentProvider { break; } + case TRUST_IDS_BY_MASTER_KEY_ID: + case TRUST_IDS_BY_PACKAGE_NAME: + case TRUST_IDS_BY_PACKAGE_NAME_AND_TRUST_ID: { + if (selection != null || selectionArgs != null) { + throw new UnsupportedOperationException(); + } + + HashMap projectionMap = new HashMap<>(); + projectionMap.put(ApiTrustIdentity._ID, "oid AS " + ApiTrustIdentity._ID); + projectionMap.put(ApiTrustIdentity.PACKAGE_NAME, ApiTrustIdentity.PACKAGE_NAME); + projectionMap.put(ApiTrustIdentity.IDENTIFIER, ApiTrustIdentity.IDENTIFIER); + projectionMap.put(ApiTrustIdentity.MASTER_KEY_ID, ApiTrustIdentity.MASTER_KEY_ID); + projectionMap.put(ApiTrustIdentity.LAST_UPDATED, ApiTrustIdentity.LAST_UPDATED); + qb.setProjectionMap(projectionMap); + + qb.setTables(Tables.API_TRUST_IDENTITIES); + + if (match == TRUST_IDS_BY_MASTER_KEY_ID) { + long masterKeyId = Long.parseLong(uri.getLastPathSegment()); + + selection = Tables.API_TRUST_IDENTITIES + "." + ApiTrustIdentity.MASTER_KEY_ID + " = ?"; + selectionArgs = new String[] { Long.toString(masterKeyId) }; + } else if (match == TRUST_IDS_BY_PACKAGE_NAME) { + String packageName = uri.getPathSegments().get(2); + + selection = Tables.API_TRUST_IDENTITIES + "." + ApiTrustIdentity.PACKAGE_NAME + " = ?"; + selectionArgs = new String[] { packageName }; + } else { // TRUST_IDS_BY_PACKAGE_NAME_AND_TRUST_ID + String packageName = uri.getPathSegments().get(2); + String trustId = uri.getPathSegments().get(3); + + selection = Tables.API_TRUST_IDENTITIES + "." + ApiTrustIdentity.PACKAGE_NAME + " = ? AND " + + Tables.API_TRUST_IDENTITIES + "." + ApiTrustIdentity.IDENTIFIER + " = ?"; + selectionArgs = new String[] { packageName, trustId }; + } + + break; + } + case UPDATED_KEYS: case UPDATED_KEYS_SPECIFIC: { HashMap projectionMap = new HashMap<>(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/KeychainExternalProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/KeychainExternalProvider.java index 82fa1a4f2..ff441abe0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/KeychainExternalProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/KeychainExternalProvider.java @@ -28,6 +28,7 @@ import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; +import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; @@ -285,6 +286,9 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC if (cursor != null) { // Tell the cursor what uri to watch, so it knows when its source data changes cursor.setNotificationUri(getContext().getContentResolver(), uri); + if (Constants.DEBUG_LOG_DB_QUERIES) { + DatabaseUtils.dumpCursor(cursor); + } } Log.d(Constants.TAG, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TrustIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TrustIdsAdapter.java new file mode 100644 index 000000000..8fd427b31 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TrustIdsAdapter.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 Vincent Breitmoser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.ui.adapter; + + +import java.util.HashMap; + +import android.app.Activity; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.support.v4.content.CursorLoader; +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; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.KeychainContract.ApiTrustIdentity; + + +public class TrustIdsAdapter extends CursorAdapter { + private static final String[] TRUST_IDS_PROJECTION = new String[] { + ApiTrustIdentity._ID, + ApiTrustIdentity.PACKAGE_NAME, + ApiTrustIdentity.IDENTIFIER, + }; + private static final int INDEX_PACKAGE_NAME = 1; + private static final int INDEX_TRUST_ID = 2; + + + protected LayoutInflater mInflater; + private HashMap appIconCache = new HashMap<>(); + + + public TrustIdsAdapter(Context context, Cursor c, int flags) { + super(context, c, flags); + mInflater = LayoutInflater.from(context); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + String packageName = cursor.getString(INDEX_PACKAGE_NAME); + String trustId = cursor.getString(INDEX_TRUST_ID); + + TextView vTrustId = (TextView) view.findViewById(R.id.trust_id_name); + ImageView vAppIcon = (ImageView) view.findViewById(R.id.trust_id_app_icon); + + Drawable drawable = getDrawableForPackageName(packageName); + vTrustId.setText(trustId); + vAppIcon.setImageDrawable(drawable); + } + + private Drawable getDrawableForPackageName(String packageName) { + if (appIconCache.containsKey(packageName)) { + return appIconCache.get(packageName); + } + + PackageManager pm = mContext.getPackageManager(); + try { + ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); + + Drawable appIcon = pm.getApplicationIcon(ai); + appIconCache.put(packageName, appIcon); + + return appIcon; + } catch (PackageManager.NameNotFoundException e) { + return null; + } + } + + public static CursorLoader createLoader(Context context, Uri dataUri) { + Uri baseUri = ApiTrustIdentity.buildByKeyUri(dataUri); + return new CursorLoader(context, baseUri, TrustIdsAdapter.TRUST_IDS_PROJECTION, null, null, null); + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mInflater.inflate(R.layout.view_key_trust_id_item, parent, false); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java index a5e6af591..f6629bd1a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java @@ -37,11 +37,14 @@ import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter; import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter; import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyserverStatusPresenter; import org.sufficientlysecure.keychain.ui.keyview.presenter.SystemContactPresenter; +import org.sufficientlysecure.keychain.ui.keyview.presenter.TrustIdsPresenter; import org.sufficientlysecure.keychain.ui.keyview.presenter.ViewKeyMvpView; import org.sufficientlysecure.keychain.ui.keyview.view.IdentitiesCardView; import org.sufficientlysecure.keychain.ui.keyview.view.KeyHealthView; import org.sufficientlysecure.keychain.ui.keyview.view.KeyserverStatusView; import org.sufficientlysecure.keychain.ui.keyview.view.SystemContactCardView; +import org.sufficientlysecure.keychain.ui.keyview.view.TrustIdsIdCardView; +import org.sufficientlysecure.keychain.util.Preferences; public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { @@ -54,10 +57,14 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { private static final int LOADER_ID_LINKED_CONTACT = 2; private static final int LOADER_ID_SUBKEY_STATUS = 3; private static final int LOADER_ID_KEYSERVER_STATUS = 4; + private static final int LOADER_ID_TRUST_IDS = 5; private IdentitiesCardView mIdentitiesCardView; private IdentitiesPresenter mIdentitiesPresenter; + private TrustIdsIdCardView mTrustIdsCard; + private TrustIdsPresenter mTrustIdsPresenter; + SystemContactCardView mSystemContactCard; SystemContactPresenter mSystemContactPresenter; @@ -88,6 +95,8 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { mIdentitiesCardView = (IdentitiesCardView) view.findViewById(R.id.card_identities); + mTrustIdsCard = (TrustIdsIdCardView) view.findViewById(R.id.view_key_card_trust_ids); + mSystemContactCard = (SystemContactCardView) view.findViewById(R.id.linked_system_contact_card); mKeyStatusHealth = (KeyHealthView) view.findViewById(R.id.key_status_health); mKeyStatusKeyserver = (KeyserverStatusView) view.findViewById(R.id.key_status_keyserver); @@ -117,6 +126,10 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { mKeyserverStatusPresenter = new KeyserverStatusPresenter( getContext(), mKeyStatusKeyserver, LOADER_ID_KEYSERVER_STATUS, masterKeyId, mIsSecret); mKeyserverStatusPresenter.startLoader(getLoaderManager()); + + mTrustIdsPresenter = new TrustIdsPresenter( + getContext(), mTrustIdsCard, LOADER_ID_TRUST_IDS, masterKeyId, false); + mTrustIdsPresenter.startLoader(getLoaderManager()); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/TrustIdsPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/TrustIdsPresenter.java new file mode 100644 index 000000000..b33497958 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/TrustIdsPresenter.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2017 Vincent Breitmoser + * + * 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.keyview.presenter; + + +import android.content.Context; +import android.database.Cursor; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.Loader; + +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.ui.adapter.TrustIdsAdapter; +import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; + + +public class TrustIdsPresenter implements LoaderCallbacks { + private final Context context; + private final TrustIdsMvpView view; + private final int loaderId; + + private final TrustIdsAdapter trustIdsAdapter; + + private final long masterKeyId; + private final boolean isSecret; + + public TrustIdsPresenter(Context context, TrustIdsMvpView view, int loaderId, long masterKeyId, boolean isSecret) { + this.context = context; + this.view = view; + this.loaderId = loaderId; + + this.masterKeyId = masterKeyId; + this.isSecret = isSecret; + + trustIdsAdapter = new TrustIdsAdapter(context, null, 0); + view.setTrustIdAdapter(trustIdsAdapter); + + view.setTrustIdClickListener(new TrustIdsClickListener() { + @Override + public void onTrustIdItemClick(int position) { + + } + }); + } + + public void startLoader(LoaderManager loaderManager) { + loaderManager.restartLoader(loaderId, null, this); + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return TrustIdsAdapter.createLoader(context, KeyRings.buildUnifiedKeyRingUri(masterKeyId)); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + trustIdsAdapter.swapCursor(data); + view.showCard(trustIdsAdapter.getCount() > 0); + } + + @Override + public void onLoaderReset(Loader loader) { + trustIdsAdapter.swapCursor(null); + } + + public interface TrustIdsMvpView { + void setTrustIdAdapter(TrustIdsAdapter trustIdsAdapter); + void showCard(boolean show); + + void setTrustIdClickListener(TrustIdsClickListener trustIdsClickListener); + } + + public interface TrustIdsClickListener { + void onTrustIdItemClick(int position); + } +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/TrustIdsIdCardView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/TrustIdsIdCardView.java new file mode 100644 index 000000000..93fa03750 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/TrustIdsIdCardView.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 Vincent Breitmoser + * + * 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.keyview.view; + + +import android.content.Context; +import android.support.v7.widget.CardView; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.Button; +import android.widget.ListView; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter; +import org.sufficientlysecure.keychain.ui.adapter.TrustIdsAdapter; +import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; +import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter.IdentitiesCardListener; +import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter.IdentitiesMvpView; +import org.sufficientlysecure.keychain.ui.keyview.presenter.LinkedIdentitiesPresenter.LinkedIdsClickListener; +import org.sufficientlysecure.keychain.ui.keyview.presenter.LinkedIdentitiesPresenter.LinkedIdsMvpView; +import org.sufficientlysecure.keychain.ui.keyview.presenter.TrustIdsPresenter.TrustIdsClickListener; +import org.sufficientlysecure.keychain.ui.keyview.presenter.TrustIdsPresenter.TrustIdsMvpView; + + +public class TrustIdsIdCardView extends CardView implements TrustIdsMvpView { + private ListView vTrustIds; + + private TrustIdsClickListener trustIdsClickListener; + + public TrustIdsIdCardView(Context context, AttributeSet attrs) { + super(context, attrs); + + View view = LayoutInflater.from(context).inflate(R.layout.trust_ids_card, this, true); + + vTrustIds = (ListView) view.findViewById(R.id.view_key_trust_ids); + vTrustIds.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (trustIdsClickListener != null) { + trustIdsClickListener.onTrustIdItemClick(position); + } + } + }); + } + + @Override + public void setTrustIdAdapter(TrustIdsAdapter trustIdsAdapter) { + vTrustIds.setAdapter(trustIdsAdapter); + } + + @Override + public void showCard(boolean show) { + setVisibility(show ? View.VISIBLE : View.GONE); + } + + @Override + public void setTrustIdClickListener(TrustIdsClickListener trustIdsClickListener) { + this.trustIdsClickListener = trustIdsClickListener; + } +} diff --git a/OpenKeychain/src/main/res/layout/trust_ids_card.xml b/OpenKeychain/src/main/res/layout/trust_ids_card.xml new file mode 100644 index 000000000..f99d73c10 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/trust_ids_card.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/view_key_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_fragment.xml index 16fa99c97..8f2b443b5 100644 --- a/OpenKeychain/src/main/res/layout/view_key_fragment.xml +++ b/OpenKeychain/src/main/res/layout/view_key_fragment.xml @@ -51,6 +51,17 @@ + + + + + + + + +