diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 53ec4870c..9bee42973 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -30,6 +30,7 @@ import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpHelper; @@ -212,6 +213,13 @@ public class ProviderHelper { ++userIdRank; } + for (PGPSignature certification : new IterableIterator(masterKey.getSignaturesOfType(PGPSignature.POSITIVE_CERTIFICATION))) { + //TODO: how to do this?? we need to verify the signatures again and again when they are displayed... +// if (certification.verify +// operations.add(buildPublicKeyOperations(context, keyRingRowId, key, rank)); + } + + try { context.getContentResolver().applyBatch(KeychainContract.CONTENT_AUTHORITY, operations); } catch (RemoteException e) { 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 similarity index 88% rename from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpFragmentAbout.java rename to 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 mTabs = new ArrayList(); - - 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 similarity index 81% rename from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpFragmentHtml.java rename to 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/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 14640480e..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,64 +36,25 @@ 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 java.util.ArrayList; -import com.beardedhen.androidbootstrap.BootstrapButton; - -public class ViewKeyActivity extends ActionBarActivity implements - LoaderManager.LoaderCallbacks { +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 BootstrapButton mActionCertify; + public static final String EXTRA_SELECTED_TAB = "selectedTab"; - 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; + ViewPager mViewPager; + TabsAdapter mTabsAdapter; private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006; @@ -95,26 +65,35 @@ public class ViewKeyActivity extends ActionBarActivity implements mExportHelper = new ExportHelper(this); // let the actionbar look like Android's contact app - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setIcon(android.R.color.transparent); - getSupportActionBar().setHomeButtonEnabled(true); + 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); - mUserIds = (ListView) findViewById(R.id.user_ids); - mKeys = (ListView) findViewById(R.id.keys); - mActionEncrypt = (BootstrapButton) findViewById(R.id.action_encrypt); - mActionCertify = (BootstrapButton) findViewById(R.id.action_certify); + mViewPager = (ViewPager) findViewById(R.id.pager); - loadData(getIntent()); + 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 @@ -168,210 +147,6 @@ public class ViewKeyActivity extends ActionBarActivity implements 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) { - encryptToContact(mDataUri); - } - }); - mActionCertify.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - certifyKey(mDataUri); - } - }); - - 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 loaders. Either re-connect with an existing ones, - // or start new ones. - 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 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 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 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); @@ -394,25 +169,8 @@ public class ViewKeyActivity extends ActionBarActivity implements startActivityForResult(queryIntent, RESULT_CODE_LOOKUP_KEY); } - private void encryptToContact(Uri dataUri) { - long keyId = ProviderHelper.getMasterKeyId(ViewKeyActivity.this, dataUri); - - 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); - } - - private void certifyKey(Uri dataUri) { - Intent signIntent = new Intent(this, CertifyKeyActivity.class); - signIntent.setData(dataUri); - startActivity(signIntent); - } - 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); 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 { + 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 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.ui; + +import 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 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.ui; + +import 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{ + + 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 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 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 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/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 mTabs = new ArrayList(); + + 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/res/layout/view_key_activity.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_activity.xml index 1c937430a..58e4919dc 100644 --- a/OpenPGP-Keychain/src/main/res/layout/view_key_activity.xml +++ b/OpenPGP-Keychain/src/main/res/layout/view_key_activity.xml @@ -1,229 +1,12 @@ - + + android:layout_height="match_parent" + android:orientation="vertical" > - + android:layout_height="match_parent" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_certs_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_certs_fragment.xml new file mode 100644 index 000000000..2a3dafc93 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/layout/view_key_certs_fragment.xml @@ -0,0 +1,31 @@ + + + + + + + + + + \ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml index b50253980..c44835bb0 100644 --- a/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml +++ b/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml @@ -1,8 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml index 2d022ba13..508d080a6 100644 --- a/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml +++ b/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml @@ -1,16 +1,15 @@ + android:paddingRight="3dip" + android:singleLine="true"> diff --git a/OpenPGP-Keychain/src/main/res/values/strings.xml b/OpenPGP-Keychain/src/main/res/values/strings.xml index 059b6ca9e..3a719afed 100644 --- a/OpenPGP-Keychain/src/main/res/values/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values/strings.xml @@ -414,6 +414,8 @@ Encrypt to this contact Certify this contact\'s key + Info + Certifications Contacts