New key view design, using Android flat buttons and Android icons

This commit is contained in:
Dominik Schürmann 2014-05-05 00:58:22 +02:00
parent 4053e1ebd7
commit 6055b0b0da
50 changed files with 1793 additions and 599 deletions

View file

@ -147,7 +147,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
}
Log.e(Constants.TAG, "uri: " + mDataUri);
mUserIds = (ListView) findViewById(R.id.user_ids);
mUserIds = (ListView) findViewById(R.id.view_key_user_ids);
mUserIdsAdapter = new ViewKeyUserIdsAdapter(this, null, 0, true);
mUserIds.setAdapter(mUserIdsAdapter);
@ -203,7 +203,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
byte[] fingerprintBlob = data.getBlob(INDEX_FINGERPRINT);
String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
((TextView) findViewById(R.id.fingerprint))
((TextView) findViewById(R.id.view_key_fingerprint))
.setText(PgpKeyHelper.colorizeFingerprint(fingerprint));
}
break;

View file

@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.ui;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
@ -31,6 +32,9 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
@ -42,20 +46,19 @@ import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment;
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.SlidingTabLayout;
import java.io.IOException;
import java.util.HashMap;
public class ViewKeyActivity extends ActionBarActivity {
public class ViewKeyActivity extends ActionBarActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
ExportHelper mExportHelper;
ProviderHelper mProviderHelper;
@ -63,9 +66,15 @@ public class ViewKeyActivity extends ActionBarActivity {
protected Uri mDataUri;
public static final String EXTRA_SELECTED_TAB = "selectedTab";
public static final int TAB_MAIN = 0;
public static final int TAB_SHARE = 1;
public static final int TAB_KEYS = 2;
public static final int TAB_CERTS = 3;
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
// view
private ViewPager mViewPager;
private SlidingTabLayout mSlidingTabLayout;
private PagerTabStripAdapter mTabsAdapter;
public static final int REQUEST_CODE_LOOKUP_KEY = 0x00007006;
@ -76,6 +85,9 @@ public class ViewKeyActivity extends ActionBarActivity {
private byte[] mNfcKeyringBytes;
private static final int NFC_SENT = 1;
private static final int LOADER_ID_UNIFIED = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
@ -89,33 +101,67 @@ public class ViewKeyActivity extends ActionBarActivity {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setIcon(android.R.color.transparent);
actionBar.setHomeButtonEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
setContentView(R.layout.view_key_activity);
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager = (ViewPager) findViewById(R.id.view_key_pager);
mSlidingTabLayout = (SlidingTabLayout) findViewById(R.id.view_key_sliding_tab_layout);
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter = new PagerTabStripAdapter(this);
mViewPager.setAdapter(mTabsAdapter);
int selectedTab = 0;
int switchToTab = TAB_MAIN;
Intent intent = getIntent();
if (intent.getExtras() != null && intent.getExtras().containsKey(EXTRA_SELECTED_TAB)) {
selectedTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB);
switchToTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB);
}
mDataUri = getIntent().getData();
Uri dataUri = getIntent().getData();
if (dataUri == null) {
Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
finish();
return;
}
initNfc(mDataUri);
loadData(dataUri);
initNfc(dataUri);
Bundle mainBundle = new Bundle();
mainBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, mDataUri);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.key_view_tab_main)),
ViewKeyMainFragment.class, mainBundle, (selectedTab == 0));
mainBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, dataUri);
mTabsAdapter.addTab(ViewKeyMainFragment.class,
mainBundle, getString(R.string.key_view_tab_main));
Bundle shareBundle = new Bundle();
shareBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, dataUri);
mTabsAdapter.addTab(ViewKeyShareFragment.class,
mainBundle, getString(R.string.key_view_tab_share));
Bundle keyDetailsBundle = new Bundle();
keyDetailsBundle.putParcelable(ViewKeyKeysFragment.ARG_DATA_URI, dataUri);
mTabsAdapter.addTab(ViewKeyKeysFragment.class,
keyDetailsBundle, getString(R.string.key_view_tab_keys_details));
Bundle certBundle = new Bundle();
certBundle.putParcelable(ViewKeyCertsFragment.ARG_DATA_URI, mDataUri);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.key_view_tab_certs)),
ViewKeyCertsFragment.class, certBundle, (selectedTab == 1));
certBundle.putParcelable(ViewKeyCertsFragment.ARG_DATA_URI, dataUri);
mTabsAdapter.addTab(ViewKeyCertsFragment.class,
certBundle, getString(R.string.key_view_tab_certs));
// NOTE: must be after adding the tabs!
mSlidingTabLayout.setViewPager(mViewPager);
// switch to tab selected by extra
mViewPager.setCurrentItem(switchToTab);
}
private void loadData(Uri dataUri) {
mDataUri = dataUri;
Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
// Prepare the loaders. Either re-connect with an existing ones,
// or start new ones.
getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
}
@Override
@ -143,24 +189,6 @@ public class ViewKeyActivity extends ActionBarActivity {
case R.id.menu_key_view_export_file:
exportToFile(mDataUri, mExportHelper, mProviderHelper);
return true;
case R.id.menu_key_view_share_default_fingerprint:
shareKey(mDataUri, true, mProviderHelper);
return true;
case R.id.menu_key_view_share_default:
shareKey(mDataUri, false, mProviderHelper);
return true;
case R.id.menu_key_view_share_qr_code_fingerprint:
shareKeyQrCode(mDataUri, true);
return true;
case R.id.menu_key_view_share_qr_code:
shareKeyQrCode(mDataUri, false);
return true;
case R.id.menu_key_view_share_nfc:
shareNfc();
return true;
case R.id.menu_key_view_share_clipboard:
copyToClipboard(mDataUri, mProviderHelper);
return true;
case R.id.menu_key_view_delete: {
deleteKey(mDataUri, mExportHelper);
return true;
@ -209,84 +237,6 @@ public class ViewKeyActivity extends ActionBarActivity {
startActivityForResult(queryIntent, REQUEST_CODE_LOOKUP_KEY);
}
private void shareKey(Uri dataUri, boolean fingerprintOnly, ProviderHelper providerHelper)
throws ProviderHelper.NotFoundException {
String content = null;
if (fingerprintOnly) {
byte[] data = (byte[]) providerHelper.getGenericData(
KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
if (data != null) {
String fingerprint = PgpKeyHelper.convertFingerprintToHex(data);
content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
} else {
AppMsg.makeText(this, "Bad key selected!",
AppMsg.STYLE_ALERT).show();
return;
}
} else {
// get public keyring as ascii armored string
try {
Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri);
content = providerHelper.getKeyRingAsArmoredString(uri);
// Android will fail with android.os.TransactionTooLargeException if key is too big
// see http://www.lonestarprod.com/?p=34
if (content.length() >= 86389) {
AppMsg.makeText(this, R.string.key_too_big_for_sharing,
AppMsg.STYLE_ALERT).show();
return;
}
} catch (IOException e) {
Log.e(Constants.TAG, "error processing key!", e);
AppMsg.makeText(this, R.string.error_invalid_data, AppMsg.STYLE_ALERT).show();
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
AppMsg.makeText(this, R.string.error_key_not_found, AppMsg.STYLE_ALERT).show();
}
}
if (content != null) {
// let user choose application
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, content);
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent,
getResources().getText(R.string.action_share_key_with)));
} else {
Log.e(Constants.TAG, "content is null!");
}
}
private void shareKeyQrCode(Uri dataUri, boolean fingerprintOnly) {
ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(dataUri,
fingerprintOnly);
dialog.show(getSupportFragmentManager(), "shareQrCodeDialog");
}
private void copyToClipboard(Uri dataUri, ProviderHelper providerHelper) {
// get public keyring as ascii armored string
try {
Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri);
String keyringArmored = providerHelper.getKeyRingAsArmoredString(uri);
ClipboardReflection.copyToClipboard(this, keyringArmored);
AppMsg.makeText(this, R.string.key_copied_to_clipboard, AppMsg.STYLE_INFO)
.show();
} catch (IOException e) {
Log.e(Constants.TAG, "error processing key!", e);
AppMsg.makeText(this, R.string.error_key_processing, AppMsg.STYLE_ALERT).show();
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
AppMsg.makeText(this, R.string.error_key_not_found, AppMsg.STYLE_ALERT).show();
}
}
private void shareNfc() {
ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance();
dialog.show(getSupportFragmentManager(), "shareNfcDialog");
}
private void deleteKey(Uri dataUri, ExportHelper exportHelper) {
// Message is received after key is deleted
Handler returnHandler = new Handler() {
@ -409,4 +359,63 @@ public class ViewKeyActivity extends ActionBarActivity {
}
};
static final String[] UNIFIED_PROJECTION = new String[]{
KeychainContract.KeyRings._ID,
KeychainContract.KeyRings.MASTER_KEY_ID,
KeychainContract.KeyRings.USER_ID,
};
static final int INDEX_UNIFIED_MASTER_KEY_ID = 1;
static final int INDEX_UNIFIED_USER_ID = 2;
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
case LOADER_ID_UNIFIED: {
Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(mDataUri);
return new CursorLoader(this, baseUri, UNIFIED_PROJECTION, null, null, null);
}
default:
return null;
}
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
/* TODO better error handling? May cause problems when a key is deleted,
* because the notification triggers faster than the activity closes.
*/
// Avoid NullPointerExceptions...
if (data.getCount() == 0) {
return;
}
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
switch (loader.getId()) {
case LOADER_ID_UNIFIED: {
if (data.moveToFirst()) {
// get name, email, and comment from USER_ID
String[] mainUserId = PgpKeyHelper.splitUserId(data.getString(INDEX_UNIFIED_USER_ID));
if (mainUserId[0] != null) {
setTitle(mainUserId[0]);
} else {
setTitle(R.string.user_id_no_name);
}
// get key id from MASTER_KEY_ID
long masterKeyId = data.getLong(INDEX_UNIFIED_MASTER_KEY_ID);
String keyIdStr = PgpKeyHelper.convertKeyIdToHex(masterKeyId);
getSupportActionBar().setSubtitle(keyIdStr);
break;
}
}
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
}

