diff options
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui')
27 files changed, 1062 insertions, 858 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SignKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index d9fb294d5..aab6b81d9 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SignKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -56,7 +56,7 @@ import com.beardedhen.androidbootstrap.BootstrapButton; /** * Signs the specified public key with the specified secret master key */ -public class SignKeyActivity extends ActionBarActivity implements +public class CertifyKeyActivity extends ActionBarActivity implements SelectSecretKeyLayoutFragment.SelectSecretKeyCallback { private BootstrapButton mSignButton; private CheckBox mUploadKeyCheckbox; @@ -72,7 +72,7 @@ public class SignKeyActivity extends ActionBarActivity implements protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.sign_key_activity); + setContentView(R.layout.certify_key_activity); final ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayShowTitleEnabled(true); @@ -164,8 +164,8 @@ public class SignKeyActivity extends ActionBarActivity implements passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog"); } catch (PgpGeneralException e) { - Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!"); - // send message to handler to start encryption directly + Log.d(Constants.TAG, "No passphrase for this secret key!"); + // send message to handler to start certification directly returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY); } } @@ -196,8 +196,8 @@ public class SignKeyActivity extends ActionBarActivity implements String passphrase = PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId); if (passphrase == null) { showPassphraseDialog(mMasterKeyId); - return; // bail out; need to wait until the user has entered the passphrase - // before trying again + // bail out; need to wait until the user has entered the passphrase before trying again + return; } else { startSigning(); } @@ -218,13 +218,13 @@ public class SignKeyActivity extends ActionBarActivity implements // Send all information needed to service to sign key in other thread Intent intent = new Intent(this, KeychainIntentService.class); - intent.setAction(KeychainIntentService.ACTION_SIGN_KEYRING); + intent.setAction(KeychainIntentService.ACTION_CERTIFY_KEYRING); // fill values for this action Bundle data = new Bundle(); - data.putLong(KeychainIntentService.SIGN_KEY_MASTER_KEY_ID, mMasterKeyId); - data.putLong(KeychainIntentService.SIGN_KEY_PUB_KEY_ID, mPubKeyId); + data.putLong(KeychainIntentService.CERTIFY_KEY_MASTER_KEY_ID, mMasterKeyId); + data.putLong(KeychainIntentService.CERTIFY_KEY_PUB_KEY_ID, mPubKeyId); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); @@ -237,14 +237,12 @@ public class SignKeyActivity extends ActionBarActivity implements if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - Toast.makeText(SignKeyActivity.this, R.string.key_sign_success, + Toast.makeText(CertifyKeyActivity.this, R.string.key_sign_success, Toast.LENGTH_SHORT).show(); // check if we need to send the key to the server or not if (mUploadKeyCheckbox.isChecked()) { - /* - * upload the newly signed key to the key server - */ + // upload the newly signed key to the keyserver uploadKey(); } else { setResult(RESULT_OK); @@ -291,7 +289,7 @@ public class SignKeyActivity extends ActionBarActivity implements super.handleMessage(message); if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - Toast.makeText(SignKeyActivity.this, R.string.key_send_success, + Toast.makeText(CertifyKeyActivity.this, R.string.key_send_success, Toast.LENGTH_SHORT).show(); setResult(RESULT_OK); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index 26657479f..652310cd2 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -34,7 +34,7 @@ import org.sufficientlysecure.keychain.helper.ActionBarHelper; import org.sufficientlysecure.keychain.helper.FileHelper; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.pgp.PgpOperation; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.exception.NoAsymmetricEncryptionException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.ProviderHelper; @@ -43,7 +43,6 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.LookupUnknownKeyDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; import org.sufficientlysecure.keychain.util.Log; @@ -61,7 +60,7 @@ import android.view.animation.AnimationUtils; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageView; -import android.widget.LinearLayout; +import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import android.widget.ViewFlipper; @@ -78,14 +77,20 @@ public class DecryptActivity extends DrawerActivity { /* EXTRA keys for input */ public static final String EXTRA_TEXT = "text"; + private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006; + private static final int RESULT_CODE_FILE = 0x00007003; + private long mSignatureKeyId = 0; private boolean mReturnResult = false; + + // TODO: replace signed only checks with something more intelligent + // PgpDecryptVerify should handle all automatically!!! private boolean mSignedOnly = false; private boolean mAssumeSymmetricEncryption = false; private EditText mMessage = null; - private LinearLayout mSignatureLayout = null; + private RelativeLayout mSignatureLayout = null; private ImageView mSignatureStatusImage = null; private TextView mUserId = null; private TextView mUserIdRest = null; @@ -100,6 +105,7 @@ public class DecryptActivity extends DrawerActivity { private EditText mFilename = null; private CheckBox mDeleteAfter = null; private BootstrapButton mBrowse = null; + private BootstrapButton mLookupKey = null; private String mInputFilename = null; private String mOutputFilename = null; @@ -107,14 +113,10 @@ public class DecryptActivity extends DrawerActivity { private Uri mContentUri = null; private boolean mReturnBinary = false; - private long mUnknownSignatureKeyId = 0; - private long mSecretKeyId = Id.key.none; private FileDialogFragment mFileDialog; - private boolean mLookupUnknownKey = true; - private boolean mDecryptImmediately = false; private BootstrapButton mDecryptButton; @@ -154,7 +156,7 @@ public class DecryptActivity extends DrawerActivity { mSourceLabel.setOnClickListener(nextSourceClickListener); mMessage = (EditText) findViewById(R.id.message); - mSignatureLayout = (LinearLayout) findViewById(R.id.signature); + mSignatureLayout = (RelativeLayout) findViewById(R.id.signature); mSignatureStatusImage = (ImageView) findViewById(R.id.ic_signature_status); mUserId = (TextView) findViewById(R.id.mainUserId); mUserIdRest = (TextView) findViewById(R.id.mainUserIdRest); @@ -171,7 +173,15 @@ public class DecryptActivity extends DrawerActivity { mBrowse.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { FileHelper.openFile(DecryptActivity.this, mFilename.getText().toString(), "*/*", - Id.request.filename); + RESULT_CODE_FILE); + } + }); + + mLookupKey = (BootstrapButton) findViewById(R.id.lookup_key); + mLookupKey.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + lookupUnknownKey(mSignatureKeyId); } }); @@ -239,7 +249,7 @@ public class DecryptActivity extends DrawerActivity { DecryptActivity.this, mSignatureKeyId); if (key != null) { Intent intent = new Intent(DecryptActivity.this, ImportKeysActivity.class); - intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEY_SERVER); + intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER); intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, mSignatureKeyId); startActivity(intent); } @@ -263,14 +273,14 @@ public class DecryptActivity extends DrawerActivity { if (mDecryptImmediately || (mSource.getCurrentView().getId() == R.id.sourceMessage && (mMessage.getText() - .length() > 0 || mContentUri != null))) { + .length() > 0 || mContentUri != null))) { decryptClicked(); } } /** * Handles all actions with this intent - * + * * @param intent */ private void handleActions(Intent intent) { @@ -287,13 +297,13 @@ public class DecryptActivity extends DrawerActivity { * Android's Action */ if (Intent.ACTION_SEND.equals(action) && type != null) { - // When sending to Keychain Encrypt via share menu + // When sending to Keychain Decrypt via share menu if ("text/plain".equals(type)) { // Plain text String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); if (sharedText != null) { // handle like normal text decryption, override action and extras to later - // execute ACTION_DECRYPT in main actions + // executeServiceMethod ACTION_DECRYPT in main actions extras.putString(EXTRA_TEXT, sharedText); action = ACTION_DECRYPT; } @@ -375,21 +385,21 @@ public class DecryptActivity extends DrawerActivity { private void updateSource() { switch (mSource.getCurrentView().getId()) { - case R.id.sourceFile: { - mSourceLabel.setText(R.string.label_file); - mDecryptButton.setText(getString(R.string.btn_decrypt)); - break; - } + case R.id.sourceFile: { + mSourceLabel.setText(R.string.label_file); + mDecryptButton.setText(getString(R.string.btn_decrypt)); + break; + } - case R.id.sourceMessage: { - mSourceLabel.setText(R.string.label_message); - mDecryptButton.setText(getString(R.string.btn_decrypt)); - break; - } + case R.id.sourceMessage: { + mSourceLabel.setText(R.string.label_message); + mDecryptButton.setText(getString(R.string.btn_decrypt)); + break; + } - default: { - break; - } + default: { + break; + } } } @@ -449,7 +459,7 @@ public class DecryptActivity extends DrawerActivity { } else { if (mDecryptTarget == Id.target.file) { askForOutputFilename(); - } else { + } else { // mDecryptTarget == Id.target.message decryptStart(); } } @@ -527,7 +537,7 @@ public class DecryptActivity extends DrawerActivity { try { if (inStream.markSupported()) { inStream.mark(200); // should probably set this to the max size of two pgpF - // objects, if it even needs to be anything other than 0. + // objects, if it even needs to be anything other than 0. } mSecretKeyId = PgpHelper.getDecryptionKeyId(this, inStream); if (mSecretKeyId == Id.key.none) { @@ -539,7 +549,7 @@ public class DecryptActivity extends DrawerActivity { inStream.reset(); } mSecretKeyId = Id.key.symmetric; - if (!PgpOperation.hasSymmetricEncryption(this, inStream)) { + if (!PgpDecryptVerify.hasSymmetricEncryption(this, inStream)) { throw new PgpGeneralException( getString(R.string.error_no_known_encryption_found)); } @@ -559,7 +569,7 @@ public class DecryptActivity extends DrawerActivity { data = "\n\n" + data; intent.putExtra(EncryptActivity.EXTRA_TEXT, data); intent.putExtra(EncryptActivity.EXTRA_SIGNATURE_KEY_ID, mSecretKeyId); - intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, new long[] { mSignatureKeyId }); + intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, new long[]{mSignatureKeyId}); startActivity(intent); } @@ -587,28 +597,10 @@ public class DecryptActivity extends DrawerActivity { } private void lookupUnknownKey(long unknownKeyId) { - // Message is received after passphrase is cached - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == LookupUnknownKeyDialogFragment.MESSAGE_OKAY) { - // the result is handled by onActivityResult() as LookupUnknownKeyDialogFragment - // starts a new Intent which then returns data - } else if (message.what == LookupUnknownKeyDialogFragment.MESSAGE_CANCEL) { - // decrypt again, but don't lookup unknown keys! - mLookupUnknownKey = false; - decryptStart(); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - - LookupUnknownKeyDialogFragment lookupKeyDialog = LookupUnknownKeyDialogFragment - .newInstance(messenger, unknownKeyId); - - lookupKeyDialog.show(getSupportFragmentManager(), "unknownKeyDialog"); + Intent intent = new Intent(this, ImportKeysActivity.class); + intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER); + intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, unknownKeyId); + startActivityForResult(intent, RESULT_CODE_LOOKUP_KEY); } private void decryptStart() { @@ -644,8 +636,6 @@ public class DecryptActivity extends DrawerActivity { data.putLong(KeychainIntentService.ENCRYPT_SECRET_KEY_ID, mSecretKeyId); - data.putBoolean(KeychainIntentService.DECRYPT_SIGNED_ONLY, mSignedOnly); - data.putBoolean(KeychainIntentService.DECRYPT_LOOKUP_UNKNOWN_KEY, mLookupUnknownKey); data.putBoolean(KeychainIntentService.DECRYPT_RETURN_BYTES, mReturnBinary); data.putBoolean(KeychainIntentService.DECRYPT_ASSUME_SYMMETRIC, mAssumeSymmetricEncryption); @@ -662,15 +652,6 @@ public class DecryptActivity extends DrawerActivity { // get returned data bundle Bundle returnData = message.getData(); - // if key is unknown show lookup dialog - if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE_LOOKUP_KEY) - && mLookupUnknownKey) { - mUnknownSignatureKeyId = returnData - .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID); - lookupUnknownKey(mUnknownSignatureKeyId); - return; - } - mSignatureKeyId = 0; mSignatureLayout.setVisibility(View.GONE); @@ -685,26 +666,26 @@ public class DecryptActivity extends DrawerActivity { } switch (mDecryptTarget) { - case Id.target.message: - String decryptedMessage = returnData - .getString(KeychainIntentService.RESULT_DECRYPTED_STRING); - mMessage.setText(decryptedMessage); - mMessage.setHorizontallyScrolling(false); - - break; - - case Id.target.file: - if (mDeleteAfter.isChecked()) { - // Create and show dialog to delete original file - DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment - .newInstance(mInputFilename); - deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog"); - } - break; - - default: - // shouldn't happen - break; + case Id.target.message: + String decryptedMessage = returnData + .getString(KeychainIntentService.RESULT_DECRYPTED_STRING); + mMessage.setText(decryptedMessage); + mMessage.setHorizontallyScrolling(false); + + break; + + case Id.target.file: + if (mDeleteAfter.isChecked()) { + // Create and show dialog to delete original file + DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment + .newInstance(mInputFilename); + deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog"); + } + break; + + default: + // shouldn't happen + break; } @@ -727,19 +708,24 @@ public class DecryptActivity extends DrawerActivity { if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS)) { mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); + mLookupKey.setVisibility(View.GONE); } else if (returnData .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN)) { mSignatureStatusImage.setImageResource(R.drawable.overlay_error); + mLookupKey.setVisibility(View.VISIBLE); Toast.makeText(DecryptActivity.this, - R.string.unknown_signature_key_touch_to_look_up, + R.string.unknown_signature, Toast.LENGTH_LONG).show(); } else { mSignatureStatusImage.setImageResource(R.drawable.overlay_error); + mLookupKey.setVisibility(View.GONE); } mSignatureLayout.setVisibility(View.VISIBLE); } } - }; + } + + ; }; // Create a new Messenger for the communication back @@ -756,36 +742,37 @@ public class DecryptActivity extends DrawerActivity { @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { - case Id.request.filename: { - if (resultCode == RESULT_OK && data != null) { - try { - String path = FileHelper.getPath(this, data.getData()); - Log.d(Constants.TAG, "path=" + path); - - mFilename.setText(path); - } catch (NullPointerException e) { - Log.e(Constants.TAG, "Nullpointer while retrieving path!"); + case RESULT_CODE_FILE: { + if (resultCode == RESULT_OK && data != null) { + try { + String path = FileHelper.getPath(this, data.getData()); + Log.d(Constants.TAG, "path=" + path); + + mFilename.setText(path); + } catch (NullPointerException e) { + Log.e(Constants.TAG, "Nullpointer while retrieving path!"); + } } + return; } - return; - } - // this request is returned after LookupUnknownKeyDialogFragment started - // ImportKeysActivity and user looked uo key - case Id.request.look_up_key_id: { - Log.d(Constants.TAG, "Returning from Lookup Key..."); - // decrypt again without lookup - mLookupUnknownKey = false; - decryptStart(); - return; - } + // this request is returned after LookupUnknownKeyDialogFragment started + // ImportKeysActivity and user looked uo key + case RESULT_CODE_LOOKUP_KEY: { + Log.d(Constants.TAG, "Returning from Lookup Key..."); + if (resultCode == RESULT_OK) { + // decrypt again + decryptStart(); + } + return; + } - default: { - break; - } - } + default: { + super.onActivityResult(requestCode, resultCode, data); - super.onActivityResult(requestCode, resultCode, data); + break; + } + } } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 81446db99..85bfba224 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -173,7 +173,7 @@ public class EncryptActivity extends DrawerActivity { String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); if (sharedText != null) { // handle like normal text encryption, override action and extras to later - // execute ACTION_ENCRYPT in main actions + // executeServiceMethod ACTION_ENCRYPT in main actions extras.putString(EXTRA_TEXT, sharedText); extras.putBoolean(EXTRA_ASCII_ARMOR, true); action = ACTION_ENCRYPT; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpFragmentAbout.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java index be7c50dbb..12d689274 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpFragmentAbout.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java @@ -33,18 +33,7 @@ import android.view.ViewGroup; import android.widget.TextView; -public class HelpFragmentAbout extends Fragment { - - /** - * Workaround for Android Bug. See - * http://stackoverflow.com/questions/8748064/starting-activity-from - * -fragment-causes-nullpointerexception - */ - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - setUserVisibleHint(true); - } +public class HelpAboutFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java index 2fe7c56e6..9ccd7e088 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java @@ -20,12 +20,13 @@ package org.sufficientlysecure.keychain.ui; import java.util.ArrayList; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBar; @@ -37,8 +38,6 @@ public class HelpActivity extends ActionBarActivity { ViewPager mViewPager; TabsAdapter mTabsAdapter; - TextView tabCenter; - TextView tabText; @Override public void onCreate(Bundle savedInstanceState) { @@ -63,93 +62,21 @@ public class HelpActivity extends ActionBarActivity { } Bundle startBundle = new Bundle(); - startBundle.putInt(HelpFragmentHtml.ARG_HTML_FILE, R.raw.help_start); + startBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_start); mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_start)), - HelpFragmentHtml.class, startBundle, (selectedTab == 0 ? true : false)); + HelpHtmlFragment.class, startBundle, (selectedTab == 0 ? true : false)); Bundle nfcBundle = new Bundle(); - nfcBundle.putInt(HelpFragmentHtml.ARG_HTML_FILE, R.raw.help_nfc_beam); + nfcBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_nfc_beam); mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_nfc_beam)), - HelpFragmentHtml.class, nfcBundle, (selectedTab == 1 ? true : false)); + HelpHtmlFragment.class, nfcBundle, (selectedTab == 1 ? true : false)); Bundle changelogBundle = new Bundle(); - changelogBundle.putInt(HelpFragmentHtml.ARG_HTML_FILE, R.raw.help_changelog); + changelogBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_changelog); mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_changelog)), - HelpFragmentHtml.class, changelogBundle, (selectedTab == 2 ? true : false)); + HelpHtmlFragment.class, changelogBundle, (selectedTab == 2 ? true : false)); mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_about)), - HelpFragmentAbout.class, null, (selectedTab == 3 ? true : false)); - } - - public static class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, - ViewPager.OnPageChangeListener { - private final Context mContext; - private final ActionBar mActionBar; - private final ViewPager mViewPager; - private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); - - static final class TabInfo { - private final Class<?> clss; - private final Bundle args; - - TabInfo(Class<?> _class, Bundle _args) { - clss = _class; - args = _args; - } - } - - public TabsAdapter(ActionBarActivity activity, ViewPager pager) { - super(activity.getSupportFragmentManager()); - mContext = activity; - mActionBar = activity.getSupportActionBar(); - mViewPager = pager; - mViewPager.setAdapter(this); - mViewPager.setOnPageChangeListener(this); - } - - public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args, boolean selected) { - TabInfo info = new TabInfo(clss, args); - tab.setTag(info); - tab.setTabListener(this); - mTabs.add(info); - mActionBar.addTab(tab, selected); - notifyDataSetChanged(); - } - - @Override - public int getCount() { - return mTabs.size(); - } - - @Override - public Fragment getItem(int position) { - TabInfo info = mTabs.get(position); - return Fragment.instantiate(mContext, info.clss.getName(), info.args); - } - - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - } - - public void onPageSelected(int position) { - mActionBar.setSelectedNavigationItem(position); - } - - public void onPageScrollStateChanged(int state) { - } - - public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { - Object tag = tab.getTag(); - for (int i = 0; i < mTabs.size(); i++) { - if (mTabs.get(i) == tag) { - mViewPager.setCurrentItem(i); - } - } - } - - public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { - } - - public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { - } + HelpAboutFragment.class, null, (selectedTab == 3 ? true : false)); } }
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpFragmentHtml.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java index fb6747db0..3afb5bbe0 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpFragmentHtml.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java @@ -28,7 +28,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ScrollView; -public class HelpFragmentHtml extends Fragment { +public class HelpHtmlFragment extends Fragment { private Activity mActivity; private int htmlFile; @@ -36,10 +36,10 @@ public class HelpFragmentHtml extends Fragment { public static final String ARG_HTML_FILE = "htmlFile"; /** - * Create a new instance of HelpFragmentHtml, providing "htmlFile" as an argument. + * Create a new instance of HelpHtmlFragment, providing "htmlFile" as an argument. */ - static HelpFragmentHtml newInstance(int htmlFile) { - HelpFragmentHtml f = new HelpFragmentHtml(); + static HelpHtmlFragment newInstance(int htmlFile) { + HelpHtmlFragment f = new HelpHtmlFragment(); // Supply html raw file input as an argument. Bundle args = new Bundle(); @@ -49,17 +49,6 @@ public class HelpFragmentHtml extends Fragment { return f; } - /** - * Workaround for Android Bug. See - * http://stackoverflow.com/questions/8748064/starting-activity-from - * -fragment-causes-nullpointerexception - */ - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - setUserVisibleHint(true); - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mActivity = getActivity(); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index dc3a07def..a5027ac1c 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> * Copyright (C) 2011 Senecaso * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -47,16 +47,19 @@ import android.support.v7.app.ActionBar; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; -import android.widget.Toast; import com.beardedhen.androidbootstrap.BootstrapButton; +import com.devspark.appmsg.AppMsg; public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNavigationListener { public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY"; public static final String ACTION_IMPORT_KEY_FROM_QR_CODE = Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_QR_CODE"; - public static final String ACTION_IMPORT_KEY_FROM_KEY_SERVER = Constants.INTENT_PREFIX - + "IMPORT_KEY_FROM_KEY_SERVER"; + public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = Constants.INTENT_PREFIX + + "IMPORT_KEY_FROM_KEYSERVER"; + // TODO: implement: + public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN = Constants.INTENT_PREFIX + + "IMPORT_KEY_FROM_KEY_SERVER_AND_RETURN"; // Actions for internal use only: public static final String ACTION_IMPORT_KEY_FROM_FILE = Constants.INTENT_PREFIX @@ -67,7 +70,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa // only used by ACTION_IMPORT_KEY public static final String EXTRA_KEY_BYTES = "key_bytes"; - // only used by ACTION_IMPORT_KEY_FROM_KEY_SERVER + // only used by ACTION_IMPORT_KEY_FROM_KEYSERVER public static final String EXTRA_QUERY = "query"; public static final String EXTRA_KEY_ID = "key_id"; public static final String EXTRA_FINGERPRINT = "fingerprint"; @@ -78,6 +81,16 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa private Fragment mCurrentFragment; private BootstrapButton mImportButton; + private static final Class[] NAVIGATION_CLASSES = new Class[]{ + ImportKeysServerFragment.class, + ImportKeysFileFragment.class, + ImportKeysQrCodeFragment.class, + ImportKeysClipboardFragment.class, + ImportKeysNFCFragment.class + }; + + private int mCurrentNavPostition = -1; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -107,6 +120,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa handleActions(savedInstanceState, getIntent()); } + protected void handleActions(Bundle savedInstanceState, Intent intent) { String action = intent.getAction(); Bundle extras = intent.getExtras(); @@ -125,24 +139,23 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa if (scheme != null && scheme.toLowerCase(Locale.ENGLISH).equals(Constants.FINGERPRINT_SCHEME)) { /* Scanning a fingerprint directly with Barcode Scanner */ - getSupportActionBar().setSelectedNavigationItem(0); - loadFragment(ImportKeysQrCodeFragment.class, null, mNavigationStrings[0]); - loadFromFingerprintUri(dataUri); + loadFromFingerprintUri(savedInstanceState, dataUri); } else if (ACTION_IMPORT_KEY.equals(action)) { /* Keychain's own Actions */ - getSupportActionBar().setSelectedNavigationItem(1); - loadFragment(ImportKeysFileFragment.class, null, mNavigationStrings[1]); + + // display file fragment + loadNavFragment(1, null); if (dataUri != null) { - // directly load data + // action: directly load data startListFragment(savedInstanceState, null, dataUri, null); } else if (extras.containsKey(EXTRA_KEY_BYTES)) { byte[] importData = intent.getByteArrayExtra(EXTRA_KEY_BYTES); - // directly load data + // action: directly load data startListFragment(savedInstanceState, importData, null, null); } - } else if (ACTION_IMPORT_KEY_FROM_KEY_SERVER.equals(action)) { + } else if (ACTION_IMPORT_KEY_FROM_KEYSERVER.equals(action)) { String query = null; if (extras.containsKey(EXTRA_QUERY)) { query = extras.getString(EXTRA_QUERY); @@ -161,82 +174,97 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa return; } - // search directly - getSupportActionBar().setSelectedNavigationItem(0); + // display keyserver fragment with query Bundle args = new Bundle(); args.putString(ImportKeysServerFragment.ARG_QUERY, query); - loadFragment(ImportKeysServerFragment.class, args, mNavigationStrings[0]); + loadNavFragment(0, args); + // action: search immediately startListFragment(savedInstanceState, null, null, query); - } else { - // Other actions + } else if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)) { + + // NOTE: this only displays the appropriate fragment, no actions are taken + loadNavFragment(1, null); + + // no immediate actions! startListFragment(savedInstanceState, null, null, null); + } else if (ACTION_IMPORT_KEY_FROM_QR_CODE.equals(action)) { + // also exposed in AndroidManifest - if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)) { - getSupportActionBar().setSelectedNavigationItem(1); - loadFragment(ImportKeysFileFragment.class, null, mNavigationStrings[1]); - } else if (ACTION_IMPORT_KEY_FROM_QR_CODE.equals(action)) { - // also exposed in AndroidManifest - getSupportActionBar().setSelectedNavigationItem(2); - loadFragment(ImportKeysQrCodeFragment.class, null, mNavigationStrings[2]); - } else if (ACTION_IMPORT_KEY_FROM_NFC.equals(action)) { - getSupportActionBar().setSelectedNavigationItem(3); - loadFragment(ImportKeysNFCFragment.class, null, mNavigationStrings[3]); - } + // NOTE: this only displays the appropriate fragment, no actions are taken + loadNavFragment(2, null); + + // no immediate actions! + startListFragment(savedInstanceState, null, null, null); + } else if (ACTION_IMPORT_KEY_FROM_NFC.equals(action)) { + + // NOTE: this only displays the appropriate fragment, no actions are taken + loadNavFragment(3, null); + + // no immediate actions! + startListFragment(savedInstanceState, null, null, null); + } else { + startListFragment(savedInstanceState, null, null, null); } } private void startListFragment(Bundle savedInstanceState, byte[] bytes, Uri dataUri, String serverQuery) { - // Check that the activity is using the layout version with - // the fragment_container FrameLayout - if (findViewById(R.id.import_keys_list_container) != null) { - - // However, if we're being restored from a previous state, - // then we don't need to do anything and should return or else - // we could end up with overlapping fragments. - if (savedInstanceState != null) { - return; - } + // However, if we're being restored from a previous state, + // then we don't need to do anything and should return or else + // we could end up with overlapping fragments. + if (savedInstanceState != null) { + return; + } - // Create an instance of the fragment - mListFragment = ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery); + // Create an instance of the fragment + mListFragment = ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery); - // Add the fragment to the 'fragment_container' FrameLayout - // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! - getSupportFragmentManager().beginTransaction() - .replace(R.id.import_keys_list_container, mListFragment) - .commitAllowingStateLoss(); - // do it immediately! - getSupportFragmentManager().executePendingTransactions(); - } + // Add the fragment to the 'fragment_container' FrameLayout + // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! + getSupportFragmentManager().beginTransaction() + .replace(R.id.import_keys_list_container, mListFragment) + .commitAllowingStateLoss(); + // do it immediately! + getSupportFragmentManager().executePendingTransactions(); } + /** + * "Basically, when using a list navigation, onNavigationItemSelected() is automatically + * called when your activity is created/re-created, whether you like it or not. To prevent + * your Fragment's onCreateView() from being called twice, this initial automatic call to + * onNavigationItemSelected() should check whether the Fragment is already in existence + * inside your Activity." + * <p/> + * from http://stackoverflow.com/questions/10983396/fragment-oncreateview-and-onactivitycreated-called-twice/14295474#14295474 + * + * In our case, if we start ImportKeysActivity with parameters to directly search using a fingerprint, + * the fragment would be loaded twice resulting in the query being empty after the second load. + * + * Our solution: + * To prevent that a fragment will be loaded again even if it was already loaded loadNavFragment + * checks against mCurrentNavPostition. + * + * @param itemPosition + * @param itemId + * @return + */ @Override public boolean onNavigationItemSelected(int itemPosition, long itemId) { - // Create new fragment from our own Fragment class - switch (itemPosition) { - case 0: - loadFragment(ImportKeysServerFragment.class, null, mNavigationStrings[itemPosition]); - break; - case 1: - loadFragment(ImportKeysFileFragment.class, null, mNavigationStrings[itemPosition]); - break; - case 2: - loadFragment(ImportKeysQrCodeFragment.class, null, mNavigationStrings[itemPosition]); - break; - case 3: - loadFragment(ImportKeysClipboardFragment.class, null, mNavigationStrings[itemPosition]); - break; - case 4: - loadFragment(ImportKeysNFCFragment.class, null, mNavigationStrings[itemPosition]); - break; - - default: - break; - } + Log.d(Constants.TAG, "onNavigationItemSelected"); + + loadNavFragment(itemPosition, null); + return true; } + private void loadNavFragment(int itemPosition, Bundle args) { + if (mCurrentNavPostition != itemPosition) { + getSupportActionBar().setSelectedNavigationItem(itemPosition); + loadFragment(NAVIGATION_CLASSES[itemPosition], args, mNavigationStrings[itemPosition]); + mCurrentNavPostition = itemPosition; + } + } + private void loadFragment(Class<?> clss, Bundle args, String tag) { mCurrentFragment = Fragment.instantiate(this, clss.getName(), args); @@ -248,26 +276,26 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa ft.commit(); } - public void loadFromFingerprintUri(Uri dataUri) { + public void loadFromFingerprintUri(Bundle savedInstanceState, Uri dataUri) { String fingerprint = dataUri.toString().split(":")[1].toLowerCase(Locale.ENGLISH); Log.d(Constants.TAG, "fingerprint: " + fingerprint); if (fingerprint.length() < 16) { - Toast.makeText(this, R.string.import_qr_code_too_short_fingerprint, - Toast.LENGTH_LONG).show(); + AppMsg.makeText(this, R.string.import_qr_code_too_short_fingerprint, + AppMsg.STYLE_ALERT).show(); return; } String query = "0x" + fingerprint; - // search directly - getSupportActionBar().setSelectedNavigationItem(0); + // display keyserver fragment with query Bundle args = new Bundle(); args.putString(ImportKeysServerFragment.ARG_QUERY, query); - loadFragment(ImportKeysServerFragment.class, args, mNavigationStrings[0]); + loadNavFragment(0, args); - startListFragment(null, null, null, query); + // action: search directly + startListFragment(savedInstanceState, null, null, query); } public void loadCallback(byte[] importData, Uri dataUri, String serverQuery, String keyServer) { @@ -364,7 +392,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa } else { toastMessage = getString(R.string.no_keys_added_or_updated); } - Toast.makeText(ImportKeysActivity.this, toastMessage, Toast.LENGTH_SHORT) + AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO) .show(); if (bad > 0) { AlertDialog.Builder alert = new AlertDialog.Builder( @@ -446,7 +474,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa // start service with intent startService(intent); } else { - Toast.makeText(this, R.string.error_nothing_import, Toast.LENGTH_LONG).show(); + AppMsg.makeText(this, R.string.error_nothing_import, AppMsg.STYLE_ALERT).show(); } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java index 68d318491..b52de5bc9 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -122,7 +122,7 @@ public class ImportKeysListFragment extends ListFragment implements mKeyBytes = getArguments().getByteArray(ARG_BYTES); mServerQuery = getArguments().getString(ARG_SERVER_QUERY); - // TODO: this is used when scanning QR Code. Currently it simply uses key server nr 0 + // TODO: this is used when scanning QR Code. Currently it simply uses keyserver nr 0 mKeyServer = Preferences.getPreferences(getActivity()) .getKeyServers()[0]; @@ -136,7 +136,7 @@ public class ImportKeysListFragment extends ListFragment implements getLoaderManager().initLoader(LOADER_ID_BYTES, null, this); } - if (mServerQuery != null) { + if (mServerQuery != null && mKeyServer != null) { // Start out with a progress indicator. setListShown(false); @@ -165,14 +165,19 @@ public class ImportKeysListFragment extends ListFragment implements mServerQuery = serverQuery; mKeyServer = keyServer; - // Start out with a progress indicator. - setListShown(false); + if (mKeyBytes != null || mDataUri != null) { + // Start out with a progress indicator. + setListShown(false); - if (mKeyBytes != null || mDataUri != null) getLoaderManager().restartLoader(LOADER_ID_BYTES, null, this); + } + + if (mServerQuery != null && mKeyServer != null) { + // Start out with a progress indicator. + setListShown(false); - if (mServerQuery != null && mKeyServer != null) getLoaderManager().restartLoader(LOADER_ID_SERVER_QUERY, null, this); + } } @Override diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java index 63727ad26..ee91b2434 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java @@ -98,22 +98,29 @@ public class ImportKeysQrCodeFragment extends Fragment { IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode, resultCode, data); if (scanResult != null && scanResult.getFormatName() != null) { + String scannedContent = scanResult.getContents(); - Log.d(Constants.TAG, "scanResult content: " + scanResult.getContents()); + Log.d(Constants.TAG, "scannedContent: " + scannedContent); // look if it's fingerprint only - if (scanResult.getContents().toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) { + if (scannedContent.toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) { importFingerprint(Uri.parse(scanResult.getContents())); return; } // look if it is the whole key - String[] parts = scanResult.getContents().split(","); + String[] parts = scannedContent.split(","); if (parts.length == 3) { importParts(parts); return; } + // is this a full key encoded as qr code? + if (scannedContent.startsWith("-----BEGIN PGP")) { + mImportActivity.loadCallback(scannedContent.getBytes(), null, null, null); + return; + } + // fail... Toast.makeText(getActivity(), R.string.import_qr_code_wrong, Toast.LENGTH_LONG) .show(); @@ -130,7 +137,7 @@ public class ImportKeysQrCodeFragment extends Fragment { } public void importFingerprint(Uri dataUri) { - mImportActivity.loadFromFingerprintUri(dataUri); + mImportActivity.loadFromFingerprintUri(null, dataUri); } private void importParts(String[] parts) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java index 2e0956d8b..d77015aa7 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java @@ -127,21 +127,21 @@ public class ImportKeysServerFragment extends Fragment { mImportActivity = (ImportKeysActivity) getActivity(); // set displayed values - if (getArguments() != null && getArguments().containsKey(ARG_QUERY)) { - String query = getArguments().getString(ARG_QUERY); - mQueryEditText.setText(query, TextView.BufferType.EDITABLE); + if (getArguments() != null) { + if (getArguments().containsKey(ARG_QUERY)) { + String query = getArguments().getString(ARG_QUERY); + mQueryEditText.setText(query, TextView.BufferType.EDITABLE); + + Log.d(Constants.TAG, "query: " + query); + } - String keyServer = null; if (getArguments().containsKey(ARG_KEY_SERVER)) { - keyServer = getArguments().getString(ARG_KEY_SERVER); + String keyServer = getArguments().getString(ARG_KEY_SERVER); int keyServerPos = mServerAdapter.getPosition(keyServer); mServerSpinner.setSelection(keyServerPos); - } else { - keyServer = (String) mServerSpinner.getSelectedItem(); - } - Log.d(Constants.TAG, "query: " + query); - Log.d(Constants.TAG, "keyServer: " + keyServer); + Log.d(Constants.TAG, "keyServer: " + keyServer); + } } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index 6ae2b9bf9..c28d57627 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -17,6 +17,7 @@ package org.sufficientlysecure.keychain.ui; +import java.util.ArrayList; import java.util.Set; import org.sufficientlysecure.keychain.Id; @@ -30,12 +31,16 @@ import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import se.emilsjolander.stickylistheaders.ApiLevelTooLowException; import se.emilsjolander.stickylistheaders.StickyListHeadersListView; + import android.annotation.SuppressLint; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; @@ -50,6 +55,7 @@ import android.view.ViewGroup; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; import android.widget.ListView; +import android.widget.Toast; import com.beardedhen.androidbootstrap.BootstrapButton; @@ -63,7 +69,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte private KeyListPublicAdapter mAdapter; private StickyListHeadersListView mStickyList; - // empty layout + // empty list layout private BootstrapButton mButtonEmptyCreate; private BootstrapButton mButtonEmptyImport; @@ -92,9 +98,9 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte @Override public void onClick(View v) { - Intent intentImportFromFile = new Intent(getActivity(), ImportKeysActivity.class); - intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE); - startActivityForResult(intentImportFromFile, 0); + Intent intent = new Intent(getActivity(), ImportKeysActivity.class); + intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE); + startActivityForResult(intent, 0); } }); @@ -109,7 +115,6 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - // mKeyListPublicActivity = (KeyListPublicActivity) getActivity(); mStickyList = (StickyListHeadersListView) getActivity().findViewById(R.id.list); mStickyList.setOnItemClickListener(this); @@ -159,18 +164,16 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte } switch (item.getItemId()) { - case R.id.menu_key_list_public_multi_encrypt: { - encrypt(ids); - - break; - } - case R.id.menu_key_list_public_multi_delete: { - showDeleteKeyDialog(ids); - - break; - } + case R.id.menu_key_list_public_multi_encrypt: { + encrypt(mode, ids); + break; + } + case R.id.menu_key_list_public_multi_delete: { + showDeleteKeyDialog(mode, ids); + break; + } } - return false; + return true; } @Override @@ -181,7 +184,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, - boolean checked) { + boolean checked) { if (checked) { count++; mAdapter.setNewSelection(position, checked); @@ -212,8 +215,12 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte } // These are the rows that we will retrieve. - static final String[] PROJECTION = new String[] { KeyRings._ID, KeyRings.MASTER_KEY_ID, - UserIds.USER_ID }; + static final String[] PROJECTION = new String[]{ + KeychainContract.KeyRings._ID, + KeychainContract.KeyRings.MASTER_KEY_ID, + KeychainContract.UserIds.USER_ID, + KeychainContract.Keys.IS_REVOKED + }; static final int USER_ID_INDEX = 2; @@ -270,7 +277,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte startActivity(viewIntent); } - public void encrypt(long[] keyRingRowIds) { + public void encrypt(ActionMode mode, long[] keyRingRowIds) { // get master key ids from row ids long[] keyRingIds = new long[keyRingRowIds.length]; for (int i = 0; i < keyRingRowIds.length; i++) { @@ -282,15 +289,44 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, keyRingIds); // used instead of startActivity set actionbar based on callingPackage startActivityForResult(intent, 0); + + mode.finish(); } /** * Show dialog to delete key - * + * * @param keyRingRowIds */ - public void showDeleteKeyDialog(long[] keyRingRowIds) { - DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(null, + public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) { + // Message is received after key is deleted + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { + Bundle returnData = message.getData(); + if (returnData != null + && returnData.containsKey(DeleteKeyDialogFragment.MESSAGE_NOT_DELETED)) { + ArrayList<String> notDeleted = + returnData.getStringArrayList(DeleteKeyDialogFragment.MESSAGE_NOT_DELETED); + String notDeletedMsg = ""; + for (String userId : notDeleted) { + notDeletedMsg += userId + "\n"; + } + Toast.makeText(getActivity(), getString(R.string.error_can_not_delete_contacts, notDeletedMsg) + + getResources().getQuantityString(R.plurals.error_can_not_delete_info, notDeleted.size()), + Toast.LENGTH_LONG).show(); + + mode.finish(); + } + } + } + }; + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(returnHandler); + + DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, keyRingRowIds, Id.type.public_key); deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog"); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java index f2e6131f6..f9d267f27 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java @@ -17,6 +17,7 @@ package org.sufficientlysecure.keychain.ui; +import java.util.ArrayList; import java.util.Set; import org.sufficientlysecure.keychain.Id; @@ -33,6 +34,9 @@ import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; import android.support.v4.app.ListFragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; @@ -45,6 +49,7 @@ import android.widget.AdapterView; import android.widget.ListView; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView.OnItemClickListener; +import android.widget.Toast; public class KeyListSecretFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener { @@ -103,13 +108,12 @@ public class KeyListSecretFragment extends ListFragment implements } switch (item.getItemId()) { - case R.id.menu_key_list_public_multi_delete: { - showDeleteKeyDialog(ids); - - break; - } + case R.id.menu_key_list_public_multi_delete: { + showDeleteKeyDialog(mode, ids); + break; + } } - return false; + return true; } @Override @@ -120,7 +124,7 @@ public class KeyListSecretFragment extends ListFragment implements @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, - boolean checked) { + boolean checked) { if (checked) { count++; mAdapter.setNewSelection(position, checked); @@ -153,8 +157,8 @@ public class KeyListSecretFragment extends ListFragment implements } // These are the rows that we will retrieve. - static final String[] PROJECTION = new String[] { KeyRings._ID, KeyRings.MASTER_KEY_ID, - UserIds.USER_ID }; + static final String[] PROJECTION = new String[]{KeyRings._ID, KeyRings.MASTER_KEY_ID, + UserIds.USER_ID}; static final String SORT_ORDER = UserIds.USER_ID + " COLLATE LOCALIZED ASC"; public Loader<Cursor> onCreateLoader(int id, Bundle args) { @@ -202,13 +206,27 @@ public class KeyListSecretFragment extends ListFragment implements /** * Show dialog to delete key - * + * * @param keyRingRowIds */ - public void showDeleteKeyDialog(long[] keyRingRowIds) { - DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(null, + public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) { + // Message is received after key is deleted + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { + mode.finish(); + } + } + }; + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(returnHandler); + + DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, keyRingRowIds, Id.type.secret_key); deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog"); } + } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java index e3881503b..550d3047d 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -40,7 +40,7 @@ import android.widget.Toast; import com.beardedhen.androidbootstrap.BootstrapButton; /** - * Sends the selected public key to a key server + * Sends the selected public key to a keyserver */ public class UploadKeyActivity extends ActionBarActivity { private BootstrapButton mUploadButton; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 99d93fbbd..0a452bc8a 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -18,8 +18,17 @@ package org.sufficientlysecure.keychain.ui; -import java.util.ArrayList; -import java.util.Date; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.support.v4.view.ViewPager; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBarActivity; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.Toast; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; @@ -27,63 +36,27 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.helper.ExportHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter; -import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter; +import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment; import org.sufficientlysecure.keychain.util.Log; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -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.v7.app.ActionBarActivity; -import android.text.format.DateFormat; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.Toast; - -import com.beardedhen.androidbootstrap.BootstrapButton; +import java.util.ArrayList; -public class ViewKeyActivity extends ActionBarActivity implements - LoaderManager.LoaderCallbacks<Cursor> { +public class ViewKeyActivity extends ActionBarActivity { ExportHelper mExportHelper; protected Uri mDataUri; - 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 BootstrapButton mActionEncrypt; - - private ListView mUserIds; - private ListView mKeys; - - private static final int LOADER_ID_KEYRING = 0; - private static final int LOADER_ID_USER_IDS = 1; - private static final int LOADER_ID_KEYS = 2; - private ViewKeyUserIdsAdapter mUserIdsAdapter; - private ViewKeyKeysAdapter mKeysAdapter; + public static final String EXTRA_SELECTED_TAB = "selectedTab"; + + ViewPager mViewPager; + TabsAdapter mTabsAdapter; + + private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006; @Override protected void onCreate(Bundle savedInstanceState) { @@ -91,25 +64,36 @@ public class ViewKeyActivity extends ActionBarActivity implements mExportHelper = new ExportHelper(this); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setIcon(android.R.color.transparent); - getSupportActionBar().setHomeButtonEnabled(true); + // let the actionbar look like Android's contact app + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setIcon(android.R.color.transparent); + actionBar.setHomeButtonEnabled(true); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); setContentView(R.layout.view_key_activity); - mName = (TextView) findViewById(R.id.name); - mEmail = (TextView) findViewById(R.id.email); - mComment = (TextView) findViewById(R.id.comment); - mKeyId = (TextView) findViewById(R.id.key_id); - mAlgorithm = (TextView) findViewById(R.id.algorithm); - mCreation = (TextView) findViewById(R.id.creation); - mExpiry = (TextView) findViewById(R.id.expiry); - mFingerprint = (TextView) findViewById(R.id.fingerprint); - mActionEncrypt = (BootstrapButton) findViewById(R.id.action_encrypt); - mUserIds = (ListView) findViewById(R.id.user_ids); - mKeys = (ListView) findViewById(R.id.keys); - - loadData(getIntent()); + mViewPager = (ViewPager) findViewById(R.id.pager); + + mTabsAdapter = new TabsAdapter(this, mViewPager); + + int selectedTab = 0; + Intent intent = getIntent(); + if (intent.getExtras() != null && intent.getExtras().containsKey(EXTRA_SELECTED_TAB)) { + selectedTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB); + } + + mDataUri = getIntent().getData(); + + 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 ? true : false)); + + 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 ? true : false)); } @Override @@ -130,9 +114,6 @@ public class ViewKeyActivity extends ActionBarActivity implements case R.id.menu_key_view_update: updateFromKeyserver(mDataUri); return true; - case R.id.menu_key_view_sign: - signKey(mDataUri); - return true; case R.id.menu_key_view_export_keyserver: uploadToKeyserver(mDataUri); return true; @@ -159,230 +140,13 @@ public class ViewKeyActivity extends ActionBarActivity implements copyToClipboard(mDataUri); return true; case R.id.menu_key_view_delete: { - // Message is received after key is deleted - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { - setResult(RESULT_CANCELED); - finish(); - } - } - }; - - mExportHelper.deleteKey(mDataUri, Id.type.public_key, returnHandler); + deleteKey(mDataUri); return true; } } return super.onOptionsItemSelected(item); } - private void loadData(Intent intent) { - if (intent.getData().equals(mDataUri)) { - Log.d(Constants.TAG, "Same URI, no need to load the data again!"); - return; - } - - mDataUri = intent.getData(); - if (mDataUri == null) { - Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!"); - finish(); - return; - } - - Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); - - mActionEncrypt.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - long keyId = ProviderHelper.getMasterKeyId(ViewKeyActivity.this, mDataUri); - - long[] encryptionKeyIds = new long[]{keyId}; - Intent intent = new Intent(ViewKeyActivity.this, EncryptActivity.class); - intent.setAction(EncryptActivity.ACTION_ENCRYPT); - intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); - // used instead of startActivity set actionbar based on callingPackage - startActivityForResult(intent, 0); - } - }); - - mUserIdsAdapter = new ViewKeyUserIdsAdapter(this, null, 0); - - mUserIds.setAdapter(mUserIdsAdapter); - // mUserIds.setEmptyView(findViewById(android.R.id.empty)); - // mUserIds.setClickable(true); - // mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() { - // @Override - // public void onItemClick(AdapterView<?> arg0, View arg1, int position, long id) { - // } - // }); - - mKeysAdapter = new ViewKeyKeysAdapter(this, null, 0); - - mKeys.setAdapter(mKeysAdapter); - - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - getSupportLoaderManager().initLoader(LOADER_ID_KEYRING, null, this); - getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); - getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this); - } - - static final String[] KEYRING_PROJECTION = new String[]{KeyRings._ID, KeyRings.MASTER_KEY_ID, - UserIds.USER_ID}; - static final int KEYRING_INDEX_ID = 0; - static final int KEYRING_INDEX_MASTER_KEY_ID = 1; - static final int KEYRING_INDEX_USER_ID = 2; - - static final String[] USER_IDS_PROJECTION = new String[]{UserIds._ID, UserIds.USER_ID, - UserIds.RANK,}; - // not the main user id - static final String USER_IDS_SELECTION = UserIds.RANK + " > 0 "; - static final String USER_IDS_SORT_ORDER = UserIds.USER_ID + " COLLATE LOCALIZED ASC"; - - static final String[] KEYS_PROJECTION = new String[]{Keys._ID, Keys.KEY_ID, - Keys.IS_MASTER_KEY, Keys.ALGORITHM, Keys.KEY_SIZE, Keys.CAN_CERTIFY, Keys.CAN_SIGN, - Keys.CAN_ENCRYPT, Keys.CREATION, Keys.EXPIRY, Keys.FINGERPRINT}; - static final String KEYS_SORT_ORDER = Keys.RANK + " ASC"; - static final int KEYS_INDEX_ID = 0; - static final int KEYS_INDEX_KEY_ID = 1; - static final int KEYS_INDEX_IS_MASTER_KEY = 2; - static final int KEYS_INDEX_ALGORITHM = 3; - static final int KEYS_INDEX_KEY_SIZE = 4; - static final int KEYS_INDEX_CAN_CERTIFY = 5; - static final int KEYS_INDEX_CAN_SIGN = 6; - static final int KEYS_INDEX_CAN_ENCRYPT = 7; - static final int KEYS_INDEX_CREATION = 8; - static final int KEYS_INDEX_EXPIRY = 9; - static final int KEYS_INDEX_FINGERPRINT = 10; - - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - switch (id) { - case LOADER_ID_KEYRING: { - Uri baseUri = mDataUri; - - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(this, baseUri, KEYRING_PROJECTION, null, null, null); - } - case LOADER_ID_USER_IDS: { - Uri baseUri = UserIds.buildUserIdsUri(mDataUri); - - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(this, baseUri, USER_IDS_PROJECTION, USER_IDS_SELECTION, null, - USER_IDS_SORT_ORDER); - } - case LOADER_ID_KEYS: { - Uri baseUri = Keys.buildKeysUri(mDataUri); - - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(this, baseUri, KEYS_PROJECTION, null, null, KEYS_SORT_ORDER); - } - - default: - return null; - } - } - - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - switch (loader.getId()) { - case LOADER_ID_KEYRING: - if (data.moveToFirst()) { - // get name, email, and comment from USER_ID - String[] mainUserId = PgpKeyHelper.splitUserId(data - .getString(KEYRING_INDEX_USER_ID)); - if (mainUserId[0] != null) { - setTitle(mainUserId[0]); - mName.setText(mainUserId[0]); - } else { - setTitle(R.string.user_id_no_name); - mName.setText(R.string.user_id_no_name); - } - mEmail.setText(mainUserId[1]); - mComment.setText(mainUserId[2]); - } - - break; - case LOADER_ID_USER_IDS: - mUserIdsAdapter.swapCursor(data); - break; - case LOADER_ID_KEYS: - // the first key here is our master key - if (data.moveToFirst()) { - // get key id from MASTER_KEY_ID - long keyId = data.getLong(KEYS_INDEX_KEY_ID); - - String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId); - mKeyId.setText(keyIdStr); - - // get creation date from CREATION - if (data.isNull(KEYS_INDEX_CREATION)) { - mCreation.setText(R.string.none); - } else { - Date creationDate = new Date(data.getLong(KEYS_INDEX_CREATION) * 1000); - - mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format( - creationDate)); - } - - // get expiry date from EXPIRY - if (data.isNull(KEYS_INDEX_EXPIRY)) { - mExpiry.setText(R.string.none); - } else { - Date expiryDate = new Date(data.getLong(KEYS_INDEX_EXPIRY) * 1000); - - mExpiry.setText(DateFormat.getDateFormat(getApplicationContext()).format( - expiryDate)); - } - - String algorithmStr = PgpKeyHelper.getAlgorithmInfo( - data.getInt(KEYS_INDEX_ALGORITHM), data.getInt(KEYS_INDEX_KEY_SIZE)); - mAlgorithm.setText(algorithmStr); - - byte[] fingerprintBlob = data.getBlob(KEYS_INDEX_FINGERPRINT); - if (fingerprintBlob == null) { - // FALLBACK for old database entries - fingerprintBlob = ProviderHelper.getFingerprint(this, mDataUri); - } - String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob, true); - fingerprint = fingerprint.replace(" ", "\n"); - - mFingerprint.setText(fingerprint); - } - - mKeysAdapter.swapCursor(data); - break; - - default: - break; - } - } - - /** - * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. - * We need to make sure we are no longer using it. - */ - public void onLoaderReset(Loader<Cursor> loader) { - switch (loader.getId()) { - case LOADER_ID_KEYRING: - // No resources need to be freed for this ID - break; - case LOADER_ID_USER_IDS: - mUserIdsAdapter.swapCursor(null); - break; - case LOADER_ID_KEYS: - mKeysAdapter.swapCursor(null); - break; - default: - break; - } - } - private void uploadToKeyserver(Uri dataUri) { Intent uploadIntent = new Intent(this, UploadKeyActivity.class); uploadIntent.setData(dataUri); @@ -398,21 +162,15 @@ public class ViewKeyActivity extends ActionBarActivity implements } Intent queryIntent = new Intent(this, ImportKeysActivity.class); - queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEY_SERVER); + queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER); queryIntent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, updateKeyId); - // TODO: lookup?? - startActivityForResult(queryIntent, Id.request.look_up_key_id); - } - - private void signKey(Uri dataUri) { - Intent signIntent = new Intent(this, SignKeyActivity.class); - signIntent.setData(dataUri); - startActivity(signIntent); + // TODO: lookup with onactivityresult! + startActivityForResult(queryIntent, RESULT_CODE_LOOKUP_KEY); } private void shareKey(Uri dataUri, boolean fingerprintOnly) { - String content = null; + String content; if (fingerprintOnly) { byte[] fingerprintBlob = ProviderHelper.getFingerprint(this, dataUri); String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob, false); @@ -465,4 +223,29 @@ public class ViewKeyActivity extends ActionBarActivity implements dialog.show(getSupportFragmentManager(), "shareNfcDialog"); } + private void deleteKey(Uri dataUri) { + // Message is received after key is deleted + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { + Bundle returnData = message.getData(); + if (returnData != null + && returnData.containsKey(DeleteKeyDialogFragment.MESSAGE_NOT_DELETED)) { + // we delete only this key, so MESSAGE_NOT_DELETED will solely contain this key + Toast.makeText(ViewKeyActivity.this, + getString(R.string.error_can_not_delete_contact) + + getResources().getQuantityString(R.plurals.error_can_not_delete_info, 1), + Toast.LENGTH_LONG).show(); + } else { + setResult(RESULT_CANCELED); + finish(); + } + } + } + }; + + mExportHelper.deleteKey(dataUri, Id.type.public_key, returnHandler); + } + } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java index a2e3e4339..59037d9ff 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java @@ -23,7 +23,6 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.ProviderHelper; import android.annotation.TargetApi; -import android.database.Cursor; import android.net.Uri; import android.nfc.NdefMessage; import android.nfc.NdefRecord; @@ -35,12 +34,11 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.support.v4.app.LoaderManager; import android.widget.Toast; @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMessageCallback, - OnNdefPushCompleteCallback, LoaderManager.LoaderCallbacks<Cursor> { + OnNdefPushCompleteCallback { // NFC private NfcAdapter mNfcAdapter; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java new file mode 100644 index 000000000..36d3e6ace --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java @@ -0,0 +1,92 @@ +/* + * 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.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.beardedhen.androidbootstrap.BootstrapButton; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Log; + + +public class ViewKeyCertsFragment extends Fragment { + + public static final String ARG_DATA_URI = "uri"; + + private BootstrapButton mActionCertify; + + private Uri mDataUri; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.view_key_certs_fragment, container, false); + + mActionCertify = (BootstrapButton) view.findViewById(R.id.action_certify); + + 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) { + if (dataUri.equals(mDataUri)) { + Log.d(Constants.TAG, "Same URI, no need to load the data again!"); + return; + } + + mDataUri = dataUri; + + Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + + mActionCertify.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + certifyKey(mDataUri); + } + }); + + } + + private void certifyKey(Uri dataUri) { + Intent signIntent = new Intent(getActivity(), CertifyKeyActivity.class); + signIntent.setData(dataUri); + startActivity(signIntent); + } + +}
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java new file mode 100644 index 000000000..495764eaf --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -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.content.Intent; +import android.database.Cursor; +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.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; +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 TextView mName; + private TextView mEmail; + private TextView mComment; + private TextView mAlgorithm; + private TextView mKeyId; + private TextView mExpiry; + private TextView mCreation; + private TextView mFingerprint; + private BootstrapButton mActionEncrypt; + + private ListView mUserIds; + private ListView mKeys; + + private static final int LOADER_ID_KEYRING = 0; + private static final int LOADER_ID_USER_IDS = 1; + private static final int LOADER_ID_KEYS = 2; + + private ViewKeyUserIdsAdapter mUserIdsAdapter; + private ViewKeyKeysAdapter mKeysAdapter; + + private Uri mDataUri; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.view_key_main_fragment, container, false); + + 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); + mUserIds = (ListView) view.findViewById(R.id.user_ids); + mKeys = (ListView) view.findViewById(R.id.keys); + mActionEncrypt = (BootstrapButton) view.findViewById(R.id.action_encrypt); + + 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) { + if (dataUri.equals(mDataUri)) { + Log.d(Constants.TAG, "Same URI, no need to load the data again!"); + return; + } + + mDataUri = dataUri; + + Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + + mActionEncrypt.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + encryptToContact(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_KEYRING, null, this); + getActivity().getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); + getActivity().getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this); + } + + static final String[] KEYRING_PROJECTION = new String[]{KeychainContract.KeyRings._ID, KeychainContract.KeyRings.MASTER_KEY_ID, + KeychainContract.UserIds.USER_ID}; + static final int KEYRING_INDEX_ID = 0; + static final int KEYRING_INDEX_MASTER_KEY_ID = 1; + static final int KEYRING_INDEX_USER_ID = 2; + + static final String[] USER_IDS_PROJECTION = new String[]{KeychainContract.UserIds._ID, KeychainContract.UserIds.USER_ID, + KeychainContract.UserIds.RANK,}; + // not the main user id + static final String USER_IDS_SELECTION = KeychainContract.UserIds.RANK + " > 0 "; + static final String USER_IDS_SORT_ORDER = KeychainContract.UserIds.USER_ID + " COLLATE LOCALIZED ASC"; + + static final String[] KEYS_PROJECTION = new String[]{KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID, + KeychainContract.Keys.IS_MASTER_KEY, KeychainContract.Keys.ALGORITHM, KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY, KeychainContract.Keys.CAN_SIGN, + KeychainContract.Keys.CAN_ENCRYPT, KeychainContract.Keys.CREATION, KeychainContract.Keys.EXPIRY, KeychainContract.Keys.FINGERPRINT}; + static final String KEYS_SORT_ORDER = KeychainContract.Keys.RANK + " ASC"; + static final int KEYS_INDEX_ID = 0; + static final int KEYS_INDEX_KEY_ID = 1; + static final int KEYS_INDEX_IS_MASTER_KEY = 2; + static final int KEYS_INDEX_ALGORITHM = 3; + static final int KEYS_INDEX_KEY_SIZE = 4; + static final int KEYS_INDEX_CAN_CERTIFY = 5; + static final int KEYS_INDEX_CAN_SIGN = 6; + static final int KEYS_INDEX_CAN_ENCRYPT = 7; + static final int KEYS_INDEX_CREATION = 8; + static final int KEYS_INDEX_EXPIRY = 9; + static final int KEYS_INDEX_FINGERPRINT = 10; + + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + switch (id) { + case LOADER_ID_KEYRING: { + Uri baseUri = mDataUri; + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + return new CursorLoader(getActivity(), baseUri, KEYRING_PROJECTION, null, null, null); + } + case LOADER_ID_USER_IDS: { + Uri baseUri = KeychainContract.UserIds.buildUserIdsUri(mDataUri); + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + return new CursorLoader(getActivity(), baseUri, USER_IDS_PROJECTION, USER_IDS_SELECTION, null, + USER_IDS_SORT_ORDER); + } + case LOADER_ID_KEYS: { + Uri baseUri = KeychainContract.Keys.buildKeysUri(mDataUri); + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, KEYS_SORT_ORDER); + } + + default: + return null; + } + } + + public void onLoadFinished(Loader<Cursor> loader, Cursor data) { + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + switch (loader.getId()) { + case LOADER_ID_KEYRING: + if (data.moveToFirst()) { + // get name, email, and comment from USER_ID + String[] mainUserId = PgpKeyHelper.splitUserId(data + .getString(KEYRING_INDEX_USER_ID)); + 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]); + } + + break; + case LOADER_ID_USER_IDS: + mUserIdsAdapter.swapCursor(data); + break; + case LOADER_ID_KEYS: + // the first key here is our master key + if (data.moveToFirst()) { + // get key id from MASTER_KEY_ID + long keyId = data.getLong(KEYS_INDEX_KEY_ID); + + String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId); + mKeyId.setText(keyIdStr); + + // get creation date from CREATION + if (data.isNull(KEYS_INDEX_CREATION)) { + mCreation.setText(R.string.none); + } else { + Date creationDate = new Date(data.getLong(KEYS_INDEX_CREATION) * 1000); + + mCreation.setText(DateFormat.getDateFormat(getActivity().getApplicationContext()).format( + creationDate)); + } + + // get expiry date from EXPIRY + if (data.isNull(KEYS_INDEX_EXPIRY)) { + mExpiry.setText(R.string.none); + } else { + Date expiryDate = new Date(data.getLong(KEYS_INDEX_EXPIRY) * 1000); + + mExpiry.setText(DateFormat.getDateFormat(getActivity().getApplicationContext()).format( + expiryDate)); + } + + String algorithmStr = PgpKeyHelper.getAlgorithmInfo( + data.getInt(KEYS_INDEX_ALGORITHM), data.getInt(KEYS_INDEX_KEY_SIZE)); + mAlgorithm.setText(algorithmStr); + + byte[] fingerprintBlob = data.getBlob(KEYS_INDEX_FINGERPRINT); + if (fingerprintBlob == null) { + // FALLBACK for old database entries + fingerprintBlob = ProviderHelper.getFingerprint(getActivity(), mDataUri); + } + String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob, true); + fingerprint = fingerprint.replace(" ", "\n"); + + mFingerprint.setText(fingerprint); + } + + mKeysAdapter.swapCursor(data); + break; + + default: + break; + } + } + + /** + * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. + * We need to make sure we are no longer using it. + */ + public void onLoaderReset(Loader<Cursor> loader) { + switch (loader.getId()) { + case LOADER_ID_KEYRING: + // No resources need to be freed for this ID + break; + case LOADER_ID_USER_IDS: + mUserIdsAdapter.swapCursor(null); + break; + case LOADER_ID_KEYS: + mKeysAdapter.swapCursor(null); + break; + default: + break; + } + } + + + private void encryptToContact(Uri dataUri) { + long keyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri); + + 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); + // used instead of startActivity set actionbar based on callingPackage + startActivityForResult(intent, 0); + } + + private void certifyKey(Uri dataUri) { + Intent signIntent = new Intent(getActivity(), CertifyKeyActivity.class); + signIntent.setData(dataUri); + startActivity(signIntent); + } + + +}
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index a850fc020..52186b662 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -90,16 +90,11 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { View view = mInflater.inflate(R.layout.import_keys_list_entry, null); TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); - mainUserId.setText(R.string.user_id_no_name); TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - mainUserIdRest.setText(""); TextView keyId = (TextView) view.findViewById(R.id.keyId); - keyId.setText(R.string.no_key); TextView fingerprint = (TextView) view.findViewById(R.id.fingerprint); TextView algorithm = (TextView) view.findViewById(R.id.algorithm); - algorithm.setText(""); TextView status = (TextView) view.findViewById(R.id.status); - status.setText(""); // main user id String userId = entry.userIds.get(0); @@ -113,6 +108,8 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { mainUserId.setTextColor(Color.RED); } mainUserId.setText(userIdSplit[0]); + } else { + mainUserId.setText(R.string.user_id_no_name); } // email @@ -124,12 +121,18 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { } keyId.setText(entry.hexKeyId); - fingerprint.setText(mActivity.getString(R.string.fingerprint) + " " + entry.fingerPrint); + + if (entry.fingerPrint != null) { + fingerprint.setText(mActivity.getString(R.string.fingerprint) + " " + entry.fingerPrint); + fingerprint.setVisibility(View.VISIBLE); + } else { + fingerprint.setVisibility(View.GONE); + } algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm); if (entry.revoked) { - status.setText("revoked"); + status.setText(R.string.revoked); } else { status.setVisibility(View.GONE); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java index 5094e8abd..4a7a9c93a 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java @@ -48,7 +48,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { private boolean selected; - private byte[] bytes = new byte[] {}; + private byte[] bytes = new byte[]{}; public ImportKeysListEntry(ImportKeysListEntry b) { this.userIds = b.userIds; @@ -167,7 +167,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { this.revoked = pgpKeyRing.getPublicKey().isRevoked(); this.fingerPrint = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey() .getFingerprint(), true); - this.hexKeyId = PgpKeyHelper.convertKeyIdToHex(keyId); + this.hexKeyId = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId); this.bitStrength = pgpKeyRing.getPublicKey().getBitStrength(); int algorithm = pgpKeyRing.getPublicKey().getAlgorithm(); if (algorithm == PGPPublicKey.RSA_ENCRYPT || algorithm == PGPPublicKey.RSA_GENERAL diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java index 753994450..b3bc39127 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java @@ -79,7 +79,7 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysL } /** - * Query key server + * Query keyserver */ private void queryServer(String query, String keyServer) { HkpKeyServer server = new HkpKeyServer(keyServer); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java index f0e926655..257136cbd 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java @@ -23,10 +23,11 @@ import java.util.Set; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; +import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.util.Log; import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; + import android.annotation.SuppressLint; import android.content.Context; import android.database.Cursor; @@ -35,6 +36,7 @@ import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.RelativeLayout; import android.widget.TextView; /** @@ -44,6 +46,7 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea private LayoutInflater mInflater; private int mSectionColumnIndex; private int mIndexUserId; + private int mIndexIsRevoked; @SuppressLint("UseSparseArrays") private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>(); @@ -66,48 +69,59 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea /** * Get column indexes for performance reasons just once in constructor and swapCursor. For a * performance comparison see http://stackoverflow.com/a/17999582 - * + * * @param cursor */ private void initIndex(Cursor cursor) { if (cursor != null) { - mIndexUserId = cursor.getColumnIndexOrThrow(UserIds.USER_ID); + mIndexUserId = cursor.getColumnIndexOrThrow(KeychainContract.UserIds.USER_ID); + mIndexIsRevoked = cursor.getColumnIndexOrThrow(KeychainContract.Keys.IS_REVOKED); } } /** * Bind cursor data to the item list view - * + * <p/> * NOTE: CursorAdapter already implements the ViewHolder pattern in its getView() method. Thus * no ViewHolder is required here. */ @Override public void bindView(View view, Context context, Cursor cursor) { TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); - mainUserId.setText(R.string.user_id_no_name); TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - mainUserIdRest.setText(""); + TextView revoked = (TextView) view.findViewById(R.id.revoked); String userId = cursor.getString(mIndexUserId); String[] userIdSplit = PgpKeyHelper.splitUserId(userId); - if (userIdSplit[0] != null) { mainUserId.setText(userIdSplit[0]); + } else { + mainUserId.setText(R.string.user_id_no_name); } if (userIdSplit[1] != null) { mainUserIdRest.setText(userIdSplit[1]); + mainUserIdRest.setVisibility(View.VISIBLE); + } else { + mainUserIdRest.setVisibility(View.GONE); + } + + boolean isRevoked = cursor.getInt(mIndexIsRevoked) > 0; + if (isRevoked) { + revoked.setVisibility(View.VISIBLE); + } else { + revoked.setVisibility(View.GONE); } } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.key_list_item, null); + return mInflater.inflate(R.layout.key_list_public_item, null); } /** * Creates a new header view and binds the section headers to it. It uses the ViewHolder * pattern. Most functionality is similar to getView() from Android's CursorAdapter. - * + * <p/> * NOTE: The variables mDataValid and mCursor are available due to the super class * CursorAdapter. */ @@ -159,8 +173,7 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea } // return the first character of the name as ID because this is what - // headers private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, - // Boolean>();are based upon + // headers are based upon String userId = mCursor.getString(mSectionColumnIndex); if (userId != null && userId.length() > 0) { return userId.subSequence(0, 1).charAt(0); @@ -173,7 +186,9 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea TextView text; } - /** -------------------------- MULTI-SELECTION METHODS -------------- */ + /** + * -------------------------- MULTI-SELECTION METHODS -------------- + */ public void setNewSelection(int position, boolean value) { mSelection.put(position, value); notifyDataSetChanged(); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java index ce9b48bff..11d1e8c17 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java @@ -71,24 +71,26 @@ public class KeyListSecretAdapter extends CursorAdapter { @Override public void bindView(View view, Context context, Cursor cursor) { TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); - mainUserId.setText(R.string.user_id_no_name); TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - mainUserIdRest.setText(""); String userId = cursor.getString(mIndexUserId); String[] userIdSplit = PgpKeyHelper.splitUserId(userId); if (userIdSplit[0] != null) { mainUserId.setText(userIdSplit[0]); + } else { + mainUserId.setText(R.string.user_id_no_name); } if (userIdSplit[1] != null) { mainUserIdRest.setText(userIdSplit[1]); + } else { + mainUserIdRest.setText(""); } } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.key_list_item, null); + return mInflater.inflate(R.layout.key_list_secret_item, null); } /** -------------------------- MULTI-SELECTION METHODS -------------- */ diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java index 7e01faf9b..d44dd5890 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java @@ -96,27 +96,31 @@ public class SelectKeyCursorAdapter extends CursorAdapter { boolean valid = cursor.getInt(mIndexProjectionValid) > 0; TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); - mainUserId.setText(R.string.user_id_no_name); TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - mainUserIdRest.setText(""); TextView keyId = (TextView) view.findViewById(R.id.keyId); - keyId.setText(R.string.no_key); TextView status = (TextView) view.findViewById(R.id.status); - status.setText(R.string.unknown_status); String userId = cursor.getString(mIndexUserId); String[] userIdSplit = PgpKeyHelper.splitUserId(userId); if (userIdSplit[0] != null) { mainUserId.setText(userIdSplit[0]); + } else { + mainUserId.setText(R.string.user_id_no_name); } if (userIdSplit[1] != null) { mainUserIdRest.setText(userIdSplit[1]); + } else { + mainUserIdRest.setText(""); } + // TODO: needed to key id to no? + keyId.setText(R.string.no_key); long masterKeyId = cursor.getLong(mIndexMasterKeyId); keyId.setText(PgpKeyHelper.convertKeyIdToHex(masterKeyId)); + // TODO: needed to set unknown_status? + status.setText(R.string.unknown_status); if (valid) { if (mKeyType == Id.type.public_key) { status.setText(R.string.can_encrypt); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java new file mode 100644 index 000000000..924a70897 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java @@ -0,0 +1,84 @@ +package org.sufficientlysecure.keychain.ui.adapter; + +import android.content.Context; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.view.ViewPager; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBarActivity; + +import java.util.ArrayList; + +public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.TabListener, + ViewPager.OnPageChangeListener { + private final Context mContext; + private final ActionBar mActionBar; + private final ViewPager mViewPager; + private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); + + static final class TabInfo { + private final Class<?> clss; + private final Bundle args; + + TabInfo(Class<?> _class, Bundle _args) { + clss = _class; + args = _args; + } + } + + public TabsAdapter(ActionBarActivity activity, ViewPager pager) { + super(activity.getSupportFragmentManager()); + mContext = activity; + mActionBar = activity.getSupportActionBar(); + mViewPager = pager; + mViewPager.setAdapter(this); + mViewPager.setOnPageChangeListener(this); + } + + public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args, boolean selected) { + TabInfo info = new TabInfo(clss, args); + tab.setTag(info); + tab.setTabListener(this); + mTabs.add(info); + mActionBar.addTab(tab, selected); + notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mTabs.size(); + } + + @Override + public Fragment getItem(int position) { + TabInfo info = mTabs.get(position); + return Fragment.instantiate(mContext, info.clss.getName(), info.args); + } + + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + } + + public void onPageSelected(int position) { + mActionBar.setSelectedNavigationItem(position); + } + + public void onPageScrollStateChanged(int state) { + } + + public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { + Object tag = tab.getTag(); + for (int i = 0; i < mTabs.size(); i++) { + if (mTabs.get(i) == tag) { + mViewPager.setCurrentItem(i); + } + } + } + + public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { + } + + public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { + } +}
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java index d5162c403..54c7eb60e 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java @@ -76,38 +76,39 @@ public class ViewKeyKeysAdapter extends CursorAdapter { @Override public void bindView(View view, Context context, Cursor cursor) { + TextView keyId = (TextView) view.findViewById(R.id.keyId); + TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails); + ImageView masterKeyIcon = (ImageView) view.findViewById(R.id.ic_masterKey); + ImageView certifyIcon = (ImageView) view.findViewById(R.id.ic_certifyKey); + ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey); + ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey); + String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)); String algorithmStr = PgpKeyHelper.getAlgorithmInfo(cursor.getInt(mIndexAlgorithm), cursor.getInt(mIndexKeySize)); - TextView keyId = (TextView) view.findViewById(R.id.keyId); keyId.setText(keyIdStr); - TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails); keyDetails.setText("(" + algorithmStr + ")"); - ImageView masterKeyIcon = (ImageView) view.findViewById(R.id.ic_masterKey); if (cursor.getInt(mIndexIsMasterKey) != 1) { masterKeyIcon.setVisibility(View.INVISIBLE); } else { masterKeyIcon.setVisibility(View.VISIBLE); } - ImageView certifyIcon = (ImageView) view.findViewById(R.id.ic_certifyKey); if (cursor.getInt(mIndexCanCertify) != 1) { certifyIcon.setVisibility(View.GONE); } else { certifyIcon.setVisibility(View.VISIBLE); } - ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey); if (cursor.getInt(mIndexCanEncrypt) != 1) { encryptIcon.setVisibility(View.GONE); } else { encryptIcon.setVisibility(View.VISIBLE); } - ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey); if (cursor.getInt(mIndexCanSign) != 1) { signIcon.setVisibility(View.GONE); } else { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java index 109bfe929..3c44bff81 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java @@ -23,12 +23,16 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; +import android.database.Cursor; +import android.net.Uri; import android.os.Bundle; import android.os.Message; import android.os.Messenger; @@ -36,6 +40,8 @@ import android.os.RemoteException; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; +import java.util.ArrayList; + public class DeleteKeyDialogFragment extends DialogFragment { private static final String ARG_MESSENGER = "messenger"; private static final String ARG_DELETE_KEY_RING_ROW_IDS = "delete_file"; @@ -43,13 +49,15 @@ public class DeleteKeyDialogFragment extends DialogFragment { public static final int MESSAGE_OKAY = 1; + public static final String MESSAGE_NOT_DELETED = "not_deleted"; + private Messenger mMessenger; /** * Creates new instance of this delete file dialog fragment */ public static DeleteKeyDialogFragment newInstance(Messenger messenger, long[] keyRingRowIds, - int keyType) { + int keyType) { DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment(); Bundle args = new Bundle(); @@ -77,20 +85,13 @@ public class DeleteKeyDialogFragment extends DialogFragment { builder.setTitle(R.string.warning); if (keyRingRowIds.length == 1) { - // TODO: better way to do this? - String userId = activity.getString(R.string.user_id_no_name); - + Uri dataUri; if (keyType == Id.type.public_key) { - PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRingByRowId(activity, - keyRingRowIds[0]); - userId = PgpKeyHelper.getMainUserIdSafe(activity, - PgpKeyHelper.getMasterKey(keyRing)); + dataUri = KeychainContract.KeyRings.buildPublicKeyRingsUri(String.valueOf(keyRingRowIds[0])); } else { - PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByRowId(activity, - keyRingRowIds[0]); - userId = PgpKeyHelper.getMainUserIdSafe(activity, - PgpKeyHelper.getMasterKey(keyRing)); + dataUri = KeychainContract.KeyRings.buildSecretKeyRingsUri(String.valueOf(keyRingRowIds[0])); } + String userId = ProviderHelper.getUserId(activity, dataUri); builder.setMessage(getString( keyType == Id.type.public_key ? R.string.key_deletion_confirmation @@ -104,9 +105,61 @@ public class DeleteKeyDialogFragment extends DialogFragment { @Override public void onClick(DialogInterface dialog, int id) { + ArrayList<String> notDeleted = new ArrayList<String>(); + if (keyType == Id.type.public_key) { - for (long keyRowId : keyRingRowIds) { - ProviderHelper.deletePublicKeyRing(activity, keyRowId); + Uri queryUri = KeychainContract.KeyRings.buildPublicKeyRingsUri(); + String[] projection = new String[]{ + KeychainContract.KeyRings._ID, // 0 + KeychainContract.KeyRings.MASTER_KEY_ID, // 1 + KeychainContract.UserIds.USER_ID // 2 + }; + + // make selection with all entries where _ID is one of the given row ids + String selection = KeychainDatabase.Tables.KEY_RINGS + "." + + KeychainContract.KeyRings._ID + " IN("; + String selectionIDs = ""; + for (int i = 0; i < keyRingRowIds.length; i++) { + selectionIDs += "'" + String.valueOf(keyRingRowIds[i]) + "'"; + if (i+1 < keyRingRowIds.length) + selectionIDs += ","; + } + selection += selectionIDs + ")"; + + Cursor cursor = activity.getContentResolver().query(queryUri, projection, + selection, null, null); + + long rowId; + long masterKeyId; + String userId; + try { + while (cursor != null && cursor.moveToNext()) { + rowId = cursor.getLong(0); + masterKeyId = cursor.getLong(1); + userId = cursor.getString(2); + + Log.d(Constants.TAG, "rowId: " + rowId + ", masterKeyId: " + masterKeyId + + ", userId: " + userId); + + // check if a corresponding secret key exists... + Cursor secretCursor = activity.getContentResolver().query( + KeychainContract.KeyRings.buildSecretKeyRingsByMasterKeyIdUri(String.valueOf(masterKeyId)), + null, null, null, null + ); + if (secretCursor != null && secretCursor.getCount() > 0) { + notDeleted.add(userId); + } else { + // it is okay to delete this key, no secret key found! + ProviderHelper.deletePublicKeyRing(activity, rowId); + } + if (secretCursor != null) { + secretCursor.close(); + } + } + } finally { + if (cursor != null) { + cursor.close(); + } } } else { for (long keyRowId : keyRingRowIds) { @@ -116,7 +169,13 @@ public class DeleteKeyDialogFragment extends DialogFragment { dismiss(); - sendMessageToHandler(MESSAGE_OKAY); + if (notDeleted.size() > 0) { + Bundle data = new Bundle(); + data.putStringArrayList(MESSAGE_NOT_DELETED, notDeleted); + sendMessageToHandler(MESSAGE_OKAY, data); + } else { + sendMessageToHandler(MESSAGE_OKAY, null); + } } }); builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @@ -131,13 +190,15 @@ public class DeleteKeyDialogFragment extends DialogFragment { /** * Send message back to handler which is initialized in a activity - * - * @param what - * Message integer you want to send + * + * @param what Message integer you want to send */ - private void sendMessageToHandler(Integer what) { + private void sendMessageToHandler(Integer what, Bundle data) { Message msg = Message.obtain(); msg.what = what; + if (data != null) { + msg.setData(data); + } try { mMessenger.send(msg); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/LookupUnknownKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/LookupUnknownKeyDialogFragment.java deleted file mode 100644 index a0592285f..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/LookupUnknownKeyDialogFragment.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2012-2013 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.dialog; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.ui.ImportKeysActivity; -import org.sufficientlysecure.keychain.util.Log; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; -import android.content.Intent; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.support.v4.app.DialogFragment; - -public class LookupUnknownKeyDialogFragment extends DialogFragment { - private static final String ARG_MESSENGER = "messenger"; - private static final String ARG_UNKNOWN_KEY_ID = "unknown_key_id"; - - public static final int MESSAGE_OKAY = 1; - public static final int MESSAGE_CANCEL = 2; - - private Messenger mMessenger; - - /** - * Creates new instance of this dialog fragment - * - * @param messenger - * @param unknownKeyId - * @return - */ - public static LookupUnknownKeyDialogFragment newInstance(Messenger messenger, long unknownKeyId) { - LookupUnknownKeyDialogFragment frag = new LookupUnknownKeyDialogFragment(); - Bundle args = new Bundle(); - args.putLong(ARG_UNKNOWN_KEY_ID, unknownKeyId); - args.putParcelable(ARG_MESSENGER, messenger); - - frag.setArguments(args); - - return frag; - } - - /** - * Creates dialog - */ - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Activity activity = getActivity(); - - final long unknownKeyId = getArguments().getLong(ARG_UNKNOWN_KEY_ID); - mMessenger = getArguments().getParcelable(ARG_MESSENGER); - - AlertDialog.Builder alert = new AlertDialog.Builder(activity); - - alert.setIcon(android.R.drawable.ic_dialog_alert); - alert.setTitle(R.string.title_unknown_signature_key); - alert.setMessage(getString(R.string.lookup_unknown_key, - PgpKeyHelper.convertKeyIdToHex(unknownKeyId))); - - alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - - sendMessageToHandler(MESSAGE_OKAY); - - Intent intent = new Intent(activity, ImportKeysActivity.class); - intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEY_SERVER); - intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, unknownKeyId); - startActivityForResult(intent, Id.request.look_up_key_id); - } - }); - alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - - sendMessageToHandler(MESSAGE_CANCEL); - } - }); - alert.setCancelable(true); - alert.setOnCancelListener(new OnCancelListener() { - - @Override - public void onCancel(DialogInterface dialog) { - sendMessageToHandler(MESSAGE_CANCEL); - } - }); - - return alert.create(); - } - - /** - * Send message back to handler which is initialized in a activity - * - * @param what - * Message integer you want to send - */ - private void sendMessageToHandler(Integer what) { - Message msg = Message.obtain(); - msg.what = what; - - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); - } catch (NullPointerException e) { - Log.w(Constants.TAG, "Messenger is null!", e); - } - } -}
\ No newline at end of file |