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 @@
+
+
+
+
+
+
+
+
+