View file

@ -75,6 +75,9 @@ public class ViewKeyCertsFragment extends Fragment
private Uri mDataUri;
// starting with 4 for this fragment
private static final int LOADER_ID = 4;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.view_key_certs_fragment, container, false);
@ -112,7 +115,7 @@ public class ViewKeyCertsFragment extends Fragment
mAdapter = new CertListAdapter(getActivity(), null);
mStickyList.setAdapter(mAdapter);
getLoaderManager().initLoader(0, null, this);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
@Override
@ -208,11 +211,18 @@ public class ViewKeyCertsFragment extends Fragment
// set name and stuff, common to both key types
TextView wSignerKeyId = (TextView) view.findViewById(R.id.signerKeyId);
TextView wSignerUserId = (TextView) view.findViewById(R.id.signerUserId);
TextView wSignerName = (TextView) view.findViewById(R.id.signerName);
TextView wSignStatus = (TextView) view.findViewById(R.id.signStatus);
String signerKeyId = PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexSignerKeyId));
String signerUserId = cursor.getString(mIndexSignerUserId);
String[] userId = PgpKeyHelper.splitUserId(cursor.getString(mIndexSignerUserId));
if (userId[0] != null) {
wSignerName.setText(userId[0]);
} else {
wSignerName.setText(R.string.user_id_no_name);
}
wSignerKeyId.setText(signerKeyId);
switch (cursor.getInt(mIndexType)) {
case PGPSignature.DEFAULT_CERTIFICATION: // 0x10
wSignStatus.setText(R.string.cert_default);
@ -231,8 +241,6 @@ public class ViewKeyCertsFragment extends Fragment
break;
}
wSignerUserId.setText(signerUserId);
wSignerKeyId.setText(signerKeyId);
view.setTag(R.id.tag_mki, cursor.getLong(mIndexMasterKeyId));
view.setTag(R.id.tag_rank, cursor.getLong(mIndexRank));

View file

@ -0,0 +1,238 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter;
import org.sufficientlysecure.keychain.util.Log;
import java.util.Date;
public class ViewKeyKeysFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "uri";
private LinearLayout mContainer;
private TextView mAlgorithm;
private TextView mKeyId;
private TextView mExpiry;
private TextView mCreation;
private TextView mFingerprint;
private TextView mSecretKey;
private ListView mKeys;
private static final int LOADER_ID_UNIFIED = 0;
private static final int LOADER_ID_KEYS = 1;
private ViewKeyKeysAdapter mKeysAdapter;
private Uri mDataUri;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.view_key_keys_fragment, container, false);
mContainer = (LinearLayout) view.findViewById(R.id.container);
mKeyId = (TextView) view.findViewById(R.id.key_id);
mAlgorithm = (TextView) view.findViewById(R.id.algorithm);
mCreation = (TextView) view.findViewById(R.id.creation);
mExpiry = (TextView) view.findViewById(R.id.expiry);
mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint);
mSecretKey = (TextView) view.findViewById(R.id.secret_key);
mKeys = (ListView) view.findViewById(R.id.keys);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Uri dataUri = getArguments().getParcelable(ARG_DATA_URI);
if (dataUri == null) {
Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
getActivity().finish();
return;
}
loadData(dataUri);
}
private void loadData(Uri dataUri) {
getActivity().setProgressBarIndeterminateVisibility(true);
mContainer.setVisibility(View.GONE);
mDataUri = dataUri;
Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
mKeysAdapter = new ViewKeyKeysAdapter(getActivity(), null, 0);
mKeys.setAdapter(mKeysAdapter);
// Prepare the loaders. Either re-connect with an existing ones,
// or start new ones.
getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
getLoaderManager().initLoader(LOADER_ID_KEYS, null, this);
}
static final String[] UNIFIED_PROJECTION = new String[] {
KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET,
KeyRings.USER_ID, KeyRings.FINGERPRINT,
KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY,
};
static final int INDEX_UNIFIED_MKI = 1;
static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2;
static final int INDEX_UNIFIED_UID = 3;
static final int INDEX_UNIFIED_FINGERPRINT = 4;
static final int INDEX_UNIFIED_ALGORITHM = 5;
static final int INDEX_UNIFIED_KEY_SIZE = 6;
static final int INDEX_UNIFIED_CREATION = 7;
static final int INDEX_UNIFIED_EXPIRY = 8;
static final String[] KEYS_PROJECTION = new String[] {
Keys._ID,
Keys.KEY_ID, Keys.RANK, Keys.ALGORITHM, Keys.KEY_SIZE, Keys.HAS_SECRET,
Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT, Keys.CAN_SIGN, Keys.IS_REVOKED,
Keys.CREATION, Keys.EXPIRY, Keys.FINGERPRINT
};
static final int KEYS_INDEX_CAN_ENCRYPT = 7;
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
case LOADER_ID_UNIFIED: {
Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null);
}
case LOADER_ID_KEYS: {
Uri baseUri = Keys.buildKeysUri(mDataUri);
return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, null);
}
default:
return null;
}
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
/* TODO better error handling? May cause problems when a key is deleted,
* because the notification triggers faster than the activity closes.
*/
// Avoid NullPointerExceptions...
if(data.getCount() == 0) {
return;
}
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
switch (loader.getId()) {
case LOADER_ID_UNIFIED: {
if (data.moveToFirst()) {
if (data.getInt(INDEX_UNIFIED_HAS_ANY_SECRET) != 0) {
mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
mSecretKey.setText(R.string.secret_key_yes);
} else {
mSecretKey.setTextColor(Color.BLACK);
mSecretKey.setText(getResources().getString(R.string.secret_key_no));
}
// get key id from MASTER_KEY_ID
long masterKeyId = data.getLong(INDEX_UNIFIED_MKI);
String keyIdStr = PgpKeyHelper.convertKeyIdToHex(masterKeyId);
mKeyId.setText(keyIdStr);
// get creation date from CREATION
if (data.isNull(INDEX_UNIFIED_CREATION)) {
mCreation.setText(R.string.none);
} else {
Date creationDate = new Date(data.getLong(INDEX_UNIFIED_CREATION) * 1000);
mCreation.setText(
DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
creationDate));
}
// get expiry date from EXPIRY
if (data.isNull(INDEX_UNIFIED_EXPIRY)) {
mExpiry.setText(R.string.none);
} else {
Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000);
mExpiry.setText(
DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
expiryDate));
}
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
getActivity(),
data.getInt(INDEX_UNIFIED_ALGORITHM),
data.getInt(INDEX_UNIFIED_KEY_SIZE)
);
mAlgorithm.setText(algorithmStr);
byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT);
String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint));
break;
}
}
case LOADER_ID_KEYS:
mKeysAdapter.swapCursor(data);
break;
}
getActivity().setProgressBarIndeterminateVisibility(false);
mContainer.setVisibility(View.VISIBLE);
}
/**
* This is called when the last Cursor provided to onLoadFinished() above is about to be closed.
* We need to make sure we are no longer using it.
*/
public void onLoaderReset(Loader<Cursor> loader) {
switch (loader.getId()) {
case LOADER_ID_KEYS:
mKeysAdapter.swapCursor(null);
break;
}
}
}

View file

