diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index d42bae67a..28f230f71 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -49,7 +49,6 @@ import java.util.Date; * convenience. */ public class PassphraseCacheService extends Service { - public static final String TAG = Constants.TAG + ": PassphraseCacheService"; public static final String ACTION_PASSPHRASE_CACHE_ADD = Constants.INTENT_PREFIX + "PASSPHRASE_CACHE_ADD"; @@ -83,7 +82,7 @@ public class PassphraseCacheService extends Service { * @param passphrase */ public static void addCachedPassphrase(Context context, long keyId, String passphrase) { - Log.d(TAG, "cacheNewPassphrase() for " + keyId); + Log.d(Constants.TAG, "PassphraseCacheService.cacheNewPassphrase() for " + keyId); Intent intent = new Intent(context, PassphraseCacheService.class); intent.setAction(ACTION_PASSPHRASE_CACHE_ADD); @@ -103,7 +102,7 @@ public class PassphraseCacheService extends Service { * @return passphrase or null (if no passphrase is cached for this keyId) */ public static String getCachedPassphrase(Context context, long keyId) { - Log.d(TAG, "getCachedPassphrase() get masterKeyId for " + keyId); + Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphrase() get masterKeyId for " + keyId); Intent intent = new Intent(context, PassphraseCacheService.class); intent.setAction(ACTION_PASSPHRASE_CACHE_GET); @@ -159,7 +158,7 @@ public class PassphraseCacheService extends Service { private String getCachedPassphraseImpl(long keyId) { // passphrase for symmetric encryption? if (keyId == Constants.key.symmetric) { - Log.d(TAG, "getCachedPassphraseImpl() for symmetric encryption"); + Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption"); String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric); if (cachedPassphrase == null) { return null; @@ -170,7 +169,7 @@ public class PassphraseCacheService extends Service { // try to get master key id which is used as an identifier for cached passphrases try { - Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + keyId); + Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for masterKeyId " + keyId); WrappedSecretKeyRing key = new ProviderHelper(this).getWrappedSecretKeyRing( KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(keyId)); // no passphrase needed? just add empty string and return it, then @@ -184,18 +183,18 @@ public class PassphraseCacheService extends Service { // get cached passphrase String cachedPassphrase = mPassphraseCache.get(keyId); if (cachedPassphrase == null) { - Log.d(TAG, "Passphrase not (yet) cached, returning null"); + Log.d(Constants.TAG, "PassphraseCacheService Passphrase not (yet) cached, returning null"); // not really an error, just means the passphrase is not cached but not empty either return null; } // set it again to reset the cache life cycle - Log.d(TAG, "Cache passphrase again when getting it!"); + Log.d(Constants.TAG, "PassphraseCacheService Cache passphrase again when getting it!"); addCachedPassphrase(this, keyId, cachedPassphrase); return cachedPassphrase; } catch (ProviderHelper.NotFoundException e) { - Log.e(TAG, "Passphrase for unknown key was requested!"); + Log.e(Constants.TAG, "PassphraseCacheService Passphrase for unknown key was requested!"); return null; } } @@ -212,7 +211,7 @@ public class PassphraseCacheService extends Service { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - Log.d(TAG, "Received broadcast..."); + Log.d(Constants.TAG, "PassphraseCacheService Received broadcast..."); if (action.equals(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE)) { long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1); @@ -248,7 +247,7 @@ public class PassphraseCacheService extends Service { */ @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.d(TAG, "onStartCommand()"); + Log.d(Constants.TAG, "PassphraseCacheService.onStartCommand()"); // register broadcastreceiver registerReceiver(); @@ -259,8 +258,8 @@ public class PassphraseCacheService extends Service { long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1); String passphrase = intent.getStringExtra(EXTRA_PASSPHRASE); - Log.d(TAG, - "Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with keyId: " + Log.d(Constants.TAG, + "PassphraseCacheService Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with keyId: " + keyId + ", ttl: " + ttl); // add keyId and passphrase to memory @@ -285,10 +284,10 @@ public class PassphraseCacheService extends Service { try { messenger.send(msg); } catch (RemoteException e) { - Log.e(Constants.TAG, "Sending message failed", e); + Log.e(Constants.TAG, "PassphraseCacheService Sending message failed", e); } } else { - Log.e(Constants.TAG, "Intent or Intent Action not supported!"); + Log.e(Constants.TAG, "PassphraseCacheService Intent or Intent Action not supported!"); } } @@ -305,11 +304,11 @@ public class PassphraseCacheService extends Service { // remove passphrase corresponding to keyId from memory mPassphraseCache.remove(keyId); - Log.d(TAG, "Timeout of keyId " + keyId + ", removed from memory!"); + Log.d(Constants.TAG, "PassphraseCacheService Timeout of keyId " + keyId + ", removed from memory!"); // stop whole service if no cached passphrases remaining if (mPassphraseCache.size() == 0) { - Log.d(TAG, "No passphrases remaining in memory, stopping service!"); + Log.d(Constants.TAG, "PassphraseCacheServic No passphrases remaining in memory, stopping service!"); stopSelf(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index d734c31db..906ed347e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -231,7 +231,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { // get new key from data bundle returned from service - Bundle data = message.getData(); + Bundle data = message.getDataAsStringList(); ArrayList newKeys = PgpConversionHelper.BytesToPGPSecretKeyList(data diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index b6a95a517..1defa4034 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -51,13 +51,14 @@ import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; -import org.sufficientlysecure.keychain.ui.adapter.UserIdsArrayAdapter; -import org.sufficientlysecure.keychain.ui.dialog.AddUserIdDialogFragment; +import org.sufficientlysecure.keychain.ui.adapter.UserIdsAddedAdapter; import org.sufficientlysecure.keychain.ui.dialog.EditUserIdDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; import org.sufficientlysecure.keychain.util.Log; +import java.util.ArrayList; + public class EditKeyFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks { @@ -76,7 +77,8 @@ public class EditKeyFragment extends LoaderFragment implements private UserIdsAdapter mUserIdsAdapter; private SubkeysAdapter mKeysAdapter; - private UserIdsArrayAdapter mUserIdsAddedAdapter; + private UserIdsAddedAdapter mUserIdsAddedAdapter; + private ArrayList mUserIdsAddedData; private Uri mDataUri; @@ -189,9 +191,10 @@ public class EditKeyFragment extends LoaderFragment implements } }); - mUserIdsAddedAdapter = new UserIdsArrayAdapter(getActivity()); + // TODO: from savedInstance?! + mUserIdsAddedData = new ArrayList(); + mUserIdsAddedAdapter = new UserIdsAddedAdapter(getActivity(), mUserIdsAddedData); mUserIdsAddedList.setAdapter(mUserIdsAddedAdapter); - mUserIdsAddedAdapter.setData(mSaveKeyringParcel.addUserIds); mKeysAdapter = new SubkeysAdapter(getActivity(), null, 0); mKeysList.setAdapter(mKeysAdapter); @@ -321,34 +324,7 @@ public class EditKeyFragment extends LoaderFragment implements } private void addUserId() { - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case AddUserIdDialogFragment.MESSAGE_OKAY: - Bundle data = message.getData(); - String userId = data.getString(AddUserIdDialogFragment.MESSAGE_DATA_USER_ID); - - if (userId != null) { - mSaveKeyringParcel.addUserIds.add(userId); - mUserIdsAddedAdapter.setData(mSaveKeyringParcel.addUserIds); - } - } - getLoaderManager().getLoader(LOADER_ID_USER_IDS).forceLoad(); - } - }; - - // Create a new Messenger for the communication back - final Messenger messenger = new Messenger(returnHandler); - - DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { - public void run() { - AddUserIdDialogFragment dialogFragment = - AddUserIdDialogFragment.newInstance(messenger); - - dialogFragment.show(getActivity().getSupportFragmentManager(), "addUserIdDialog"); - } - }); + mUserIdsAddedAdapter.add(new UserIdsAddedAdapter.UserIdModel()); } private void save() { @@ -360,17 +336,23 @@ public class EditKeyFragment extends LoaderFragment implements @Override public void handleMessage(Message message) { if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - saveFinal(); + String passphrase = + message.getData().getString(PassphraseDialogFragment.MESSAGE_DATA_PASSPHRASE); + Log.d(Constants.TAG, "after caching passphrase"); + saveFinal(passphrase); } } } ); - + } else { + saveFinal(passphrase); } - } - private void saveFinal() { + private void saveFinal(String passphrase) { + Log.d(Constants.TAG, "add userids to parcel: " + mUserIdsAddedAdapter.getDataAsStringList()); + mSaveKeyringParcel.addUserIds = mUserIdsAddedAdapter.getDataAsStringList(); + // Message is received after importing is done in KeychainIntentService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( getActivity(), @@ -408,6 +390,7 @@ public class EditKeyFragment extends LoaderFragment implements // fill values for this action Bundle data = new Bundle(); + data.putString(KeychainIntentService.SAVE_KEYRING_PASSPHRASE, passphrase); data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, mSaveKeyringParcel); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index d2cb5283d..d6b0c7944 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -439,9 +439,7 @@ public class KeyListFragment extends LoaderFragment private class ItemViewHolder { TextView mMainUserId; TextView mMainUserIdRest; - View mStatusDivider; FrameLayout mStatusLayout; - ImageButton mButton; TextView mRevoked; ImageView mVerified; } @@ -452,9 +450,7 @@ public class KeyListFragment extends LoaderFragment ItemViewHolder holder = new ItemViewHolder(); holder.mMainUserId = (TextView) view.findViewById(R.id.mainUserId); holder.mMainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - holder.mStatusDivider = (View) view.findViewById(R.id.status_divider); holder.mStatusLayout = (FrameLayout) view.findViewById(R.id.status_layout); - holder.mButton = (ImageButton) view.findViewById(R.id.edit); holder.mRevoked = (TextView) view.findViewById(R.id.revoked); holder.mVerified = (ImageView) view.findViewById(R.id.verified); view.setTag(holder); @@ -491,26 +487,12 @@ public class KeyListFragment extends LoaderFragment { // set edit button and revoked info, specific by key type if (cursor.getInt(KeyListFragment.INDEX_HAS_ANY_SECRET) != 0) { - // this is a secret key - show the edit mButton - h.mStatusDivider.setVisibility(View.VISIBLE); + // this is a secret key h.mStatusLayout.setVisibility(View.VISIBLE); h.mRevoked.setVisibility(View.GONE); h.mVerified.setVisibility(View.GONE); - h.mButton.setVisibility(View.VISIBLE); - - final long id = cursor.getLong(INDEX_MASTER_KEY_ID); - h.mButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); - editIntent.setData(KeyRingData.buildSecretKeyRingUri(Long.toString(id))); - editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY); - startActivityForResult(editIntent, 0); - } - }); } else { - // this is a public key - hide the edit mButton, show if it's revoked - h.mStatusDivider.setVisibility(View.GONE); - h.mButton.setVisibility(View.GONE); + // this is a public key - show if it's revoked boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0; boolean isExpired = !cursor.isNull(INDEX_EXPIRY) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java index 87ab1bb8c..8634070cc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java @@ -1,3 +1,20 @@ +/* + * 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.os.Bundle; @@ -9,14 +26,14 @@ import android.view.animation.AnimationUtils; import org.sufficientlysecure.keychain.R; -/** This is a fragment helper class, which implements a generic +/** + * This is a fragment helper class, which implements a generic * progressbar/container view. - * + *

* To use it in a fragment, simply subclass, use onCreateView to create the * layout's root view, and ues getContainer() as root view of your subclass. * The layout shows a progress bar by default, and can be switched to the * actual contents by calling setContentShown(). - * */ public class LoaderFragment extends Fragment { private boolean mContentShown; @@ -35,7 +52,6 @@ public class LoaderFragment extends Fragment { mContentShown = false; return root; - } protected ViewGroup getContainer() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index 7fc78dc41..7bf9334b8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -123,6 +123,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC TextView vComment = (TextView) view.findViewById(R.id.comment); ImageView vVerified = (ImageView) view.findViewById(R.id.certified); ImageView vHasChanges = (ImageView) view.findViewById(R.id.has_changes); + ImageView vEditImage = (ImageView) view.findViewById(R.id.edit_image); String userId = cursor.getString(mIndexUserId); String[] splitUserId = KeyRing.splitUserId(userId); @@ -167,8 +168,10 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC } else { vHasChanges.setVisibility(View.GONE); } + vEditImage.setVisibility(View.VISIBLE); } else { vHasChanges.setVisibility(View.GONE); + vEditImage.setVisibility(View.GONE); } if (isRevoked) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java new file mode 100644 index 000000000..137217ff4 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java @@ -0,0 +1,206 @@ +/* + * 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.adapter; + +import android.app.Activity; +import android.content.Context; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.Patterns; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.EditText; +import android.widget.ImageButton; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.ContactHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; + +public class UserIdsAddedAdapter extends ArrayAdapter { + private LayoutInflater mInflater; + private Activity mActivity; + + private ArrayAdapter mAutoCompleteNameAdapter; + private ArrayAdapter mAutoCompleteEmailAdapter; + + // hold a private reference to the underlying data List + private List mData; + + public static class UserIdModel { + String name = ""; + String address = ""; + String comment = ""; + + @Override + public String toString() { + String userId = name; + if (!TextUtils.isEmpty(comment)) { + userId += " (" + comment + ")"; + } + if (!TextUtils.isEmpty(address)) { + userId += " <" + address + ">"; + } + return userId; + } + } + + public UserIdsAddedAdapter(Activity activity, List data) { + super(activity, -1, data); + mActivity = activity; + mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mData = data; + mAutoCompleteNameAdapter = new ArrayAdapter + (mActivity, android.R.layout.simple_dropdown_item_1line, + ContactHelper.getPossibleUserNames(mActivity) + ); + mAutoCompleteEmailAdapter = new ArrayAdapter + (mActivity, android.R.layout.simple_dropdown_item_1line, + ContactHelper.getPossibleUserEmails(mActivity) + ); + } + + public ArrayList getDataAsStringList() { + ArrayList out = new ArrayList(); + for (UserIdModel id : mData) { + // ignore empty user ids + if (!TextUtils.isEmpty(id.toString())) { + out.add(id.toString()); + } + } + + return out; + } + + static class ViewHolder { + public AutoCompleteTextView vAddress; + public AutoCompleteTextView vName; + public EditText vComment; + public ImageButton vDelete; + // also hold a reference to the model item + public UserIdModel mModel; + } + + public View getView(final int position, View convertView, ViewGroup parent) { + if (convertView == null) { + // Not recycled, inflate a new view + convertView = mInflater.inflate(R.layout.edit_key_user_id_added_item, null); + final ViewHolder viewHolder = new ViewHolder(); + viewHolder.vAddress = (AutoCompleteTextView) convertView.findViewById(R.id.user_id_added_item_address); + viewHolder.vName = (AutoCompleteTextView) convertView.findViewById(R.id.user_id_added_item_name); + viewHolder.vComment = (EditText) convertView.findViewById(R.id.user_id_added_item_comment); + viewHolder.vDelete = (ImageButton) convertView.findViewById(R.id.user_id_added_item_delete); + convertView.setTag(viewHolder); + + viewHolder.vAddress.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + // update referenced item in view holder + viewHolder.mModel.address = s.toString(); + + // show icon on valid email addresses + if (viewHolder.mModel.address.length() > 0) { + Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(viewHolder.mModel.address); + if (emailMatcher.matches()) { + viewHolder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, + R.drawable.uid_mail_ok, 0); + } else { + viewHolder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, + R.drawable.uid_mail_bad, 0); + } + } else { + // remove drawable if email is empty + viewHolder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + } + } + }); + + viewHolder.vName.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + // update referenced item in view holder + viewHolder.mModel.name = s.toString(); + } + }); + + viewHolder.vComment.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + // update referenced item in view holder + viewHolder.mModel.comment = s.toString(); + } + }); + + viewHolder.vDelete.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // remove reference model item from adapter (data and notify about change) + UserIdsAddedAdapter.this.remove(viewHolder.mModel); + } + }); + + } + final ViewHolder holder = (ViewHolder) convertView.getTag(); + + // save reference to model item + holder.mModel = getItem(position); + + holder.vAddress.setText(holder.mModel.address); + holder.vAddress.setThreshold(1); // Start working from first character + holder.vAddress.setAdapter(mAutoCompleteEmailAdapter); + + holder.vName.setText(holder.mModel.name); + holder.vName.setThreshold(1); // Start working from first character + holder.vName.setAdapter(mAutoCompleteNameAdapter); + + holder.vComment.setText(holder.mModel.comment); + + return convertView; + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java deleted file mode 100644 index e6445c074..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2013-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.adapter; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.Context; -import android.os.Build; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.CheckBox; -import android.widget.ImageView; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.KeyRing; - -import java.util.List; - -public class UserIdsArrayAdapter extends ArrayAdapter { - protected LayoutInflater mInflater; - protected Activity mActivity; - - protected List mData; - - static class ViewHolder { - public TextView vName; - public TextView vAddress; - public TextView vComment; - public ImageView vVerified; - public ImageView vHasChanges; - public CheckBox vCheckBox; - } - - public UserIdsArrayAdapter(Activity activity) { - super(activity, -1); - mActivity = activity; - mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public void setData(List data) { - clear(); - if (data != null) { - this.mData = data; - - // add data to extended ArrayAdapter - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - addAll(data); - } else { - for (String entry : data) { - add(entry); - } - } - } - } - - public List getData() { - return mData; - } - - @Override - public boolean hasStableIds() { - return true; - } - - public View getView(int position, View convertView, ViewGroup parent) { - String entry = mData.get(position); - ViewHolder holder; - if (convertView == null) { - holder = new ViewHolder(); - convertView = mInflater.inflate(R.layout.view_key_userids_item, null); - holder.vName = (TextView) convertView.findViewById(R.id.userId); - holder.vAddress = (TextView) convertView.findViewById(R.id.address); - holder.vComment = (TextView) convertView.findViewById(R.id.comment); - holder.vVerified = (ImageView) convertView.findViewById(R.id.certified); - holder.vHasChanges = (ImageView) convertView.findViewById(R.id.has_changes); - holder.vCheckBox = (CheckBox) convertView.findViewById(R.id.checkBox); - convertView.setTag(holder); - } else { - holder = (ViewHolder) convertView.getTag(); - } - - // user id - String[] splitUserId = KeyRing.splitUserId(entry); - if (splitUserId[0] != null) { - holder.vName.setText(splitUserId[0]); - } else { - holder.vName.setText(R.string.user_id_no_name); - } - if (splitUserId[1] != null) { - holder.vAddress.setText(splitUserId[1]); - holder.vAddress.setVisibility(View.VISIBLE); - } else { - holder.vAddress.setVisibility(View.GONE); - } - if (splitUserId[2] != null) { - holder.vComment.setText(splitUserId[2]); - holder.vComment.setVisibility(View.VISIBLE); - } else { - holder.vComment.setVisibility(View.GONE); - } - - holder.vCheckBox.setVisibility(View.GONE); - - holder.vVerified.setImageResource(R.drawable.key_certify_ok_depth0); - - // all items are "new" - holder.vHasChanges.setVisibility(View.VISIBLE); - - return convertView; - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java deleted file mode 100644 index c27266e3f..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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.dialog; - -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.support.v4.app.DialogFragment; -import android.text.TextUtils; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.view.inputmethod.EditorInfo; -import android.widget.EditText; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Log; - -public class AddUserIdDialogFragment extends DialogFragment implements EditText.OnEditorActionListener { - private static final String ARG_MESSENGER = "messenger"; - - public static final int MESSAGE_OKAY = 1; - - public static final String MESSAGE_DATA_USER_ID = "user_id"; - - private Messenger mMessenger; - - EditText mName; - EditText mAddress; - EditText mComment; - - /** - * Creates new instance of this dialog fragment - */ - public static AddUserIdDialogFragment newInstance(Messenger messenger) { - AddUserIdDialogFragment frag = new AddUserIdDialogFragment(); - Bundle args = new Bundle(); - args.putParcelable(ARG_MESSENGER, messenger); - - frag.setArguments(args); - - return frag; - } - - /** - * Creates dialog - */ - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - mMessenger = getArguments().getParcelable(ARG_MESSENGER); - - CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(getActivity()); - LayoutInflater inflater = getActivity().getLayoutInflater(); - View view = inflater.inflate(R.layout.add_user_id_dialog, null); - alert.setView(view); - alert.setTitle("Add Identity"); - - mName = (EditText) view.findViewById(R.id.name); - mAddress = (EditText) view.findViewById(R.id.address); - mComment = (EditText) view.findViewById(R.id.comment); - - alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - done(); - } - }); - - alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - - - return alert.show(); - } - - @Override - public void onActivityCreated(Bundle arg0) { - super.onActivityCreated(arg0); - // Show soft keyboard automatically - mName.requestFocus(); - getDialog().getWindow().setSoftInputMode( - WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); - mComment.setOnEditorActionListener(this); - } - - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (EditorInfo.IME_ACTION_DONE == actionId) { - done(); - return true; - } - return false; - } - - private void done() { - String name = mName.getText().toString(); - String email = mAddress.getText().toString(); - String comment = mComment.getText().toString(); - - String userId = null; - if (!TextUtils.isEmpty(name)) { - userId = name; - if (!TextUtils.isEmpty(comment)) { - userId += " (" + comment + ")"; - } - if (!TextUtils.isEmpty(email)) { - userId += " <" + email + ">"; - } - } - Bundle data = new Bundle(); - data.putString(MESSAGE_DATA_USER_ID, userId); - sendMessageToHandler(MESSAGE_OKAY, data); - - this.dismiss(); - } - - /** - * Send message back to handler which is initialized in a activity - * - * @param what Message integer you want to send - */ - private void sendMessageToHandler(Integer what, Bundle data) { - Message msg = Message.obtain(); - msg.what = what; - if (data != null) { - msg.setData(data); - } - - 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); - } - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java index da29f808a..294ff1500 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java @@ -25,9 +25,7 @@ import android.widget.ListView; * Automatically calculate height of ListView based on contained items. This enables to put this * ListView into a ScrollView without messing up. *

- * from - * http://stackoverflow.com/questions/2419246/how-do-i-create-a-listview-thats-not-in-a-scrollview- - * or-has-the-scrollview-dis + * from http://stackoverflow.com/a/3580117 */ public class FixedListView extends ListView { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java index 4ecc96cee..cd5671801 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java @@ -388,7 +388,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { // get new key from data bundle returned from service - Bundle data = message.getData(); + Bundle data = message.getDataAsStringList(); UncachedSecretKey newKey = PgpConversionHelper .BytesToPGPSecretKey(data .getByteArray(KeychainIntentService.RESULT_NEW_KEY)); diff --git a/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml b/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml deleted file mode 100644 index 502ca1c70..000000000 --- a/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/edit_key_fragment.xml b/OpenKeychain/src/main/res/layout/edit_key_fragment.xml index 7f94cb3cd..05e6c09c5 100644 --- a/OpenKeychain/src/main/res/layout/edit_key_fragment.xml +++ b/OpenKeychain/src/main/res/layout/edit_key_fragment.xml @@ -111,7 +111,7 @@ android:layout_height="match_parent" android:text="add key" android:minHeight="?android:attr/listPreferredItemHeight" - android:drawableRight="@drawable/ic_action_add_person" + android:drawableRight="@drawable/ic_action_new_account" android:drawablePadding="8dp" android:gravity="center_vertical" android:clickable="true" diff --git a/OpenKeychain/src/main/res/layout/edit_key_user_id_added_item.xml b/OpenKeychain/src/main/res/layout/edit_key_user_id_added_item.xml new file mode 100644 index 000000000..542c59b12 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/edit_key_user_id_added_item.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + diff --git a/OpenKeychain/src/main/res/layout/key_list_item.xml b/OpenKeychain/src/main/res/layout/key_list_item.xml index 73a20bd2e..99e4c0268 100644 --- a/OpenKeychain/src/main/res/layout/key_list_item.xml +++ b/OpenKeychain/src/main/res/layout/key_list_item.xml @@ -38,32 +38,11 @@ android:textAppearance="?android:attr/textAppearanceSmall" /> - - - - + android:background="@color/result_green" /> @@ -68,4 +70,13 @@ + + + diff --git a/Resources/gnupg-infographic/README b/Resources/gnupg-infographic/README new file mode 100644 index 000000000..f29c0a84a --- /dev/null +++ b/Resources/gnupg-infographic/README @@ -0,0 +1,13 @@ +Source files for GnuPG infographic +================================== + +These are the source graphics for the Email Self-Defense infographic from the +Free Software Foundation, available at . + +License +------- + +Copyright (c) 2014 Free Software Foundation, Inc. + +Licensed under the Creative Commons Attribution license (CC-BY). See full +source and attribution text at the above site. diff --git a/Resources/gnupg-infographic/gnupg-infographic.png b/Resources/gnupg-infographic/gnupg-infographic.png new file mode 100644 index 000000000..52b8f21ac Binary files /dev/null and b/Resources/gnupg-infographic/gnupg-infographic.png differ diff --git a/Resources/gnupg-infographic/gnupg-infographic.svg b/Resources/gnupg-infographic/gnupg-infographic.svg new file mode 100644 index 000000000..9a17421e2 --- /dev/null +++ b/Resources/gnupg-infographic/gnupg-infographic.svg @@ -0,0 +1,8145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + To protect ourselves from surveillance, we need to learn when to use GnuPG and startsharing our public keys whenever we share email addresses. + + + Thousands of people already use GnuPG, including activists, journalists, whistleblowers and everyday folks. Each person using it makes our community stronger, and shows surveillance agencies that we are ready to fight back. + + + + + + + + + + + GnuPG is freely licensed software; it's completely transparent and anyone can copy it or make their own version. This makes it safer from surveillance than proprietary software (like Windows or Word). Learn more at FSF.org. + + + Teach yourself email self-defense. Learn GnuPG in 30 minutes at EmailSelfDefense.FSF.org + + + + + + + + + + + + + + + + + + + + + + PUBLIC PRIVATE YOUR PUBLIC KEY YOUR PRIVATE KEY + + + All you need is a simple program called GnuPG. It encrypts your email into a code that only the right people can read. GnuPG runs on pretty much any computer or smartphone. It's freely licensed and costs no money. Each user has a unique public key and private key, which are random strings of numbers. Take back your privacy! Meet GnuPG Your public key isn't like a physical key, because it's shared. It's in an online directory, where people can look it up and download it. People use your public key, along with GnuPG, to encrypt emails they send to you. Your private key is more like a physical key, because you keep it to yourself (on your computer). You use GnuPG and your private key to decode encrypted emails other people send to you. If an email encrypted with GnuPG falls into the wrong hands, it'll just look like nonsense. Without the real recipient's private key, it's almost impossible to read it. To the real recipient, it opens up like a normal email. Easy! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The password protecting your email is only a thin layer of security that can't protect against the battering ram of sophisticated surveillance systems. Each message passes through many computer systems on the way to its destination. Surveillance agencies take advantage of this to read millions and millions of emails. Even if you have nothing to hide, when you send normal email, the people you talk to are being exposed as well. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ? ? ? ? + + + + + + + + + + + + + + + + + + + + ERROR + + + %#&$! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + EMAIL SELF-DEFENSE Bulk surveillance violates our fundamental rights and makes free speech risky. But we're far from helpless to do something about it. + + + + + + + + + PUB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PRIV + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ? ? ? ? + The sender and recipient are both safer now. Even if this email doesn't have any private information, being encrypted makes it gum up bulk surveillance systems. Take that, surveillance! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GnuPG + + + + Infographic and guide design by Journalism++ + + + + + Copyright 2014 Free Software Foundation. Remixing encouraged! Get the source at the URL above. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +