1
0
mirror of https://github.com/moparisthebest/k-9 synced 2025-01-07 03:38:08 -05:00

add crypto indicators to top level header

This commit is contained in:
Vincent Breitmoser 2015-02-09 16:51:34 +01:00
parent edc7cac841
commit 1511178f2a
7 changed files with 304 additions and 79 deletions

View File

@ -40,6 +40,7 @@ import com.fsck.k9.activity.setup.Prefs;
import com.fsck.k9.crypto.PgpData;
import com.fsck.k9.fragment.MessageListFragment;
import com.fsck.k9.fragment.MessageListFragment.MessageListFragmentListener;
import com.fsck.k9.ui.messageview.MessageCryptoHelper.MessageCryptoAnnotations;
import com.fsck.k9.ui.messageview.MessageViewFragment;
import com.fsck.k9.ui.messageview.MessageViewFragment.MessageViewFragmentListener;
import com.fsck.k9.mailstore.StorageManager;
@ -1400,18 +1401,18 @@ public class MessageList extends K9Activity implements MessageListFragmentListen
}
@Override
public void onReply(LocalMessage message, PgpData pgpData) {
MessageCompose.actionReply(this, message, false, pgpData.getDecryptedData());
public void onReply(LocalMessage message, String quote) {
MessageCompose.actionReply(this, message, false, quote);
}
@Override
public void onReplyAll(LocalMessage message, PgpData pgpData) {
MessageCompose.actionReply(this, message, true, pgpData.getDecryptedData());
public void onReplyAll(LocalMessage message, String quote) {
MessageCompose.actionReply(this, message, true, quote);
}
@Override
public void onForward(LocalMessage mMessage, PgpData mPgpData) {
MessageCompose.actionForward(this, mMessage, mPgpData.getDecryptedData());
public void onForward(LocalMessage mMessage, String quote) {
MessageCompose.actionForward(this, mMessage, quote);
}
@Override

View File

@ -475,7 +475,6 @@ public class LocalMessageExtractor {
* not contain children of the former types.
*/
ArrayList<Part> parts = new ArrayList<Part>();
if (!getCryptSubPieces(message, parts, annotations)) {
parts.add(message);

View File

@ -427,6 +427,10 @@ public class MessageCryptoHelper {
return annotations.containsKey(part);
}
public OpenPgpResultAnnotation getPrincipalResultForSender(String sender) {
return annotations.isEmpty() ? null : annotations.values().iterator().next();
}
}
}

View File

@ -18,6 +18,7 @@ import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mailstore.MessageViewInfo;
import com.fsck.k9.mailstore.MessageViewInfo.MessageViewContainer;
import com.fsck.k9.ui.messageview.MessageCryptoHelper.MessageCryptoAnnotations;
import com.fsck.k9.view.MessageHeader;
@ -84,12 +85,17 @@ public class MessageView extends LinearLayout {
return mHeaderContainer;
}
public void setHeaders(final Message message, Account account) {
/** This method is called twice: Once before the message is loaded,
* showing all available information at the time and an indeterminate
* progress bar. Once loading of the message has finished, the
* information is updated by another call with the loading flag set
* to false.
*/
public void setHeaders(final Message message, Account account, MessageCryptoAnnotations annotations) {
try {
mHeaderContainer.populate(message, account);
mHeaderContainer.populate(message, account, annotations == null,
annotations == null ? null : annotations.getPrincipalResultForSender(null));
mHeaderContainer.setVisibility(View.VISIBLE);
} catch (Exception me) {
Log.e(K9.LOG_TAG, "setHeaders - error", me);
}

View File

@ -35,7 +35,6 @@ import com.fsck.k9.activity.ChooseFolder;
import com.fsck.k9.activity.MessageReference;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.crypto.PgpData;
import com.fsck.k9.fragment.ConfirmationDialogFragment;
import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
import com.fsck.k9.fragment.ProgressDialogFragment;
@ -57,7 +56,6 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
private static final String ARG_REFERENCE = "reference";
private static final String STATE_MESSAGE_REFERENCE = "reference";
private static final String STATE_PGP_DATA = "pgpData";
private static final int ACTIVITY_CHOOSE_FOLDER_MOVE = 1;
private static final int ACTIVITY_CHOOSE_FOLDER_COPY = 2;
@ -77,7 +75,6 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
}
private MessageView mMessageView;
private PgpData mPgpData;
private Account mAccount;
private MessageReference mMessageReference;
private LocalMessage mMessage;
@ -172,24 +169,22 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
MessageReference messageReference;
if (savedInstanceState != null) {
mPgpData = (PgpData) savedInstanceState.get(STATE_PGP_DATA);
messageReference = (MessageReference) savedInstanceState.get(STATE_MESSAGE_REFERENCE);
} else {
Bundle args = getArguments();
messageReference = args.getParcelable(ARG_REFERENCE);
}
displayMessage(messageReference, (mPgpData == null));
displayMessage(messageReference);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(STATE_MESSAGE_REFERENCE, mMessageReference);
outState.putSerializable(STATE_PGP_DATA, mPgpData);
}
private void displayMessage(MessageReference ref, boolean resetPgpData) {
private void displayMessage(MessageReference ref) {
mMessageReference = ref;
if (K9.DEBUG) {
Log.d(K9.LOG_TAG, "MessageView displaying message " + mMessageReference);
@ -199,11 +194,6 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
mAccount = Preferences.getPreferences(appContext).getAccount(mMessageReference.accountUuid);
messageCryptoHelper = new MessageCryptoHelper(mContext, this, mAccount);
if (resetPgpData) {
// start with fresh, empty PGP data
mPgpData = new PgpData();
}
// Clear previous message
mMessageView.resetView();
mMessageView.resetHeaderView();
@ -222,7 +212,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
}
private void onLoadMessageFromDatabaseFinished(LocalMessage message) {
displayMessageHeader(message);
displayMessageHeader(message, null);
if (message.isBodyMissing()) {
startDownloadingMessageBody(message);
@ -262,6 +252,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
void startExtractingTextAndAttachments(MessageCryptoAnnotations annotations) {
this.messageAnnotations = annotations;
displayMessageHeader(mMessage, messageAnnotations);
getLoaderManager().initLoader(DECODE_MESSAGE_LOADER_ID, null, decodeMessageLoaderCallback);
}
@ -279,8 +270,8 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
}
}
private void displayMessageHeader(LocalMessage message) {
mMessageView.setHeaders(message, mAccount);
private void displayMessageHeader(LocalMessage message, MessageCryptoAnnotations annotations) {
mMessageView.setHeaders(message, mAccount, annotations);
displayMessageSubject(getSubjectForMessage(message));
mFragmentListener.updateMenu();
}
@ -344,21 +335,22 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
mController.moveMessage(mAccount, srcFolder, messageToMove, dstFolder, null);
}
// TODO useful citation
public void onReply() {
if (mMessage != null) {
mFragmentListener.onReply(mMessage, mPgpData);
mFragmentListener.onReply(mMessage, "");
}
}
public void onReplyAll() {
if (mMessage != null) {
mFragmentListener.onReplyAll(mMessage, mPgpData);
mFragmentListener.onReplyAll(mMessage, "");
}
}
public void onForward() {
if (mMessage != null) {
mFragmentListener.onForward(mMessage, mPgpData);
mFragmentListener.onForward(mMessage, "");
}
}
@ -367,7 +359,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
boolean newState = !mMessage.isSet(Flag.FLAGGED);
mController.setFlag(mAccount, mMessage.getFolder().getName(),
Collections.singletonList(mMessage), Flag.FLAGGED, newState);
mMessageView.setHeaders(mMessage, mAccount);
mMessageView.setHeaders(mMessage, mAccount, messageAnnotations);
}
}
@ -479,7 +471,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
if (mMessage != null) {
mController.setFlag(mAccount, mMessage.getFolder().getName(),
Collections.singletonList(mMessage), Flag.SEEN, !mMessage.isSet(Flag.SEEN));
mMessageView.setHeaders(mMessage, mAccount);
mMessageView.setHeaders(mMessage, mAccount, messageAnnotations);
String subject = mMessage.getSubject();
displayMessageSubject(subject);
mFragmentListener.updateMenu();
@ -698,10 +690,10 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
}
public interface MessageViewFragmentListener {
public void onForward(LocalMessage mMessage, PgpData mPgpData);
public void onForward(LocalMessage mMessage, String citation);
public void disableDeleteAction();
public void onReplyAll(LocalMessage mMessage, PgpData mPgpData);
public void onReply(LocalMessage mMessage, PgpData mPgpData);
public void onReplyAll(LocalMessage mMessage, String citation);
public void onReply(LocalMessage mMessage, String citation);
public void displayMessageSubject(String title);
public void setProgress(boolean b);
public void showNextMessageOrReturn();

View File

@ -6,6 +6,7 @@ import java.util.List;
import java.util.Set;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.os.Parcel;
import android.os.Parcelable;
@ -20,7 +21,9 @@ import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.QuickContactBadge;
import android.widget.TextView;
import android.widget.Toast;
@ -38,6 +41,10 @@ import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mailstore.OpenPgpResultAnnotation;
import com.fsck.k9.ui.messageview.MessageCryptoHelper.MessageCryptoAnnotations;
import org.openintents.openpgp.OpenPgpSignatureResult;
public class MessageHeader extends LinearLayout implements OnClickListener {
private Context mContext;
@ -49,6 +56,9 @@ public class MessageHeader extends LinearLayout implements OnClickListener {
private TextView mCcLabel;
private TextView mSubjectView;
private ProgressBar mProgress;
private ImageView mPgpSignatureIcon;
private ImageView mPgpEncryptedIcon;
private View mChip;
private CheckBox mFlagged;
private int defaultSubjectColor;
@ -89,6 +99,9 @@ public class MessageHeader extends LinearLayout implements OnClickListener {
@Override
protected void onFinishInflate() {
mProgress = (ProgressBar) findViewById(R.id.progress);
mAnsweredIcon = findViewById(R.id.answered);
mForwardedIcon = findViewById(R.id.forwarded);
mFromView = (TextView) findViewById(R.id.from);
@ -97,6 +110,9 @@ public class MessageHeader extends LinearLayout implements OnClickListener {
mCcView = (TextView) findViewById(R.id.cc);
mCcLabel = (TextView) findViewById(R.id.cc_label);
mPgpSignatureIcon = (ImageView) findViewById(R.id.pgp_signature_icon);
mPgpEncryptedIcon= (ImageView) findViewById(R.id.pgp_encryption_icon);
mContactBadge = (QuickContactBadge) findViewById(R.id.contact_badge);
mSubjectView = (TextView) findViewById(R.id.subject);
@ -213,7 +229,9 @@ public class MessageHeader extends LinearLayout implements OnClickListener {
}
public void populate(final Message message, final Account account) throws MessagingException {
public void populate(final Message message, final Account account,
boolean loading, OpenPgpResultAnnotation pgpResult)
throws MessagingException {
final Contacts contacts = K9.showContactName() ? mContacts : null;
final CharSequence from = MessageHelper.toFriendly(message.getFrom(), contacts);
final CharSequence to = MessageHelper.toFriendly(message.getRecipients(Message.RecipientType.TO), contacts);
@ -291,6 +309,29 @@ public class MessageHeader extends LinearLayout implements OnClickListener {
mChip.setBackgroundColor(mAccount.getChipColor());
// if this is null, it's still loading
if (loading) {
mProgress.setVisibility(View.VISIBLE);
mPgpSignatureIcon.setVisibility(View.GONE);
mPgpEncryptedIcon.setVisibility(View.GONE);
} else if (pgpResult == null) {
mProgress.setVisibility(View.GONE);
mPgpSignatureIcon.setVisibility(View.GONE);
mPgpEncryptedIcon.setVisibility(View.GONE);
mPgpSignatureIcon.setImageResource(R.drawable.status_signature_unverified_cutout);
int color = R.color.openpgp_sidebar;
mPgpSignatureIcon.setColorFilter(mContext.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
} else {
mProgress.setVisibility(View.GONE);
mPgpSignatureIcon.setVisibility(View.VISIBLE);
mPgpEncryptedIcon.setVisibility(View.VISIBLE);
setPgpStatus(pgpResult);
}
setVisibility(View.VISIBLE);
if (mSavedState != null) {
@ -303,6 +344,173 @@ public class MessageHeader extends LinearLayout implements OnClickListener {
}
}
private void setPgpStatus(OpenPgpResultAnnotation pgpResult) {
OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult();
if (signatureResult == null) {
setStatusImage(mContext, mPgpSignatureIcon, STATE_NOT_SIGNED);
} else {
switch (signatureResult.getStatus()) {
case OpenPgpSignatureResult.SIGNATURE_ERROR: {
setStatusImage(mContext, mPgpSignatureIcon, STATE_INVALID);
break;
}
case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: {
setStatusImage(mContext, mPgpSignatureIcon, STATE_VERIFIED);
break;
}
case OpenPgpSignatureResult.SIGNATURE_KEY_MISSING: {
setStatusImage(mContext, mPgpSignatureIcon, STATE_UNKNOWN_KEY);
break;
}
case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: {
setStatusImage(mContext, mPgpSignatureIcon, STATE_UNVERIFIED);
break;
}
case OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED: {
setStatusImage(mContext, mPgpSignatureIcon, STATE_EXPIRED);
break;
}
case OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED: {
setStatusImage(mContext, mPgpSignatureIcon, STATE_REVOKED);
break;
}
}
}
}
public static final int STATE_REVOKED = 1;
public static final int STATE_EXPIRED = 2;
public static final int STATE_VERIFIED = 3;
public static final int STATE_UNAVAILABLE = 4;
public static final int STATE_ENCRYPTED = 5;
public static final int STATE_NOT_ENCRYPTED = 6;
public static final int STATE_UNVERIFIED = 7;
public static final int STATE_UNKNOWN_KEY = 8;
public static final int STATE_INVALID = 9;
public static final int STATE_NOT_SIGNED = 10;
public static void setStatusImage(Context context, ImageView statusIcon, int state) {
setStatusImage(context, statusIcon, null, state);
}
public static void setStatusImage(Context context, ImageView statusIcon, TextView statusText,
int state) {
switch (state) {
/** GREEN: everything is good **/
case STATE_VERIFIED: {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_verified_cutout));
int color = R.color.openpgp_green;
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
if (statusText != null) {
statusText.setTextColor(context.getResources().getColor(color));
}
break;
}
case STATE_ENCRYPTED: {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_lock_closed));
int color = R.color.openpgp_green;
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
if (statusText != null) {
statusText.setTextColor(context.getResources().getColor(color));
}
break;
}
/** ORANGE: mostly bad... **/
case STATE_UNVERIFIED: {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_unverified_cutout));
int color = R.color.openpgp_orange;
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
if (statusText != null) {
statusText.setTextColor(context.getResources().getColor(color));
}
break;
}
case STATE_UNKNOWN_KEY: {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout));
int color = R.color.openpgp_orange;
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
if (statusText != null) {
statusText.setTextColor(context.getResources().getColor(color));
}
break;
}
/** RED: really bad... **/
case STATE_REVOKED: {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_revoked_cutout));
int color = R.color.openpgp_red;
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
if (statusText != null) {
statusText.setTextColor(context.getResources().getColor(color));
}
break;
}
case STATE_EXPIRED: {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_expired_cutout));
int color = R.color.openpgp_red;
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
if (statusText != null) {
statusText.setTextColor(context.getResources().getColor(color));
}
break;
}
case STATE_NOT_ENCRYPTED: {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_lock_open));
int color = R.color.openpgp_red;
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
if (statusText != null) {
statusText.setTextColor(context.getResources().getColor(color));
}
break;
}
case STATE_NOT_SIGNED: {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout));
int color = R.color.openpgp_red;
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
if (statusText != null) {
statusText.setTextColor(context.getResources().getColor(color));
}
break;
}
case STATE_INVALID: {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout));
int color = R.color.openpgp_red;
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
if (statusText != null) {
statusText.setTextColor(context.getResources().getColor(color));
}
break;
}
}
}
public void onShowAdditionalHeaders() {
int currentVisibility = mAdditionalHeadersView.getVisibility();
if (currentVisibility == View.VISIBLE) {

View File

@ -39,47 +39,12 @@
android:layout_height="wrap_content"
android:orientation="horizontal" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<QuickContactBadge
android:id="@+id/contact_badge"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp" />
<!-- State icons -->
<LinearLayout
android:id="@+id/icon_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:layout_marginBottom="2dip"
android:layout_below="@+id/contact_badge"
android:layout_centerHorizontal="true"
android:orientation="vertical" >
<View
android:id="@+id/answered"
android:layout_width="32sp"
android:layout_height="32sp"
android:paddingRight="2dip"
android:background="@drawable/ic_email_answered_small" />
<View
android:id="@+id/forwarded"
android:layout_width="22sp"
android:layout_height="22sp"
android:paddingRight="4dip"
android:background="@drawable/ic_email_forwarded_small" />
</LinearLayout>
</RelativeLayout>
<QuickContactBadge
android:id="@+id/contact_badge"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="16dp" />
<RelativeLayout
android:layout_width="match_parent"
@ -87,13 +52,28 @@
android:padding="6dip"
android:layout_marginLeft="2dp" >
<ProgressBar
style="?android:attr/progressBarStyleSmall"
android:layout_width="24dp"
android:layout_height="24dp"
android:id="@+id/progress"
android:indeterminate="true"
android:layout_alignParentLeft="true" />
<ImageView
android:id="@+id/pgp_signature_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/status_signature_unverified_cutout"
android:layout_gravity="center_vertical" />
<!-- From -->
<TextView
android:id="@+id/from"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_toRightOf="@+id/pgp_signature_icon"
android:layout_toLeftOf="@+id/flagged"
android:paddingTop="0dp"
android:paddingRight="6dip"
@ -109,7 +89,7 @@
android:id="@+id/to_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/from"
android:layout_alignParentLeft="true"
android:layout_alignBaseline="@+id/to"
android:paddingTop="2dp"
android:paddingRight="4dp"
@ -170,7 +150,8 @@
android:singleLine="true"
android:ellipsize="none"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary" />
android:textColor="?android:attr/textColorSecondary"
android:text="Jan 1st 2015" />
<CheckBox
android:id="@+id/flagged"
@ -182,10 +163,44 @@
style="?android:attr/starStyle"
android:checked="false" />
<LinearLayout
android:id="@+id/icon_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_below="@+id/cc"
android:layout_alignParentLeft="true"
>
<View
android:id="@+id/answered"
android:layout_width="32sp"
android:layout_height="32sp"
android:paddingRight="2dip"
android:background="@drawable/ic_email_answered_small" />
<View
android:id="@+id/forwarded"
android:layout_width="32sp"
android:layout_height="32sp"
android:paddingRight="4dip"
android:background="@drawable/ic_email_forwarded_small" />
<ImageView
android:id="@+id/pgp_encryption_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/status_lock_open"
android:layout_gravity="center_vertical" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
<!-- State icons -->
<TextView
android:id="@+id/additional_headers_view"
android:layout_width="match_parent"