@ -19,66 +19,46 @@ package org.sufficientlysecure.keychain.ui;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.R;import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter;
import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter;
import org.sufficientlysecure.keychain.util.Log;
import java.util.Date;
public class ViewKeyMainFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "uri";
private LinearLayout mContainer;
private TextView mName;
private TextView mEmail;
private TextView mComment;
private TextView mAlgorithm;
private TextView mKeyId;
private TextView mExpiry;
private TextView mCreation;
private TextView mFingerprint;
private TextView mSecretKey;
private BootstrapButton mActionEdit;
private BootstrapButton mActionEncrypt;
private BootstrapButton mActionCertify;
private View mActionEdit;
private View mActionEditDivider;
private View mActionEncrypt;
private View mActionCertify;
private View mActionCertifyDivider;
private ListView mUserIds;
private ListView mKeys;
private static final int LOADER_ID_UNIFIED = 0;
private static final int LOADER_ID_USER_IDS = 1;
private static final int LOADER_ID_KEYS = 2;
private ViewKeyUserIdsAdapter mUserIdsAdapter;
private ViewKeyKeysAdapter mKeysAdapter;
private Uri mDataUri;
@ -87,20 +67,12 @@ public class ViewKeyMainFragment extends Fragment implements
View view = inflater.inflate(R.layout.view_key_main_fragment, container, false);
mContainer = (LinearLayout) view.findViewById(R.id.container);
mName = (TextView) view.findViewById(R.id.name);
mEmail = (TextView) view.findViewById(R.id.email);
mComment = (TextView) view.findViewById(R.id.comment);
mKeyId = (TextView) view.findViewById(R.id.key_id);
mAlgorithm = (TextView) view.findViewById(R.id.algorithm);
mCreation = (TextView) view.findViewById(R.id.creation);
mExpiry = (TextView) view.findViewById(R.id.expiry);
mFingerprint = (TextView) view.findViewById(R.id.fingerprint);
mSecretKey = (TextView) view.findViewById(R.id.secret_key);
mUserIds = (ListView) view.findViewById(R.id.user_ids);
mKeys = (ListView) view.findViewById(R.id.keys);
mActionEdit = (BootstrapButton) view.findViewById(R.id.action_edit);
mActionEncrypt = (BootstrapButton) view.findViewById(R.id.action_encrypt);
mActionCertify = (BootstrapButton) view.findViewById(R.id.action_certify);
mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids);
mActionEdit = view.findViewById(R.id.view_key_action_edit);
mActionEditDivider = view.findViewById(R.id.view_key_action_edit_divider);
mActionEncrypt = view.findViewById(R.id.view_key_action_encrypt);
mActionCertify = view.findViewById(R.id.view_key_action_certify);
mActionCertifyDivider = view.findViewById(R.id.view_key_action_certify_divider);
return view;
}
@ -120,11 +92,6 @@ public class ViewKeyMainFragment extends Fragment implements
}
private void loadData(Uri dataUri) {
if (dataUri.equals(mDataUri)) {
Log.d(Constants.TAG, "Same URI, no need to load the data again!");
return;
}
getActivity().setProgressBarIndeterminateVisibility(true);
mContainer.setVisibility(View.GONE);
@ -135,44 +102,46 @@ public class ViewKeyMainFragment extends Fragment implements
mActionEncrypt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
encryptToContact(mDataUri);
encrypt(mDataUri);
}
});
mActionCertify.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
certifyKey(mDataUri);
certify(mDataUri);
}
});
mActionEdit.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
editKey(mDataUri);
}
});
mUserIdsAdapter = new ViewKeyUserIdsAdapter(getActivity(), null, 0);
mUserIds.setAdapter(mUserIdsAdapter);
mKeysAdapter = new ViewKeyKeysAdapter(getActivity(), null, 0);
mKeys.setAdapter(mKeysAdapter);
// Prepare the loaders. Either re-connect with an existing ones,
// or start new ones.
getActivity().getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
getActivity().getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
getActivity().getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this);
getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
getLoaderManager().initLoader(LOADER_ID_KEYS, null, this);
}
static final String[] UNIFIED_PROJECTION = new String[] {
KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET,
static final String[] UNIFIED_PROJECTION = new String[]{
KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET,
KeyRings.USER_ID, KeyRings.FINGERPRINT,
KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY,
};
static final int INDEX_UNIFIED_MKI = 1;
static final int INDEX_UNIFIED_MASTER_KEY_ID = 1;
static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2;
static final int INDEX_UNIFIED_UID = 3;
static final int INDEX_UNIFIED_USER_ID = 3;
static final int INDEX_UNIFIED_FINGERPRINT = 4;
static final int INDEX_UNIFIED_ALGORITHM = 5;
static final int INDEX_UNIFIED_KEY_SIZE = 6;
static final int INDEX_UNIFIED_CREATION = 7;
static final int INDEX_UNIFIED_EXPIRY = 8;
static final String[] KEYS_PROJECTION = new String[] {
static final String[] KEYS_PROJECTION = new String[]{
Keys._ID,
Keys.KEY_ID, Keys.RANK, Keys.ALGORITHM, Keys.KEY_SIZE, Keys.HAS_SECRET,
Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT, Keys.CAN_SIGN, Keys.IS_REVOKED,
@ -205,7 +174,7 @@ public class ViewKeyMainFragment extends Fragment implements
* because the notification triggers faster than the activity closes.
*/
// Avoid NullPointerExceptions...
if(data.getCount() == 0) {
if (data.getCount() == 0) {
return;
}
// Swap the new cursor in. (The framework will take care of closing the
@ -213,81 +182,24 @@ public class ViewKeyMainFragment extends Fragment implements
switch (loader.getId()) {
case LOADER_ID_UNIFIED: {
if (data.moveToFirst()) {
// get name, email, and comment from USER_ID
String[] mainUserId = PgpKeyHelper.splitUserId(data.getString(INDEX_UNIFIED_UID));
if (mainUserId[0] != null) {
getActivity().setTitle(mainUserId[0]);
mName.setText(mainUserId[0]);
} else {
getActivity().setTitle(R.string.user_id_no_name);
mName.setText(R.string.user_id_no_name);
}
mEmail.setText(mainUserId[1]);
mComment.setText(mainUserId[2]);
if (data.getInt(INDEX_UNIFIED_HAS_ANY_SECRET) != 0) {
mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
mSecretKey.setText(R.string.secret_key_yes);
// certify button
mActionCertify.setVisibility(View.GONE);
mActionCertifyDivider.setVisibility(View.GONE);
// edit button
mActionEdit.setVisibility(View.VISIBLE);
mActionEdit.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
editIntent.setData(
KeyRingData.buildSecretKeyRingUri(mDataUri));
editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
startActivityForResult(editIntent, 0);
}
});
mActionEditDivider.setVisibility(View.VISIBLE);
} else {
mSecretKey.setTextColor(Color.BLACK);
mSecretKey.setText(getResources().getString(R.string.secret_key_no));
// certify button
mActionCertify.setVisibility(View.VISIBLE);
mActionCertifyDivider.setVisibility(View.VISIBLE);
// edit button
mActionEdit.setVisibility(View.GONE);
mActionEditDivider.setVisibility(View.GONE);
}
// get key id from MASTER_KEY_ID
long masterKeyId = data.getLong(INDEX_UNIFIED_MKI);
String keyIdStr = PgpKeyHelper.convertKeyIdToHex(masterKeyId);
mKeyId.setText(keyIdStr);
// get creation date from CREATION
if (data.isNull(INDEX_UNIFIED_CREATION)) {
mCreation.setText(R.string.none);
} else {
Date creationDate = new Date(data.getLong(INDEX_UNIFIED_CREATION) * 1000);
mCreation.setText(
DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
creationDate));
}
// get expiry date from EXPIRY
if (data.isNull(INDEX_UNIFIED_EXPIRY)) {
mExpiry.setText(R.string.none);
} else {
Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000);
mExpiry.setText(
DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
expiryDate));
}
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
getActivity(),
data.getInt(INDEX_UNIFIED_ALGORITHM),
data.getInt(INDEX_UNIFIED_KEY_SIZE)
);
mAlgorithm.setText(algorithmStr);
byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT);
String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint));
break;
}
}
@ -307,11 +219,12 @@ public class ViewKeyMainFragment extends Fragment implements
break;
}
} while (data.moveToNext());
if (!canEncrypt) {
if (canEncrypt) {
mActionEncrypt.setVisibility(View.VISIBLE);
} else {
mActionEncrypt.setVisibility(View.GONE);
}
mKeysAdapter.swapCursor(data);
break;
}
getActivity().setProgressBarIndeterminateVisibility(false);
@ -327,16 +240,13 @@ public class ViewKeyMainFragment extends Fragment implements
case LOADER_ID_USER_IDS:
mUserIdsAdapter.swapCursor(null);
break;
case LOADER_ID_KEYS:
mKeysAdapter.swapCursor(null);
break;
}
}
private void encryptToContact(Uri dataUri) {
private void encrypt(Uri dataUri) {
try {
long keyId = new ProviderHelper(getActivity()).extractOrGetMasterKeyId(dataUri);
long[] encryptionKeyIds = new long[]{ keyId };
long[] encryptionKeyIds = new long[]{keyId};
Intent intent = new Intent(getActivity(), EncryptActivity.class);
intent.setAction(EncryptActivity.ACTION_ENCRYPT);
intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds);
@ -347,10 +257,17 @@ public class ViewKeyMainFragment extends Fragment implements
}
}
private void certifyKey(Uri dataUri) {
private void certify(Uri dataUri) {
Intent signIntent = new Intent(getActivity(), CertifyKeyActivity.class);
signIntent.setData(dataUri);
startActivity(signIntent);
}
private void editKey(Uri dataUri) {
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri));
editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
startActivityForResult(editIntent, 0);
}
}

View file

@ -0,0 +1,313 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui;
import android.annotation.TargetApi;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.QrCodeUtils;
import java.io.IOException;
public class ViewKeyShareFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "uri";
private LinearLayout mContainer;
private TextView mFingerprint;
private ImageView mFingerprintQrCode;
private View mFingerprintShareButton;
private View mFingerprintClipboardButton;
private View mKeyShareButton;
private View mKeyClipboardButton;
private View mNfcHelpButton;
private View mNfcPrefsButton;
ProviderHelper mProviderHelper;
private static final int QR_CODE_SIZE = 1000;
private static final int LOADER_ID_UNIFIED = 0;
private Uri mDataUri;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.view_key_share_fragment, container, false);
mProviderHelper = new ProviderHelper(ViewKeyShareFragment.this.getActivity());
mContainer = (LinearLayout) view.findViewById(R.id.container);
mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint);
mFingerprintQrCode = (ImageView) view.findViewById(R.id.view_key_fingerprint_qr_code_image);
mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share);
mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard);
mKeyShareButton = view.findViewById(R.id.view_key_action_key_share);
mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard);
mNfcHelpButton = view.findViewById(R.id.view_key_action_nfc_help);
mNfcPrefsButton = view.findViewById(R.id.view_key_action_nfc_prefs);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mNfcPrefsButton.setVisibility(View.VISIBLE);
} else {
mNfcPrefsButton.setVisibility(View.GONE);
}
mFingerprintQrCode.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showQrCodeDialog();
}
});
mFingerprintShareButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
share(mDataUri, mProviderHelper, true, false);
}
});
mFingerprintClipboardButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
share(mDataUri, mProviderHelper, true, true);
}
});
mKeyShareButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
share(mDataUri, mProviderHelper, false, false);
}
});
mKeyClipboardButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
share(mDataUri, mProviderHelper, false, true);
}
});
mNfcHelpButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showNfcHelpDialog();
}
});
mNfcPrefsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showNfcPrefs();
}
});
return view;
}
private void share(Uri dataUri, ProviderHelper providerHelper, boolean fingerprintOnly,
boolean toClipboard) {
try {
String content;
if (fingerprintOnly) {
byte[] data = (byte[]) providerHelper.getGenericData(
KeyRings.buildUnifiedKeyRingUri(dataUri),
Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
String fingerprint = PgpKeyHelper.convertFingerprintToHex(data);
content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
} else {
// get public keyring as ascii armored string
Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri);
content = providerHelper.getKeyRingAsArmoredString(uri);
}
if (toClipboard) {
ClipboardReflection.copyToClipboard(getActivity(), content);
String message;
if (fingerprintOnly) {
message = getResources().getString(R.string.fingerprint_copied_to_clipboard);
} else {
message = getResources().getString(R.string.key_copied_to_clipboard);
}
AppMsg.makeText(getActivity(), message, AppMsg.STYLE_INFO).show();
} else {
// Android will fail with android.os.TransactionTooLargeException if key is too big
// see http://www.lonestarprod.com/?p=34
if (content.length() >= 86389) {
AppMsg.makeText(getActivity(), R.string.key_too_big_for_sharing,
AppMsg.STYLE_ALERT).show();
return;
}
// let user choose application
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, content);
sendIntent.setType("text/plain");
String title;
if (fingerprintOnly) {
title = getResources().getString(R.string.title_share_fingerprint_with);
} else {
title = getResources().getString(R.string.title_share_key_with);
}
startActivity(Intent.createChooser(sendIntent, title));
}
} catch (IOException e) {
Log.e(Constants.TAG, "error processing key!", e);
AppMsg.makeText(getActivity(), R.string.error_key_processing, AppMsg.STYLE_ALERT).show();
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
AppMsg.makeText(getActivity(), R.string.error_key_not_found, AppMsg.STYLE_ALERT).show();
}
}
private void showQrCodeDialog() {
ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(mDataUri,
true);
dialog.show(ViewKeyShareFragment.this.getActivity().getSupportFragmentManager(), "shareQrCodeDialog");
}
private void showNfcHelpDialog() {
ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance();
dialog.show(getActivity().getSupportFragmentManager(), "shareNfcDialog");
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void showNfcPrefs() {
Intent intentSettings = new Intent(
Settings.ACTION_NFCSHARING_SETTINGS);
startActivity(intentSettings);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Uri dataUri = getArguments().getParcelable(ARG_DATA_URI);
if (dataUri == null) {
Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
getActivity().finish();
return;
}
loadData(dataUri);
}
private void loadData(Uri dataUri) {
getActivity().setProgressBarIndeterminateVisibility(true);
mContainer.setVisibility(View.GONE);
mDataUri = dataUri;
Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
// Prepare the loaders. Either re-connect with an existing ones,
// or start new ones.
getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
}
static final String[] UNIFIED_PROJECTION = new String[]{
KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET,
KeyRings.USER_ID, KeyRings.FINGERPRINT,
KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY,
};
static final int INDEX_UNIFIED_MASTER_KEY_ID = 1;
static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2;
static final int INDEX_UNIFIED_USER_ID = 3;
static final int INDEX_UNIFIED_FINGERPRINT = 4;
static final int INDEX_UNIFIED_ALGORITHM = 5;
static final int INDEX_UNIFIED_KEY_SIZE = 6;
static final int INDEX_UNIFIED_CREATION = 7;
static final int INDEX_UNIFIED_EXPIRY = 8;
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
case LOADER_ID_UNIFIED: {
Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null);
}
default:
return null;
}
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
/* TODO better error handling? May cause problems when a key is deleted,
* because the notification triggers faster than the activity closes.
*/
// Avoid NullPointerExceptions...
if (data.getCount() == 0) {
return;
}
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
switch (loader.getId()) {
case LOADER_ID_UNIFIED: {
if (data.moveToFirst()) {
byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT);
String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint));
String qrCodeContent = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
mFingerprintQrCode.setImageBitmap(
QrCodeUtils.getQRCodeBitmap(qrCodeContent, QR_CODE_SIZE)
);
break;
}
}
}
getActivity().setProgressBarIndeterminateVisibility(false);
mContainer.setVisibility(View.VISIBLE);
}
/**
* This is called when the last Cursor provided to onLoadFinished() above is about to be closed.
* We need to make sure we are no longer using it.
*/
public void onLoaderReset(Loader<Cursor> loader) {
}
}

View file

@ -28,7 +28,6 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
@ -106,7 +105,7 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
holder.mainUserId = (TextView) convertView.findViewById(R.id.mainUserId);
holder.mainUserIdRest = (TextView) convertView.findViewById(R.id.mainUserIdRest);
holder.keyId = (TextView) convertView.findViewById(R.id.keyId);
holder.fingerprint = (TextView) convertView.findViewById(R.id.fingerprint);
holder.fingerprint = (TextView) convertView.findViewById(R.id.view_key_fingerprint);
holder.algorithm = (TextView) convertView.findViewById(R.id.algorithm);
holder.status = (TextView) convertView.findViewById(R.id.status);
holder.userIdsList = (LinearLayout) convertView.findViewById(R.id.user_ids_list);

View file

@ -17,7 +17,7 @@
package org.sufficientlysecure.keychain.ui.adapter;
import android.content.Context;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
@ -26,8 +26,8 @@ import android.support.v7.app.ActionBarActivity;
import java.util.ArrayList;
public class PagerTabStripAdapter extends FragmentPagerAdapter {
private final Context mContext;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
protected final Activity mActivity;
protected final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
public final Class<?> clss;
@ -43,7 +43,7 @@ public class PagerTabStripAdapter extends FragmentPagerAdapter {
public PagerTabStripAdapter(ActionBarActivity activity) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActivity = activity;
}
public void addTab(Class<?> clss, Bundle args, String title) {
@ -60,7 +60,7 @@ public class PagerTabStripAdapter extends FragmentPagerAdapter {
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
return Fragment.instantiate(mActivity, info.clss.getName(), info.args);
}
@Override

View file

@ -27,6 +27,7 @@ import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
@ -106,40 +107,55 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter implements AdapterView.
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView vRank = (TextView) view.findViewById(R.id.rank);
TextView vUserId = (TextView) view.findViewById(R.id.userId);
TextView vName = (TextView) view.findViewById(R.id.userId);
TextView vAddress = (TextView) view.findViewById(R.id.address);
TextView vComment = (TextView) view.findViewById(R.id.comment);
ImageView vVerified = (ImageView) view.findViewById(R.id.certified);
if (cursor.getInt(mIsPrimary) > 0) {
vRank.setText("+");
} else {
vRank.setText(Integer.toString(cursor.getInt(mIndexRank)));
}
ImageView vPrimaryUserIdIcon = (ImageView) view.findViewById(R.id.primary_user_id_icon);
String[] userId = PgpKeyHelper.splitUserId(cursor.getString(mIndexUserId));
if (userId[0] != null) {
vUserId.setText(userId[0]);
vName.setText(userId[0]);
} else {
vUserId.setText(R.string.user_id_no_name);
vName.setText(R.string.user_id_no_name);
}
if (userId[1] != null) {
vAddress.setText(userId[1]);
vAddress.setVisibility(View.VISIBLE);
} else {
vAddress.setVisibility(View.GONE);
}
if (userId[2] != null) {
vComment.setText(userId[2]);
vComment.setVisibility(View.VISIBLE);
} else {
vComment.setVisibility(View.GONE);
}
// show small star icon for primary user ids
if (cursor.getInt(mIsPrimary) > 0) {
vPrimaryUserIdIcon.setVisibility(View.VISIBLE);
} else {
vPrimaryUserIdIcon.setVisibility(View.GONE);
}
vAddress.setText(userId[1]);
if (cursor.getInt(mIsRevoked) > 0) {
vRank.setText(" ");
// no star icon for revoked user ids!
vPrimaryUserIdIcon.setVisibility(View.GONE);
// set revocation icon
vVerified.setImageResource(R.drawable.key_certify_revoke);
// disable and strike through text for revoked user ids
vUserId.setEnabled(false);
vName.setEnabled(false);
vAddress.setEnabled(false);
vUserId.setText(OtherHelper.strikeOutText(vUserId.getText()));
vName.setText(OtherHelper.strikeOutText(vName.getText()));
vAddress.setText(OtherHelper.strikeOutText(vAddress.getText()));
} else {
vUserId.setEnabled(true);
vName.setEnabled(true);
vAddress.setEnabled(true);
int verified = cursor.getInt(mVerifiedId);
// TODO introduce own resources for this :)
switch (verified) {
case Certs.VERIFIED_SECRET:
vVerified.setImageResource(R.drawable.key_certify_ok_depth0);

View file

@ -0,0 +1,318 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sufficientlysecure.keychain.util;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Build;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.HorizontalScrollView;
import android.widget.TextView;
/**
* Copied from http://developer.android.com/samples/SlidingTabsColors/index.html
*/
/**
* To be used with ViewPager to provide a tab indicator component which give constant feedback as to
* the user's scroll progress.
* <p/>
* To use the component, simply add it to your view hierarchy. Then in your
* {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call
* {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.
* <p/>
* The colors can be customized in two ways. The first and simplest is to provide an array of colors
* via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
* alternative is via the {@link TabColorizer} interface which provides you complete control over
* which color is used for any individual position.
* <p/>
* The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
* providing the layout ID of your custom layout.
*/
public class SlidingTabLayout extends HorizontalScrollView {
/**
* Allows complete control over the colors drawn in the tab layout. Set with
* {@link #setCustomTabColorizer(TabColorizer)}.
*/
public interface TabColorizer {
/**
* @return return the color of the indicator used when {@code position} is selected.
*/
int getIndicatorColor(int position);
/**
* @return return the color of the divider drawn to the right of {@code position}.
*/
int getDividerColor(int position);
}
private static final int TITLE_OFFSET_DIPS = 24;
private static final int TAB_VIEW_PADDING_DIPS = 16;
private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
private int mTitleOffset;
private int mTabViewLayoutId;
private int mTabViewTextViewId;
private ViewPager mViewPager;
private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
private final SlidingTabStrip mTabStrip;
public SlidingTabLayout(Context context) {
this(context, null);
}
public SlidingTabLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// Disable the Scroll Bar
setHorizontalScrollBarEnabled(false);
// Make sure that the Tab Strips fills this View
setFillViewport(true);
mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
mTabStrip = new SlidingTabStrip(context);
addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
}
/**
* Set the custom {@link TabColorizer} to be used.
* <p/>
* If you only require simple custmisation then you can use
* {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
* similar effects.
*/
public void setCustomTabColorizer(TabColorizer tabColorizer) {
mTabStrip.setCustomTabColorizer(tabColorizer);
}
/**
* Sets the colors to be used for indicating the selected tab. These colors are treated as a
* circular array. Providing one color will mean that all tabs are indicated with the same color.
*/
public void setSelectedIndicatorColors(int... colors) {
mTabStrip.setSelectedIndicatorColors(colors);
}
/**
* Sets the colors to be used for tab dividers. These colors are treated as a circular array.
* Providing one color will mean that all tabs are indicated with the same color.
*/
public void setDividerColors(int... colors) {
mTabStrip.setDividerColors(colors);
}
/**
* Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
* required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
* that the layout can update it's scroll position correctly.
*
* @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
*/
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
mViewPagerPageChangeListener = listener;
}
/**
* Set the custom layout to be inflated for the tab views.
*
* @param layoutResId Layout id to be inflated
* @param textViewId id of the {@link TextView} in the inflated view
*/
public void setCustomTabView(int layoutResId, int textViewId) {
mTabViewLayoutId = layoutResId;
mTabViewTextViewId = textViewId;
}
/**
* Sets the associated view pager. Note that the assumption here is that the pager content
* (number of tabs and tab titles) does not change after this call has been made.
*/
public void setViewPager(ViewPager viewPager) {
mTabStrip.removeAllViews();
mViewPager = viewPager;
if (viewPager != null) {
viewPager.setOnPageChangeListener(new InternalViewPagerListener());
populateTabStrip();
}
}
/**
* Create a default view to be used for tabs. This is called if a custom tab view is not set via
* {@link #setCustomTabView(int, int)}.
*/
protected TextView createDefaultTabView(Context context) {
TextView textView = new TextView(context);
textView.setGravity(Gravity.CENTER);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
textView.setTypeface(Typeface.DEFAULT_BOLD);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// If we're running on Honeycomb or newer, then we can use the Theme's
// selectableItemBackground to ensure that the View has a pressed state
TypedValue outValue = new TypedValue();
getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
outValue, true);
textView.setBackgroundResource(outValue.resourceId);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
textView.setAllCaps(true);
}
int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
textView.setPadding(padding, padding, padding, padding);
return textView;
}
private void populateTabStrip() {
final PagerAdapter adapter = mViewPager.getAdapter();
final View.OnClickListener tabClickListener = new TabClickListener();
for (int i = 0; i < adapter.getCount(); i++) {
View tabView = null;
TextView tabTitleView = null;
if (mTabViewLayoutId != 0) {
// If there is a custom tab view layout id set, try and inflate it
tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
false);
tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
}
if (tabView == null) {
tabView = createDefaultTabView(getContext());
}
if (tabTitleView == null && TextView.class.isInstance(tabView)) {
tabTitleView = (TextView) tabView;
}
tabTitleView.setText(adapter.getPageTitle(i));
tabView.setOnClickListener(tabClickListener);
mTabStrip.addView(tabView);
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mViewPager != null) {
scrollToTab(mViewPager.getCurrentItem(), 0);
}
}
private void scrollToTab(int tabIndex, int positionOffset) {
final int tabStripChildCount = mTabStrip.getChildCount();
if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
return;
}
View selectedChild = mTabStrip.getChildAt(tabIndex);
if (selectedChild != null) {
int targetScrollX = selectedChild.getLeft() + positionOffset;
if (tabIndex > 0 || positionOffset > 0) {
// If we're not at the first child and are mid-scroll, make sure we obey the offset
targetScrollX -= mTitleOffset;
}
scrollTo(targetScrollX, 0);
}
}
private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
private int mScrollState;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
int tabStripChildCount = mTabStrip.getChildCount();
if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
return;
}
mTabStrip.onViewPagerPageChanged(position, positionOffset);
View selectedTitle = mTabStrip.getChildAt(position);
int extraOffset = (selectedTitle != null)
? (int) (positionOffset * selectedTitle.getWidth())
: 0;
scrollToTab(position, extraOffset);
if (mViewPagerPageChangeListener != null) {
mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,
positionOffsetPixels);
}
}
@Override
public void onPageScrollStateChanged(int state) {
mScrollState = state;
if (mViewPagerPageChangeListener != null) {
mViewPagerPageChangeListener.onPageScrollStateChanged(state);
}
}
@Override
public void onPageSelected(int position) {
if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
mTabStrip.onViewPagerPageChanged(position, 0f);
scrollToTab(position, 0);
}
if (mViewPagerPageChangeListener != null) {
mViewPagerPageChangeListener.onPageSelected(position);
}
}
}
private class TabClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
if (v == mTabStrip.getChildAt(i)) {
mViewPager.setCurrentItem(i);
return;
}
}
}
}
}

View file

@ -0,0 +1,211 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sufficientlysecure.keychain.util;
import android.R;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.LinearLayout;
/**
* Copied from http://developer.android.com/samples/SlidingTabsColors/index.html
*/
class SlidingTabStrip extends LinearLayout {
private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8;
private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
private final int mBottomBorderThickness;
private final Paint mBottomBorderPaint;
private final int mSelectedIndicatorThickness;
private final Paint mSelectedIndicatorPaint;
private final int mDefaultBottomBorderColor;
private final Paint mDividerPaint;
private final float mDividerHeight;
private int mSelectedPosition;
private float mSelectionOffset;
private SlidingTabLayout.TabColorizer mCustomTabColorizer;
private final SimpleTabColorizer mDefaultTabColorizer;
SlidingTabStrip(Context context) {
this(context, null);
}
SlidingTabStrip(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
final float density = getResources().getDisplayMetrics().density;
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true);
final int themeForegroundColor = outValue.data;
mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor,
DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
mDefaultTabColorizer = new SimpleTabColorizer();
mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);
mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor,
DEFAULT_DIVIDER_COLOR_ALPHA));
mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
mBottomBorderPaint = new Paint();
mBottomBorderPaint.setColor(mDefaultBottomBorderColor);
mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
mSelectedIndicatorPaint = new Paint();
mDividerHeight = DEFAULT_DIVIDER_HEIGHT;
mDividerPaint = new Paint();
mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density));
}
void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {
mCustomTabColorizer = customTabColorizer;
invalidate();
}
void setSelectedIndicatorColors(int... colors) {
// Make sure that the custom colorizer is removed
mCustomTabColorizer = null;
mDefaultTabColorizer.setIndicatorColors(colors);
invalidate();
}
void setDividerColors(int... colors) {
// Make sure that the custom colorizer is removed
mCustomTabColorizer = null;
mDefaultTabColorizer.setDividerColors(colors);
invalidate();
}
void onViewPagerPageChanged(int position, float positionOffset) {
mSelectedPosition = position;
mSelectionOffset = positionOffset;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
final int height = getHeight();
final int childCount = getChildCount();
final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height);
final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null
? mCustomTabColorizer
: mDefaultTabColorizer;
// Thick colored underline below the current selection
if (childCount > 0) {
View selectedTitle = getChildAt(mSelectedPosition);
int left = selectedTitle.getLeft();
int right = selectedTitle.getRight();
int color = tabColorizer.getIndicatorColor(mSelectedPosition);
if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
if (color != nextColor) {
color = blendColors(nextColor, color, mSelectionOffset);
}
// Draw the selection partway between the tabs
View nextTitle = getChildAt(mSelectedPosition + 1);
left = (int) (mSelectionOffset * nextTitle.getLeft() +
(1.0f - mSelectionOffset) * left);
right = (int) (mSelectionOffset * nextTitle.getRight() +
(1.0f - mSelectionOffset) * right);
}
mSelectedIndicatorPaint.setColor(color);
canvas.drawRect(left, height - mSelectedIndicatorThickness, right,
height, mSelectedIndicatorPaint);
}
// Thin underline along the entire bottom edge
canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);
// Vertical separators between the titles
int separatorTop = (height - dividerHeightPx) / 2;
for (int i = 0; i < childCount - 1; i++) {
View child = getChildAt(i);
mDividerPaint.setColor(tabColorizer.getDividerColor(i));
canvas.drawLine(child.getRight(), separatorTop, child.getRight(),
separatorTop + dividerHeightPx, mDividerPaint);
}
}
/**
* Set the alpha value of the {@code color} to be the given {@code alpha} value.
*/
private static int setColorAlpha(int color, byte alpha) {
return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
}
/**
* Blend {@code color1} and {@code color2} using the given ratio.
*
* @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
* 0.0 will return {@code color2}.
*/
private static int blendColors(int color1, int color2, float ratio) {
final float inverseRation = 1f - ratio;
float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
return Color.rgb((int) r, (int) g, (int) b);
}
private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {
private int[] mIndicatorColors;
private int[] mDividerColors;
@Override
public final int getIndicatorColor(int position) {
return mIndicatorColors[position % mIndicatorColors.length];
}
@Override
public final int getDividerColor(int position) {
return mDividerColors[position % mDividerColors.length];
}
void setIndicatorColors(int... colors) {
mIndicatorColors = colors;
}
void setDividerColors(int... colors) {
mDividerColors = colors;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Borderless Buttons for API < 11, see http://stackoverflow.com/a/14663170 -->
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="@android:integer/config_shortAnimTime">
<item android:state_pressed="true" android:drawable="@color/emphasis" />
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@color/bg_gray" />
<item android:drawable="@android:color/transparent" />
</selector>

View file

@ -93,7 +93,7 @@
android:text="@string/label_fingerprint" />
<TextView
android:id="@+id/fingerprint"
android:id="@+id/view_key_fingerprint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:typeface="monospace" />
@ -111,7 +111,7 @@
android:text="@string/section_uids_to_sign" />
<org.sufficientlysecure.keychain.ui.widget.FixedListView
android:id="@+id/user_ids"
android:id="@+id/view_key_user_ids"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants" />

View file

@ -106,7 +106,7 @@
android:typeface="monospace" />
<TextView
android:id="@+id/fingerprint"
android:id="@+id/view_key_fingerprint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="0000 0000 0000 0000 0000\n0000 0000 0000 0000 0000"

View file

@ -52,7 +52,7 @@
android:layout_height="match_parent">
<Button
android:background="@drawable/selector_transparent_button"
style="@style/SelectableItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/edit"

View file

@ -2,11 +2,18 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
android:orientation="vertical">
<org.sufficientlysecure.keychain.util.SlidingTabLayout
android:id="@+id/view_key_sliding_tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:id="@+id/view_key_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="0px"
android:layout_weight="1"
android:background="@android:color/white" />
</LinearLayout>

View file

@ -12,22 +12,22 @@
android:focusable="false">
<TextView
android:id="@+id/signerKeyId"
android:id="@+id/signerName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="signer key id"
android:text="signer name"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<TextView
android:id="@+id/signerUserId"
android:id="@+id/signerKeyId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="&lt;user@example.com>"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_below="@+id/signerKeyId"
android:layout_below="@+id/signerName"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
@ -38,7 +38,7 @@
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="status"
android:visibility="visible"
android:layout_above="@+id/signerUserId"
android:layout_above="@+id/signerKeyId"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="10dp" />

View file

@ -0,0 +1,149 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- focusable and related properties to workaround http://stackoverflow.com/q/16182331-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:descendantFocusability="beforeDescendants"
android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:id="@+id/container">
<TextView
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="14dp"
android:text="@string/section_master_key" />
<TableLayout
android:layout_width="wrap_content"
android:paddingLeft="8dp"
android:layout_height="0dp"
android:layout_weight="1"
android:shrinkColumns="1">
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
android:text="@string/label_key_id" />
<TextView
android:id="@+id/key_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="5dip"
android:text=""
android:typeface="monospace" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/label_algorithm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
android:text="@string/label_algorithm" />
<TextView
android:id="@+id/algorithm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="5dip"
android:text="" />
</TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/tableRow">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
android:text="@string/label_fingerprint" />
<TextView
android:id="@+id/view_key_fingerprint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:typeface="monospace" />
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
android:text="@string/label_creation" />
<TextView
android:id="@+id/creation"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
android:text="@string/label_expiry" />
<TextView
android:id="@+id/expiry"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
android:text="@string/label_secret_key" />
<TextView
android:id="@+id/secret_key"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</TableRow>
</TableLayout>
<TextView
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="14dp"
android:text="@string/section_keys" />
<org.sufficientlysecure.keychain.ui.widget.FixedListView
android:id="@+id/keys"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>

View file

@ -17,248 +17,94 @@
<TextView
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="14dp"
android:text="@string/section_master_user_id" />
<TableLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:stretchColumns="1">
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingRight="10dip"
android:text="@string/label_name" />
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingRight="5dip"
android:text="" />
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingRight="10dip"
android:text="@string/label_email" />
<TextView
android:id="@+id/email"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingRight="5dip"
android:text="" />
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingRight="10dip"
android:text="@string/label_comment" />
<TextView
android:id="@+id/comment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingRight="5dip"
android:text="" />
</TableRow>
</TableLayout>
<TextView
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="14dp"
android:text="@string/section_master_key" />
<TableLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:shrinkColumns="1">
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
android:text="@string/label_key_id" />
<TextView
android:id="@+id/key_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="5dip"
android:text=""
android:typeface="monospace" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/label_algorithm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
android:text="@string/label_algorithm" />
<TextView
android:id="@+id/algorithm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="5dip"
android:text="" />
</TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/tableRow">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
android:text="@string/label_fingerprint" />
<TextView
android:id="@+id/fingerprint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:typeface="monospace" />
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
android:text="@string/label_creation" />
<TextView
android:id="@+id/creation"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
android:text="@string/label_expiry" />
<TextView
android:id="@+id/expiry"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
android:text="@string/label_secret_key" />
<TextView
android:id="@+id/secret_key"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</TableRow>
</TableLayout>
<TextView
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="14dp"
android:text="@string/section_user_ids" />
android:text="@string/section_user_ids"
android:layout_weight="1" />
<org.sufficientlysecure.keychain.ui.widget.FixedListView
android:id="@+id/user_ids"
android:id="@+id/view_key_user_ids"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_height="0dp"
android:layout_marginBottom="4dp"
android:layout_weight="1" />
<View
android:id="@+id/view_key_action_certify_divider"
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/view_key_action_certify"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:clickable="true"
style="@style/SelectableItem"
android:orientation="horizontal">
<TextView
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="0dip"
android:layout_height="match_parent"
android:text="@string/key_view_action_certify"
android:layout_weight="1"
android:drawableRight="@drawable/ic_action_good"
android:drawablePadding="8dp"
android:gravity="center_vertical" />
</LinearLayout>
<TextView
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_height="0dp"
android:layout_marginTop="14dp"
android:text="@string/section_keys" />
<org.sufficientlysecure.keychain.ui.widget.FixedListView
android:id="@+id/keys"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:text="@string/section_actions"
android:layout_weight="1" />
<TextView
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="14dp"
android:text="@string/section_actions" />
<com.beardedhen.androidbootstrap.BootstrapButton
android:id="@+id/action_edit"
android:id="@+id/view_key_action_edit"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:clickable="true"
style="@style/SelectableItem"
android:text="@string/key_view_action_edit"
bootstrapbutton:bb_icon_left="fa-key"
bootstrapbutton:bb_type="info"
android:visibility="gone" />
android:layout_weight="1"
android:drawableRight="@drawable/ic_action_edit"
android:drawablePadding="8dp"
android:gravity="center_vertical" />
<com.beardedhen.androidbootstrap.BootstrapButton
android:id="@+id/action_encrypt"
<View
android:id="@+id/view_key_action_edit_divider"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:layout_height="1dip"
android:background="?android:attr/listDivider" />
<TextView
android:id="@+id/view_key_action_encrypt"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:clickable="true"
style="@style/SelectableItem"
android:text="@string/key_view_action_encrypt"
bootstrapbutton:bb_icon_left="fa-lock"
bootstrapbutton:bb_type="info" />
<com.beardedhen.androidbootstrap.BootstrapButton
android:id="@+id/action_certify"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:text="@string/key_view_action_certify"
bootstrapbutton:bb_icon_left="fa-pencil"
bootstrapbutton:bb_type="info" />
android:layout_weight="1"
android:drawableRight="@drawable/ic_action_secure"
android:drawablePadding="8dp"
android:gravity="center_vertical" />
</LinearLayout>

View file

@ -0,0 +1,179 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- focusable and related properties to workaround http://stackoverflow.com/q/16182331-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:descendantFocusability="beforeDescendants"
android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:id="@+id/container">
<TextView
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginTop="14dp"
android:text="@string/section_fingerprint"
android:layout_weight="1" />
<LinearLayout
android:id="@+id/view_key_action_fingerprint_share"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:clickable="true"
style="@style/SelectableItem"
android:orientation="horizontal">
<TextView
android:id="@+id/view_key_fingerprint"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="0dip"
android:layout_height="match_parent"
android:text=""
android:layout_weight="1"
android:typeface="monospace"
android:drawableRight="@drawable/ic_action_share"
android:drawablePadding="8dp"
android:gravity="center_vertical" />
<View
android:layout_width="1dip"
android:layout_height="match_parent"
android:gravity="right"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:background="?android:attr/listDivider" />
<ImageButton
android:id="@+id/view_key_action_fingerprint_clipboard"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="8dp"
android:src="@drawable/ic_action_copy"
android:layout_gravity="center_vertical"
style="@style/SelectableItem" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="?android:attr/listDivider" />
<ImageView
android:id="@+id/view_key_fingerprint_qr_code_image"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
style="@style/SelectableItem" />
<TextView
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginTop="14dp"
android:text="@string/section_share_key"
android:layout_weight="1" />
<LinearLayout
android:id="@+id/view_key_action_key_share"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:clickable="true"
style="@style/SelectableItem"
android:orientation="horizontal">
<TextView
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="0dip"
android:layout_height="match_parent"
android:text="@string/key_view_action_share_with"
android:layout_weight="1"
android:drawableRight="@drawable/ic_action_share"
android:drawablePadding="8dp"
android:gravity="center_vertical" />
<View
android:layout_width="1dip"
android:layout_height="match_parent"
android:gravity="right"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:background="?android:attr/listDivider" />
<ImageButton
android:id="@+id/view_key_action_key_clipboard"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="8dp"
android:src="@drawable/ic_action_copy"
android:layout_gravity="center_vertical"
style="@style/SelectableItem" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/view_key_action_nfc_help"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:clickable="true"
style="@style/SelectableItem"
android:orientation="horizontal">
<TextView
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="0dip"
android:layout_height="match_parent"
android:text="@string/key_view_action_share_nfc"
android:layout_weight="1"
android:drawableRight="@drawable/ic_action_help"
android:drawablePadding="8dp"
android:gravity="center_vertical" />
<View
android:layout_width="1dip"
android:layout_height="match_parent"
android:gravity="right"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:background="?android:attr/listDivider" />
<ImageButton
android:id="@+id/view_key_action_nfc_prefs"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="8dp"
android:src="@drawable/ic_action_settings"
android:layout_gravity="center_vertical"
style="@style/SelectableItem" />
</LinearLayout>
</LinearLayout>
</ScrollView>

View file

@ -2,6 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:paddingRight="3dip"
android:singleLine="true">
@ -13,23 +14,42 @@
android:clickable="false"
android:focusable="false" />
<TextView
android:id="@+id/rank"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="0"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_marginLeft="8dp"
android:layout_gravity="center_vertical"
android:width="30sp" />
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/certified"
android:src="@drawable/key_certify_ok_self" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:id="@+id/primary_user_id_icon"
android:src="@drawable/ic_action_important_small" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_gravity="center_vertical"
android:layout_width="0dip"
android:layout_marginLeft="8dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView
android:id="@+id/address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="alice@example.com"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/userId"
android:layout_width="wrap_content"
@ -38,20 +58,13 @@
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/address"
android:id="@+id/comment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="alice@example.com"
android:textColor="@color/tertiary_text_light"
android:text="comment"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/certified"
android:src="@drawable/key_certify_ok_self"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp" />
</LinearLayout>

View file

@ -2,53 +2,6 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_key_view_share"
android:icon="@drawable/ic_action_share"
app:showAsAction="always"
android:title="@string/menu_share">
<menu>
<item
android:id="@+id/menu_key_view_share_fingerprint_title"
app:showAsAction="never"
android:title="@string/menu_share_title_fingerprint">
<menu>
<item
android:id="@+id/menu_key_view_share_default_fingerprint"
app:showAsAction="never"
android:title="@string/menu_share_default_fingerprint" />
<item
android:id="@+id/menu_key_view_share_qr_code_fingerprint"
app:showAsAction="never"
android:title="@string/menu_share_qr_code_fingerprint" />
</menu>
</item>
<item
android:id="@+id/menu_key_view_share_title"
app:showAsAction="never"
android:title="@string/menu_share_title">
<menu>
<item
android:id="@+id/menu_key_view_share_default"
app:showAsAction="never"
android:title="@string/menu_share_default" />
<item
android:id="@+id/menu_key_view_share_qr_code"
app:showAsAction="never"
android:title="@string/menu_share_qr_code" />
<item
android:id="@+id/menu_key_view_share_nfc"
app:showAsAction="never"
android:title="@string/menu_share_nfc" />
<item
android:id="@+id/menu_key_view_share_clipboard"
app:showAsAction="never"
android:title="@string/menu_copy_to_clipboard" />
</menu>
</item>
</menu>
</item>
<item
android:id="@+id/menu_key_keyserver"
android:icon="@drawable/ic_action_cloud"
@ -69,13 +22,13 @@
<item
android:id="@+id/menu_key_view_export_file"
android:icon="@drawable/ic_action_import_export"
app:showAsAction="ifRoom"
app:showAsAction="never"
android:title="@string/menu_export_key" />
<item
android:id="@+id/menu_key_view_delete"
android:icon="@drawable/ic_action_discard"
app:showAsAction="ifRoom"
app:showAsAction="never"
android:title="@string/menu_delete_key" />
</menu>

View file

@ -15,4 +15,8 @@
<item name="android:textSize">14sp</item>
</style>
<style name="SelectableItem">
<item name="android:background">?android:attr/selectableItemBackground</item>
</style>
</resources>

View file

@ -3,9 +3,13 @@
<color name="emphasis">#31b6e7</color>
<color name="bg_gray">#cecbce</color>
<color name="tertiary_text_light">#808080</color>
<color name="result_red">#FF4444</color>
<color name="result_orange">#FFBB33</color>
<color name="result_green">#99CC00</color>
<color name="result_blue">#33B5E5</color>
<color name="holo_gray_light">#33999999</color>
<color name="holo_gray_bright">#33CCCCCC</color>
<color name="result_red">#ffff4444</color>
<color name="result_orange">#ffffbb33</color>
<color name="result_green">#ff99cc00</color>
<color name="result_blue">#ff33b5e5</color>
</resources>

View file

@ -14,7 +14,8 @@
<string name="title_key_server_preference">Keyserver Preference</string>
<string name="title_change_passphrase">Change Passphrase</string>
<string name="title_set_passphrase">Set Passphrase</string>
<string name="title_share_with">Share with…</string>
<string name="title_share_fingerprint_with">Share fingerprint with…</string>
<string name="title_share_key_with">Share key with…</string>
<string name="title_share_file">Share file with…</string>
<string name="title_encrypt_to_file">Encrypt To File</string>
<string name="title_decrypt_to_file">Decrypt To File</string>
@ -28,19 +29,21 @@
<string name="title_help">Help</string>
<!-- section -->
<string name="section_user_ids">User IDs</string>
<string name="section_user_ids">Identities</string>
<string name="section_keys">Keys</string>
<string name="section_general">General</string>
<string name="section_defaults">Defaults</string>
<string name="section_advanced">Advanced</string>
<string name="section_master_key">Master Key</string>
<string name="section_master_user_id">Master User ID</string>
<string name="section_master_user_id">Primary Identity</string>
<string name="section_actions">Actions</string>
<string name="section_share_key">Share key</string>
<string name="section_certification_key">Your Key used for certification</string>
<string name="section_upload_key">Upload Key</string>
<string name="section_key_server">Keyserver</string>
<string name="section_encrypt_and_or_sign">Encrypt and/or Sign</string>
<string name="section_decrypt_verify">Decrypt and Verify</string>
<string name="section_fingerprint">Fingerprint</string>
<!-- button -->
<string name="btn_certify">Certify</string>
@ -121,7 +124,7 @@
<string name="label_expiry">Expiry</string>
<string name="label_usage">Usage</string>
<string name="label_key_size">Key Size</string>
<string name="label_main_user_id">Main User ID</string>
<string name="label_main_user_id">Primary identity</string>
<string name="label_name">Name</string>
<string name="label_comment">Comment</string>
<string name="label_email">Email</string>
@ -207,7 +210,7 @@
<string name="key_deletion_confirmation_multi">Do you really want to delete all selected public keys?\nYou can\'t undo this!</string>
<string name="secret_key_deletion_confirmation">Do you really want to delete the SECRET key \'%s\'?\nYou can\'t undo this!</string>
<string name="ask_save_changed_key">You have made changes to the keyring, would you like to save it?</string>
<string name="ask_empty_id_ok">You have added an empty user ID, are you sure you want to continue?</string>
<string name="ask_empty_id_ok">You have added an empty identity, are you sure you want to continue?</string>
<string name="public_key_deletetion_confirmation">Do you really want to delete the public key \'%s\'?\nYou can\'t undo this!</string>
<string name="also_export_secret_keys">Also export secret keys?</string>
@ -251,6 +254,7 @@
<string name="list_empty">This list is empty!</string>
<string name="nfc_successful">Successfully sent key with NFC Beam!</string>
<string name="key_copied_to_clipboard">Key has been copied to the clipboard!</string>
<string name="fingerprint_copied_to_clipboard">Fingerprint has been copied to the clipboard!</string>
<string name="key_has_already_been_certified">Key has already been certified!</string>
<string name="select_key_to_sign">Please select a key to be used for signing!</string>
<string name="key_too_big_for_sharing">Key is too big to be shared this way!</string>
@ -268,8 +272,8 @@
<string name="error_master_key_must_not_be_el_gamal">the master key cannot be an ElGamal key</string>
<string name="error_unknown_algorithm_choice">unknown algorithm choice</string>
<string name="error_user_id_no_email">no email found</string>
<string name="error_key_needs_a_user_id">need at least one user id</string>
<string name="error_main_user_id_must_not_be_empty">main user id must not be empty</string>
<string name="error_key_needs_a_user_id">need at least one identity</string>
<string name="error_main_user_id_must_not_be_empty">primary identity must not be empty</string>
<string name="error_key_needs_master_key">need at least a master key</string>
<string name="error_no_signature_passphrase">no passphrase given</string>
<string name="error_no_signature_key">no signature key given</string>
@ -422,8 +426,8 @@
<string name="api_register_allow">Allow access</string>
<string name="api_register_disallow">Disallow access</string>
<string name="api_register_error_select_key">Please select a key!</string>
<string name="api_select_pub_keys_missing_text">No public keys were found for these user ids:</string>
<string name="api_select_pub_keys_dublicates_text">More than one public key exist for these user ids:</string>
<string name="api_select_pub_keys_missing_text">No public keys were found for these identities:</string>
<string name="api_select_pub_keys_dublicates_text">More than one public key exist for these identities:</string>
<string name="api_select_pub_keys_text">Please review the list of recipients!</string>
<string name="api_error_wrong_signature">Signature check failed! Have you installed this app from a different source? If you are sure that this is not an attack, revoke this app\'s registration in OpenKeychain and then register the app again.</string>
@ -447,10 +451,14 @@
<string name="key_list_empty_button_import">importing keys.</string>
<!-- Key view -->
<string name="key_view_action_edit">Edit this key</string>
<string name="key_view_action_edit">Edit key</string>
<string name="key_view_action_encrypt">Encrypt with this key</string>
<string name="key_view_action_certify">Certify this key</string>
<string name="key_view_tab_main">Info</string>
<string name="key_view_action_certify">Certify identities</string>
<string name="key_view_action_share_with">with…</string>
<string name="key_view_action_share_nfc">over NFC by holding the devices back to back</string>
<string name="key_view_tab_main">Main Info</string>
<string name="key_view_tab_share">Share</string>
<string name="key_view_tab_keys_details">Key Details</string>
<string name="key_view_tab_certs">Certifications</string>
<!-- Navigation Drawer -->
@ -485,10 +493,10 @@
<!-- unsorted -->
<string name="section_signer_id">Signer</string>
<string name="section_cert">Certificate Details</string>
<string name="label_user_id">User ID</string>
<string name="label_user_id">Identity</string>
<string name="unknown_uid">&lt;unknown&gt;</string>
<string name="empty_certs">No certificates for this key</string>
<string name="section_uids_to_sign">User IDs to sign</string>
<string name="section_uids_to_sign">Identities to sign</string>
<string name="label_revocation">Revocation Reason</string>
<string name="label_verify_status">Verification Status</string>
<string name="label_cert_type">Type</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- Used in Android < 4 -->
<style name="KeychainTheme" parent="@style/Theme.AppCompat.Light">
<item name="android:alertDialogStyle">@style/CustomDialogTheme</item>
</style>
@ -30,5 +29,8 @@
<item name="android:textSize">14sp</item>
</style>
<style name="SelectableItem">
<item name="android:background">@drawable/selector_transparent_button</item>
</style>
</resources>