This commit is contained in:
unknown 2011-02-12 16:24:56 -05:00
commit 42edb24c4b
14 changed files with 617 additions and 453 deletions

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="13001"
android:versionName="3.701" package="com.fsck.k9"
android:versionCode="13002"
android:versionName="3.702" package="com.fsck.k9"
>
<uses-sdk
android:minSdkVersion="3"

View file

@ -1,5 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<com.fsck.k9.view.SingleMessageView
android:id="@+id/message_view"
android:orientation="vertical"
android:layout_width="fill_parent"
android:background="@android:color/transparent"
android:layout_height="wrap_content"
android:layout_weight="1"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Header area -->
<com.fsck.k9.view.MessageHeader
android:id="@+id/header_container"
@ -216,4 +223,4 @@
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_width="fill_parent" />
</merge>
</com.fsck.k9.view.SingleMessageView>

View file

@ -18,13 +18,9 @@
android:orientation="vertical"
android:layout_width="fill_parent"
android:background="@android:color/transparent"
android:layout_height="0dip"
android:layout_height="wrap_content"
android:layout_weight="1">
<include layout="@layout/message_view_header" />
<View
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1" />
<include layout="@layout/message" />
<include layout="@layout/message_view_scrolling_buttons"/>
</LinearLayout>
</com.fsck.k9.view.ToggleScrollView>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
<com.fsck.k9.view.MessageCryptoView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_decrypt"
android:orientation="horizontal"
@ -55,4 +55,4 @@
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
</com.fsck.k9.view.MessageCryptoView>

View file

@ -1,88 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="@+id/extra_buttons"
android:orientation="horizontal"
android:layout_width="fill_parent"
<LinearLayout
android:id="@+id/extra_buttons"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="2dip"
android:gravity="center_vertical">
<Button
android:id="@+id/reply"
android:text="@string/reply_action"
android:layout_height="wrap_content"
android:paddingBottom="2dip"
android:gravity="center_vertical">
<Button
android:id="@+id/reply"
android:text="@string/reply_action"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1" />
<Button
android:id="@+id/reply_all"
android:text="@string/reply_all_action"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1" />
<Button
android:id="@+id/forward"
android:text="@string/forward_action"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout
android:id="@+id/scrolling_move_buttons"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_width="0dip"
android:layout_weight="1"/>
<Button
android:id="@+id/reply_all"
android:text="@string/reply_all_action"
android:layout_height="wrap_content"
android:paddingBottom="2dip"
android:gravity="center_vertical">
<Button
android:id="@+id/archive_scrolling"
android:text="@string/message_view_archive_action"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1" />
<Button
android:id="@+id/move_scrolling"
android:text="@string/message_view_move_action"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1" />
<Button
android:id="@+id/spam_scrolling"
android:text="@string/message_view_spam_action"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout
android:id="@+id/scrolling_buttons"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_width="0dip"
android:layout_weight="1"/>
<Button
android:id="@+id/forward"
android:text="@string/forward_action"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<Button
android:id="@+id/previous_scrolling"
android:text="@string/message_view_prev_action"
android:contentDescription="@string/previous_action"
android:textSize="35dip"
android:padding="0dip"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1" />
android:layout_width="0dip"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:id="@+id/scrolling_move_buttons"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="2dip"
android:gravity="center_vertical">
<Button
android:id="@+id/archive_scrolling"
android:text="@string/message_view_archive_action"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1"/>
<ImageButton
android:id="@+id/delete_scrolling"
android:layout_height="wrap_content"
android:src="@drawable/ic_button_delete"
android:layout_width="0dip"
android:layout_weight="1" />
<Button
android:id="@+id/next_scrolling"
android:padding="0dip"
android:text="@string/message_view_next_action"
android:textSize="35dip"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1" />
</LinearLayout>
<Button
android:id="@+id/move_scrolling"
android:text="@string/message_view_move_action"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1"/>
<Button
android:id="@+id/spam_scrolling"
android:text="@string/message_view_spam_action"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:id="@+id/scrolling_buttons"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<Button
android:id="@+id/previous_scrolling"
android:text="@string/message_view_prev_action"
android:contentDescription="@string/previous_action"
android:textSize="35dip"
android:padding="0dip"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1"/>
<ImageButton
android:id="@+id/delete_scrolling"
android:layout_height="wrap_content"
android:src="@drawable/ic_button_delete"
android:layout_width="0dip"
android:layout_weight="1"/>
<Button
android:id="@+id/next_scrolling"
android:padding="0dip"
android:text="@string/message_view_next_action"
android:textSize="35dip"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight="1"/>
</LinearLayout>
</merge>

View file

@ -683,6 +683,8 @@ public class Account implements BaseAccount {
switchLocalStorage(id);
successful = true;
} catch (MessagingException e) {
Log.e(K9.LOG_TAG, "Switching local storage provider from " +
mLocalStorageProviderId + " to " + id + " failed.", e);
} finally {
// if migration to/from SD-card failed once, it will fail again.
if (!successful) {

View file

@ -299,6 +299,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
finish();
} else if (startup && accounts.length == 1 && onOpenAccount(accounts[0])) {
// fall through to "else" if !onOpenAccount()
finish();
} else {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
requestWindowFeature(Window.FEATURE_PROGRESS);

View file

@ -20,20 +20,15 @@ import android.widget.*;
import com.fsck.k9.*;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.crypto.CryptoProvider;
import com.fsck.k9.crypto.PgpData;
import com.fsck.k9.helper.Contacts;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.*;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.store.LocalStore.LocalAttachmentBodyPart;
import com.fsck.k9.mail.store.LocalStore.LocalMessage;
import com.fsck.k9.mail.store.StorageManager;
import com.fsck.k9.view.AccessibleWebView;
import com.fsck.k9.view.AttachmentView;
import com.fsck.k9.view.MessageWebView;
import com.fsck.k9.view.ToggleScrollView;
import com.fsck.k9.view.MessageHeader;
import com.fsck.k9.view.SingleMessageView;
import java.io.Serializable;
import java.util.*;
@ -46,22 +41,15 @@ public class MessageView extends K9Activity implements OnClickListener {
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;
private View mDecryptLayout;
private Button mDecryptButton;
private LinearLayout mCryptoSignatureLayout = null;
private ImageView mCryptoSignatureStatusImage = null;
private TextView mCryptoSignatureUserId = null;
private TextView mCryptoSignatureUserIdRest = null;
private MessageWebView mMessageContentView;
private boolean mScreenReaderEnabled;
private AccessibleWebView mAccessibleMessageContentView;
private MessageHeader mHeaderContainer;
private LinearLayout mAttachments;
private View mShowPicturesSection;
private boolean mShowPictures;
private Button mDownloadRemainder;
View next;
View previous;
private SingleMessageView mMessageView;
private PgpData mPgpData;
private View mNext;
private View mPrevious;
private View mDelete;
private View mArchive;
private View mMove;
@ -71,14 +59,12 @@ public class MessageView extends K9Activity implements OnClickListener {
private MessageReference mMessageReference;
private ArrayList<MessageReference> mMessageReferences;
private Message mMessage;
private PgpData mPgpData = null;
private static final int PREVIOUS = 1;
private static final int NEXT = 2;
private int mLastDirection = PREVIOUS;
private MessagingController mController = MessagingController.getInstance(getApplication());
private MessageReference mNextMessage = null;
private MessageReference mPreviousMessage = null;
private Menu optionsMenu = null;
private Listener mListener = new Listener();
private MessageViewHandler mHandler = new MessageViewHandler();
private Contacts mContacts;
@ -209,15 +195,7 @@ public class MessageView extends K9Activity implements OnClickListener {
case KeyEvent.KEYCODE_Z: {
mHandler.post(new Runnable() {
public void run() {
if (mScreenReaderEnabled) {
mAccessibleMessageContentView.zoomIn();
} else {
if (event.isShiftPressed()) {
mMessageContentView.zoomIn();
} else {
mMessageContentView.zoomOut();
}
}
mMessageView.zoom(event);
}
});
return true;
@ -245,31 +223,6 @@ public class MessageView extends K9Activity implements OnClickListener {
}
class MessageViewHandler extends Handler {
public void setHeaders(final Message message) {
runOnUiThread(new Runnable() {
public void run() {
try {
mHeaderContainer.populate(message, mAccount);
mHeaderContainer.setOnFlagListener(new OnClickListener() {
@Override public void onClick(View v) {
if (mMessage != null) {
onFlag();
}
}
});
} catch (Exception me) {
Log.e(K9.LOG_TAG, "setHeaders - error", me);
}
if (mMessage.isSet(Flag.X_DOWNLOADED_FULL)) {
mDownloadRemainder.setVisibility(View.GONE);
} else {
mDownloadRemainder.setEnabled(true);
mDownloadRemainder.setVisibility(View.VISIBLE);
}
}
});
}
public void progress(final boolean progress) {
runOnUiThread(new Runnable() {
@ -282,8 +235,7 @@ public class MessageView extends K9Activity implements OnClickListener {
public void addAttachment(final View attachmentView) {
runOnUiThread(new Runnable() {
public void run() {
mAttachments.addView(attachmentView);
mAttachments.setVisibility(View.VISIBLE);
mMessageView.addAttachment(attachmentView);
}
});
}
@ -291,32 +243,16 @@ public class MessageView extends K9Activity implements OnClickListener {
public void removeAllAttachments() {
runOnUiThread(new Runnable() {
public void run() {
for (int i = 0, count = mAttachments.getChildCount(); i < count; i++) {
mAttachments.removeView(mAttachments.getChildAt(i));
}
mMessageView.removeAllAttachments();
}
});
}
);
}
public void setAttachmentsEnabled(final boolean enabled) {
runOnUiThread(new Runnable() {
public void run() {
for (int i = 0, count = mAttachments.getChildCount(); i < count; i++) {
AttachmentView attachment = (AttachmentView) mAttachments.getChildAt(i);
attachment.viewButton.setEnabled(enabled);
attachment.downloadButton.setEnabled(enabled);
}
}
});
}
public void networkError() {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MessageView.this,
R.string.status_network_error, Toast.LENGTH_LONG).show();
Toast.makeText(MessageView.this, R.string.status_network_error, Toast.LENGTH_LONG).show();
}
});
}
@ -324,8 +260,7 @@ public class MessageView extends K9Activity implements OnClickListener {
public void invalidIdError() {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MessageView.this,
R.string.status_invalid_id_error, Toast.LENGTH_LONG).show();
Toast.makeText(MessageView.this, R.string.status_invalid_id_error, Toast.LENGTH_LONG).show();
}
});
}
@ -344,13 +279,22 @@ public class MessageView extends K9Activity implements OnClickListener {
public void showShowPictures(final boolean show) {
runOnUiThread(new Runnable() {
public void run() {
mShowPicturesSection.setVisibility(show ? View.VISIBLE : View.GONE);
mMessageView.showShowPicturesSection(show);
}
});
}
public void setHeaders(final Message message, final Account account) {
runOnUiThread(new Runnable() {
public void run() {
mMessageView.setHeaders(message, account);
}
});
}
}
public static void actionView(Context context, MessageReference messRef, List<MessageReference> messReferences) {
actionView(context, messRef, messReferences, null);
}
@ -372,22 +316,11 @@ public class MessageView extends K9Activity implements OnClickListener {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.message_view);
mMessageContentView = (MessageWebView) findViewById(R.id.message_content);
mAccessibleMessageContentView = (AccessibleWebView) findViewById(R.id.accessible_message_content);
mAttachments = (LinearLayout) findViewById(R.id.attachments);
mHeaderContainer = (MessageHeader) findViewById(R.id.header_container);
mTopView = mToggleScrollView = (ToggleScrollView) findViewById(R.id.top_view);
mMessageView = (SingleMessageView) findViewById(R.id.message_view);
mScreenReaderEnabled = isScreenReaderActive();
if (mScreenReaderEnabled) {
mAccessibleMessageContentView.setVisibility(View.VISIBLE);
mMessageContentView.setVisibility(View.GONE);
} else {
mAccessibleMessageContentView.setVisibility(View.GONE);
mMessageContentView.setVisibility(View.VISIBLE);
}
setupDecryptLayout();
mMessageView.initialize(this, isScreenReaderActive());
setTitle("");
Intent intent = getIntent();
@ -395,7 +328,6 @@ public class MessageView extends K9Activity implements OnClickListener {
if (icicle != null) {
restoreMessageReferences(icicle);
mPgpData = (PgpData) icicle.getSerializable(STATE_PGP_DATA);
updateDecryptLayout();
} else {
if (uri == null) {
restoreMessageReferencesExtra(intent);
@ -437,12 +369,10 @@ public class MessageView extends K9Activity implements OnClickListener {
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "MessageView got message " + mMessageReference);
if (intent.getBooleanExtra(EXTRA_NEXT, false)) {
next.requestFocus();
mNext.requestFocus();
}
setupHeaderLayout();
setupButtonViews();
displayMessage(mMessageReference);
}
@ -513,51 +443,6 @@ public class MessageView extends K9Activity implements OnClickListener {
buttons.setVisibility(View.GONE);
}
}
}
private void setupHeaderLayout() {
mShowPicturesSection = findViewById(R.id.show_pictures_section);
mShowPictures = false;
mDownloadRemainder = (Button) findViewById(R.id.download_remainder);
mMessageContentView.configure();
mTopView = mToggleScrollView = (ToggleScrollView) findViewById(R.id.top_view);
mAttachments.setVisibility(View.GONE);
}
private void setupDecryptLayout() {
mDecryptLayout = findViewById(R.id.layout_decrypt);
mDecryptButton = (Button) findViewById(R.id.btn_decrypt);
mDecryptButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
try {
String data = null;
Part part = MimeUtility.findFirstPartByMimeType(mMessage, "text/plain");
if (part == null) {
part = MimeUtility.findFirstPartByMimeType(mMessage, "text/html");
}
if (part != null) {
data = MimeUtility.getTextFromPart(part);
}
mAccount.getCryptoProvider().decrypt(MessageView.this, data, mPgpData);
} catch (MessagingException me) {
Log.e(K9.LOG_TAG, "Unable to decrypt email.", me);
}
}
});
mCryptoSignatureLayout = (LinearLayout) findViewById(R.id.crypto_signature);
mCryptoSignatureStatusImage = (ImageView) findViewById(R.id.ic_crypto_signature_status);
mCryptoSignatureUserId = (TextView) findViewById(R.id.userId);
mCryptoSignatureUserIdRest = (TextView) findViewById(R.id.userIdRest);
mCryptoSignatureLayout.setVisibility(View.INVISIBLE);
}
private boolean isScreenReaderActive() {
@ -598,15 +483,15 @@ public class MessageView extends K9Activity implements OnClickListener {
outState.putSerializable(EXTRA_MESSAGE_REFERENCE, mMessageReference);
outState.putSerializable(EXTRA_MESSAGE_REFERENCES, mMessageReferences);
outState.putSerializable(STATE_PGP_DATA, mPgpData);
outState.putBoolean(SHOW_PICTURES, mShowPictures);
outState.putBoolean(SHOW_PICTURES, mMessageView.showPictures());
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
setLoadPictures(savedInstanceState.getBoolean(SHOW_PICTURES));
initializeCrypto((PgpData) savedInstanceState.getSerializable(STATE_PGP_DATA));
updateDecryptLayout();
mPgpData = (PgpData) savedInstanceState.getSerializable(STATE_PGP_DATA);
mMessageView.updateCryptoLayout(mAccount.getCryptoProvider(), mPgpData, mMessage);
}
private void displayMessage(MessageReference ref) {
@ -614,30 +499,28 @@ public class MessageView extends K9Activity implements OnClickListener {
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "MessageView displaying message " + mMessageReference);
mAccount = Preferences.getPreferences(this).getAccount(mMessageReference.accountUuid);
mTopView.setVisibility(View.GONE);
mTopView.scrollTo(0, 0);
mMessageContentView.scrollTo(0, 0);
mHeaderContainer.setVisibility(View.GONE);
mMessageContentView.clearView();
setLoadPictures(false);
mAttachments.removeAllViews();
clearMessageDisplay();
findSurroundingMessagesUid();
// start with fresh, empty PGP data
initializeCrypto(null);
mPgpData = new PgpData();
mTopView.setVisibility(View.VISIBLE);
mController.loadMessageForView(
mAccount,
mMessageReference.folderName,
mMessageReference.uid,
mListener);
mController.loadMessageForView(mAccount, mMessageReference.folderName, mMessageReference.uid, mListener);
setupDisplayMessageButtons();
}
private void clearMessageDisplay() {
mTopView.setVisibility(View.GONE);
mTopView.scrollTo(0, 0);
setLoadPictures(false);
mMessageView.resetView();
}
private void setupDisplayMessageButtons() {
mDelete.setEnabled(true);
next.setEnabled(mNextMessage != null);
previous.setEnabled(mPreviousMessage != null);
mNext.setEnabled(mNextMessage != null);
mPrevious.setEnabled(mPreviousMessage != null);
// If moving isn't support at all, then all of them must be disabled anyway.
if (mController.isMoveCapable(mAccount)) {
// Only enable the button if the Archive folder is not the current folder and not NONE.
@ -657,8 +540,8 @@ public class MessageView extends K9Activity implements OnClickListener {
if (buttons != null) {
buttons.setVisibility(View.GONE);
}
next = findViewById(R.id.next);
previous = findViewById(R.id.previous);
mNext = findViewById(R.id.next);
mPrevious = findViewById(R.id.previous);
mDelete = findViewById(R.id.delete);
}
@ -667,8 +550,8 @@ public class MessageView extends K9Activity implements OnClickListener {
if (buttons != null) {
buttons.setVisibility(View.GONE);
}
next = findViewById(R.id.next_scrolling);
previous = findViewById(R.id.previous_scrolling);
mNext = findViewById(R.id.next_scrolling);
mPrevious = findViewById(R.id.previous_scrolling);
mDelete = findViewById(R.id.delete_scrolling);
}
@ -695,8 +578,8 @@ public class MessageView extends K9Activity implements OnClickListener {
private void disableButtons() {
setLoadPictures(false);
disableMoveButtons();
next.setEnabled(false);
previous.setEnabled(false);
mNext.setEnabled(false);
mPrevious.setEnabled(false);
mDelete.setEnabled(false);
}
@ -869,8 +752,7 @@ public class MessageView extends K9Activity implements OnClickListener {
mMessage.getFolder().getName(), new String[] {mMessage.getUid()}, Flag.FLAGGED, !mMessage.isSet(Flag.FLAGGED));
try {
mMessage.setFlag(Flag.FLAGGED, !mMessage.isSet(Flag.FLAGGED));
mHandler.setHeaders(mMessage);
prepareMenuItems();
mMessageView.setHeaders(mMessage, mAccount);
} catch (MessagingException me) {
Log.e(K9.LOG_TAG, "Could not set flag on local message", me);
}
@ -967,7 +849,7 @@ public class MessageView extends K9Activity implements OnClickListener {
mTopView.startAnimation(outToLeftAnimation());
}
displayMessage(mNextMessage);
next.requestFocus();
mNext.requestFocus();
}
@Override
@ -982,7 +864,7 @@ public class MessageView extends K9Activity implements OnClickListener {
mTopView.startAnimation(inFromRightAnimation());
}
displayMessage(mPreviousMessage);
previous.requestFocus();
mPrevious.requestFocus();
}
private void onMarkAsUnread() {
@ -995,7 +877,7 @@ public class MessageView extends K9Activity implements OnClickListener {
false);
try {
mMessage.setFlag(Flag.SEEN, false);
mHandler.setHeaders(mMessage);
mMessageView.setHeaders(mMessage, mAccount);
String subject = mMessage.getSubject();
setTitle(subject);
} catch (Exception e) {
@ -1009,17 +891,8 @@ public class MessageView extends K9Activity implements OnClickListener {
if (mMessage.isSet(Flag.X_DOWNLOADED_FULL)) {
return;
}
mDownloadRemainder.setEnabled(false);
mController.loadMessageForViewRemote(
mAccount,
mMessageReference.folderName,
mMessageReference.uid,
mListener);
}
private void onShowPictures() {
// TODO: Download attachments that are used as inline image
setLoadPictures(true);
mMessageView.downloadRemainderButton().setEnabled(false);
mController.loadMessageForViewRemote(mAccount, mMessageReference.folderName, mMessageReference.uid, mListener);
}
/**
@ -1030,11 +903,12 @@ public class MessageView extends K9Activity implements OnClickListener {
* false, otherwise.
*/
private void setLoadPictures(boolean enable) {
mMessageContentView.blockNetworkData(!enable);
mShowPictures = enable;
mMessageView.blockNetworkData(!enable);
mMessageView.setShowPictures(enable);
mHandler.showShowPictures(false);
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.reply:
@ -1076,7 +950,7 @@ public class MessageView extends K9Activity implements OnClickListener {
((AttachmentView)view).saveFile();
break;
case R.id.show_pictures:
onShowPictures();
setLoadPictures(true);
break;
case R.id.download_remainder:
onDownloadRemainder();
@ -1122,14 +996,15 @@ public class MessageView extends K9Activity implements OnClickListener {
break;
case R.id.show_full_header:
runOnUiThread(new Runnable() {
@Override public void run() {
mHeaderContainer.onShowAdditionalHeaders();
@Override
public void run() {
mMessageView.showAllHeaders();
}
});
break;
case R.id.select_text:
mToggleScrollView.setScrolling(false);
mMessageContentView.emulateShiftHeld();
mMessageView.beginSelectingText();
break;
default:
return super.onOptionsItemSelected(item);
@ -1141,8 +1016,6 @@ public class MessageView extends K9Activity implements OnClickListener {
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.message_view_option, menu);
optionsMenu = menu;
prepareMenuItems();
if (!mController.isCopyCapable(mAccount)) {
menu.findItem(R.id.copy).setVisible(false);
}
@ -1160,11 +1033,6 @@ public class MessageView extends K9Activity implements OnClickListener {
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
prepareMenuItems();
return super.onPrepareOptionsMenu(menu);
}
// TODO: when switching to API version 8, override onCreateDialog(int, Bundle)
/**
@ -1182,8 +1050,8 @@ public class MessageView extends K9Activity implements OnClickListener {
return super.onCreateDialog(id);
}
private void prepareMenuItems() {
Menu menu = optionsMenu;
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (menu != null) {
MenuItem flagItem = menu.findItem(R.id.flag);
if (flagItem != null && mMessage != null) {
@ -1191,10 +1059,11 @@ public class MessageView extends K9Activity implements OnClickListener {
}
MenuItem additionalHeadersItem = menu.findItem(R.id.show_full_header);
if (additionalHeadersItem != null) {
additionalHeadersItem.setTitle(mHeaderContainer.additionalHeadersVisible() ?
additionalHeadersItem.setTitle(mMessageView.additionalHeadersVisible() ?
R.string.hide_full_header_action : R.string.show_full_header_action);
}
}
return super.onPrepareOptionsMenu(menu);
}
public void displayMessage(Account account, String folder, String uid, Message message) {
@ -1202,13 +1071,13 @@ public class MessageView extends K9Activity implements OnClickListener {
if (MessageView.this.mMessage != null
&& MessageView.this.mMessage.isSet(Flag.X_DOWNLOADED_PARTIAL)
&& message.isSet(Flag.X_DOWNLOADED_FULL)) {
mHandler.setHeaders(message);
mMessageView.setHeaders(message, account);
}
MessageView.this.mMessage = message;
mHandler.removeAllAttachments();
String text, type;
if (mPgpData.getDecryptedData() != null) {
text = mPgpData.getDecryptedData();
String type;
String text = mPgpData.getDecryptedData();
if (text != null) {
type = "text/plain";
} else {
// getTextForDisplay() always returns HTML-ified content.
@ -1221,38 +1090,29 @@ public class MessageView extends K9Activity implements OnClickListener {
mHandler.post(new Runnable() {
public void run() {
mTopView.scrollTo(0, 0);
if (mScreenReaderEnabled) {
mAccessibleMessageContentView.loadDataWithBaseURL("http://",
emailText, contentType, "utf-8", null);
} else {
mMessageContentView.loadDataWithBaseURL("http://", emailText,
contentType, "utf-8", null);
mMessageContentView.scrollTo(0, 0);
}
updateDecryptLayout();
mMessageView.loadBodyFromText(mAccount.getCryptoProvider(), mPgpData, mMessage, emailText, contentType);
}
});
// If the message contains external pictures and the "Show pictures"
// button wasn't already pressed, see if the user's preferences has us
// showing them anyway.
if (Utility.hasExternalImages(text) && !mShowPictures) {
if (Utility.hasExternalImages(text) && !mMessageView.showPictures()) {
if ((account.getShowPictures() == Account.ShowPictures.ALWAYS) ||
((account.getShowPictures() == Account.ShowPictures.ONLY_FROM_CONTACTS) &&
mContacts.isInContacts(message.getFrom()[0].getAddress()))) {
onShowPictures();
setLoadPictures(true);
} else {
mHandler.showShowPictures(true);
mMessageView.showShowPicturesSection(true);
}
}
} else {
mHandler.post(new Runnable() {
public void run() {
mMessageContentView.loadUrl("file:///android_asset/empty.html");
updateDecryptLayout();
mMessageView.loadBodyFromUrl("file:///android_asset/empty.html");
}
});
}
renderAttachments(mMessage, 0);
mMessageView.renderAttachments(mMessage, 0, mMessage, mAccount, mController, mListener);
} catch (Exception e) {
if (Config.LOGV) {
Log.v(K9.LOG_TAG, "loadMessageForViewBodyAvailable", e);
@ -1260,53 +1120,31 @@ public class MessageView extends K9Activity implements OnClickListener {
}
}
private void renderAttachments(Part part, int depth) throws MessagingException {
if (part.getBody() instanceof Multipart) {
Multipart mp = (Multipart) part.getBody();
for (int i = 0; i < mp.getCount(); i++) {
renderAttachments(mp.getBodyPart(i), depth + 1);
}
} else if (part instanceof LocalAttachmentBodyPart) {
String contentDisposition = MimeUtility.unfoldAndDecode(part.getDisposition());
// Inline parts with a content-id are almost certainly components of an HTML message
// not attachments. Don't show attachment download buttons for them.
if (contentDisposition != null &&
MimeUtility.getHeaderParameter(contentDisposition, null).matches("^(?i:inline)")
&& part.getHeader("Content-ID") != null) {
return;
}
renderPartAsAttachment(part);
}
}
private void renderPartAsAttachment(Part part) throws MessagingException {
LayoutInflater inflater = getLayoutInflater();
AttachmentView view = (AttachmentView)inflater.inflate(R.layout.message_view_attachment, null);
if (view.populateFromPart(part, mMessage, mAccount, mController, mListener)) {
mHandler.addAttachment(view);
}
return;
}
class Listener extends MessagingListener {
@Override
public void loadMessageForViewHeadersAvailable(Account account, String folder, String uid,
public void loadMessageForViewHeadersAvailable(final Account account, String folder, String uid,
final Message message) {
if (!mMessageReference.uid.equals(uid) || !mMessageReference.folderName.equals(folder)
|| !mMessageReference.accountUuid.equals(account.getUuid())) {
return;
}
MessageView.this.mMessage = message;
if (!message.isSet(Flag.X_DOWNLOADED_FULL)
&& !message.isSet(Flag.X_DOWNLOADED_PARTIAL)) {
mHandler.post(new Runnable() {
public void run() {
mMessageContentView.loadUrl("file:///android_asset/downloading.html");
updateDecryptLayout();
runOnUiThread(
new Runnable() {
public void run() {
if (!message.isSet(Flag.X_DOWNLOADED_FULL) && !message.isSet(Flag.X_DOWNLOADED_PARTIAL)) {
mMessageView.loadBodyFromUrl("file:///android_asset/downloading.html");
}
});
}
mHandler.setHeaders(message);
mMessageView.setHeaders(message, account);
mMessageView.setOnFlagListener(new OnClickListener() {
@Override
public void onClick(View v) {
onFlag();
}
});
}
});
}
@Override
@ -1339,8 +1177,7 @@ public class MessageView extends K9Activity implements OnClickListener {
}
if ((MessageView.this.mMessage == null) ||
!MessageView.this.mMessage.isSet(Flag.X_DOWNLOADED_PARTIAL)) {
mMessageContentView.loadUrl("file:///android_asset/empty.html");
updateDecryptLayout();
mMessageView.loadBodyFromUrl("file:///android_asset/empty.html");
}
}
});
@ -1348,7 +1185,7 @@ public class MessageView extends K9Activity implements OnClickListener {
@Override
public void loadMessageForViewFinished(Account account, String folder, String uid,
Message message) {
final Message message) {
if (!mMessageReference.uid.equals(uid) || !mMessageReference.folderName.equals(folder)
|| !mMessageReference.accountUuid.equals(account.getUuid())) {
return;
@ -1356,6 +1193,7 @@ public class MessageView extends K9Activity implements OnClickListener {
mHandler.post(new Runnable() {
public void run() {
setProgressBarIndeterminateVisibility(false);
mMessageView.setShowDownloadButton(message);
}
});
}
@ -1368,7 +1206,6 @@ public class MessageView extends K9Activity implements OnClickListener {
}
mHandler.post(new Runnable() {
public void run() {
updateDecryptLayout();
setProgressBarIndeterminateVisibility(true);
}
});
@ -1380,7 +1217,7 @@ public class MessageView extends K9Activity implements OnClickListener {
if (mMessage != message) {
return;
}
mHandler.setAttachmentsEnabled(false);
mMessageView.setAttachmentsEnabled(false);
mHandler.progress(true);
if (requiresDownload) {
mHandler.fetchingAttachment();
@ -1388,12 +1225,11 @@ public class MessageView extends K9Activity implements OnClickListener {
}
@Override
public void loadAttachmentFinished(Account account, Message message,
Part part, Object tag) {
public void loadAttachmentFinished(Account account, Message message, Part part, Object tag) {
if (mMessage != message) {
return;
}
mHandler.setAttachmentsEnabled(true);
mMessageView.setAttachmentsEnabled(true);
mHandler.progress(false);
Object[] params = (Object[]) tag;
boolean download = (Boolean) params[0];
@ -1412,93 +1248,22 @@ public class MessageView extends K9Activity implements OnClickListener {
if (mMessage != message) {
return;
}
mHandler.setAttachmentsEnabled(true);
mMessageView.setAttachmentsEnabled(true);
mHandler.progress(false);
mHandler.networkError();
}
}
private void initializeCrypto(PgpData data) {
if (data == null) {
if (mAccount == null) {
mAccount = Preferences.getPreferences(this).getAccount(mMessageReference.accountUuid);
}
mPgpData = new PgpData();
} else {
mPgpData = data;
}
public PgpData getPgpData() {
return mPgpData;
}
/**
* Fill the decrypt layout with signature data, if known, make controls visible, if
* they should be visible.
*/
public void updateDecryptLayout() {
if (mPgpData.getSignatureKeyId() != 0) {
mCryptoSignatureUserIdRest.setText(
getString(R.string.key_id, Long.toHexString(mPgpData.getSignatureKeyId() & 0xffffffffL)));
String userId = mPgpData.getSignatureUserId();
if (userId == null) {
userId = getString(R.string.unknown_crypto_signature_user_id);
}
String chunks[] = userId.split(" <", 2);
String name = chunks[0];
if (chunks.length > 1) {
mCryptoSignatureUserIdRest.setText("<" + chunks[1]);
}
mCryptoSignatureUserId.setText(name);
if (mPgpData.getSignatureSuccess()) {
mCryptoSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
} else if (mPgpData.getSignatureUnknown()) {
mCryptoSignatureStatusImage.setImageResource(R.drawable.overlay_error);
} else {
mCryptoSignatureStatusImage.setImageResource(R.drawable.overlay_error);
}
mCryptoSignatureLayout.setVisibility(View.VISIBLE);
mDecryptLayout.setVisibility(View.VISIBLE);
} else {
mCryptoSignatureLayout.setVisibility(View.INVISIBLE);
}
if (false || ((mMessage == null) && (mPgpData.getDecryptedData() == null))) {
mDecryptLayout.setVisibility(View.GONE);
return;
}
if (mPgpData.getDecryptedData() != null) {
if (mPgpData.getSignatureKeyId() == 0) {
mDecryptLayout.setVisibility(View.GONE);
} else {
// no need to show this after decryption/verification
mDecryptButton.setVisibility(View.GONE);
}
return;
}
mDecryptButton.setVisibility(View.VISIBLE);
CryptoProvider crypto = mAccount.getCryptoProvider();
if (crypto.isEncrypted(mMessage)) {
mDecryptButton.setText(R.string.btn_decrypt);
mDecryptLayout.setVisibility(View.VISIBLE);
} else if (crypto.isSigned(mMessage)) {
mDecryptButton.setText(R.string.btn_verify);
mDecryptLayout.setVisibility(View.VISIBLE);
} else {
mDecryptLayout.setVisibility(View.GONE);
try {
// check for PGP/MIME encryption
Part pgp = MimeUtility.findFirstPartByMimeType(mMessage, "application/pgp-encrypted");
if (pgp != null) {
Toast.makeText(this, R.string.pgp_mime_unsupported, Toast.LENGTH_LONG).show();
}
} catch (MessagingException e) {
// nothing to do...
}
}
}
public void onDecryptDone() {
// This REALLY should be in MessageCryptoView
public void onDecryptDone(PgpData pgpData) {
// TODO: this might not be enough if the orientation was changed while in APG,
// sometimes shows the original encrypted content
mMessageContentView.loadDataWithBaseURL("email://", mPgpData.getDecryptedData(), "text/plain", "utf-8", null);
updateDecryptLayout();
mMessageView.loadBodyFromText(mAccount.getCryptoProvider(), mPgpData, mMessage, mPgpData.getDecryptedData(), "text/plain");
}
}

View file

@ -46,6 +46,7 @@ import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Folder;
import com.fsck.k9.mail.Folder.FolderType;
import com.fsck.k9.mail.Folder.OpenMode;
import com.fsck.k9.mail.Message.RecipientType;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Part;
@ -1004,13 +1005,19 @@ public class MessagingController implements Runnable {
* Remove any messages that are in the local store but no longer on the remote store or are too old
*/
if (account.syncRemoteDeletions()) {
ArrayList<Message> destroyMessages = new ArrayList<Message>();
for (Message localMessage : localMessages) {
if (remoteUidMap.get(localMessage.getUid()) == null) {
localMessage.destroy();
destroyMessages.add(localMessage);
}
}
for (MessagingListener l : getListeners(listener)) {
l.synchronizeMailboxRemovedMessage(account, folder, localMessage);
}
localFolder.destroyMessages(destroyMessages.toArray(EMPTY_MESSAGE_ARRAY));
for (Message destroyMessage : destroyMessages) {
for (MessagingListener l : getListeners(listener)) {
l.synchronizeMailboxRemovedMessage(account, folder, destroyMessage);
}
}
}
@ -3469,7 +3476,22 @@ public class MessagingController implements Runnable {
if (quotedText != null) {
msg.putExtra(Intent.EXTRA_TEXT, quotedText);
}
msg.putExtra(Intent.EXTRA_SUBJECT, "Fwd: " + message.getSubject());
msg.putExtra(Intent.EXTRA_SUBJECT, message.getSubject());
Address[] to = message.getRecipients(RecipientType.TO);
String[] recipientsTo = new String[to.length];
for (int i = 0; i < to.length; i++) {
recipientsTo[i] = to[i].toString();
}
msg.putExtra(Intent.EXTRA_EMAIL, recipientsTo);
Address[] cc = message.getRecipients(RecipientType.CC);
String[] recipientsCc = new String[cc.length];
for (int i = 0; i < cc.length; i++) {
recipientsCc[i] = cc[i].toString();
}
msg.putExtra(Intent.EXTRA_CC, recipientsCc);
msg.setType("text/plain");
context.startActivity(Intent.createChooser(msg, context.getString(R.string.send_alternate_chooser_title)));
} catch (MessagingException me) {

View file

@ -327,7 +327,7 @@ public class Apg extends CryptoProvider {
pgpData.setSignatureUnknown(data.getBooleanExtra(Apg.EXTRA_SIGNATURE_UNKNOWN, false));
pgpData.setDecryptedData(data.getStringExtra(Apg.EXTRA_DECRYPTED_MESSAGE));
((MessageView) activity).onDecryptDone();
((MessageView) activity).onDecryptDone(pgpData);
break;
@ -386,9 +386,7 @@ public class Apg extends CryptoProvider {
activity.startActivityForResult(intent, Apg.DECRYPT_MESSAGE);
return true;
} catch (ActivityNotFoundException e) {
Toast.makeText(activity,
R.string.error_activity_not_found,
Toast.LENGTH_SHORT).show();
Toast.makeText(activity, R.string.error_activity_not_found, Toast.LENGTH_SHORT).show();
return false;
}
}

View file

@ -2020,6 +2020,27 @@ public class LocalStore extends Store implements Serializable {
appendMessages(messages, false);
}
public void destroyMessages(final Message[] messages) throws MessagingException {
try {
database.execute(true, new DbCallback<Void>() {
@Override
public Void doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException {
for (Message message : messages) {
try {
message.destroy();
} catch (MessagingException e) {
throw new WrappedException(e);
}
}
return null;
}
});
} catch (MessagingException e) {
throw new WrappedException(e);
}
}
/**
* The method differs slightly from the contract; If an incoming message already has a uid
* assigned and it matches the uid of an existing message then this message will replace the

View file

@ -27,10 +27,8 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import org.apache.commons.codec.binary.Hex;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.*;
public class SmtpTransport extends Transport {
public static final int CONNECTION_SECURITY_NONE = 0;
@ -284,7 +282,7 @@ public class SmtpTransport extends Transport {
addressesOfCharset.add(addressString);
}
for (HashMap.Entry<String, ArrayList<String>> charsetAddressesMapEntry :
for (Map.Entry<String, ArrayList<String>> charsetAddressesMapEntry :
charsetAddressesMap.entrySet()) {
String charset = charsetAddressesMapEntry.getKey();
ArrayList<String> addressesOfCharset = charsetAddressesMapEntry.getValue();

View file

@ -0,0 +1,143 @@
package com.fsck.k9.view;
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.*;
import com.fsck.k9.K9;
import com.fsck.k9.R;
import com.fsck.k9.crypto.CryptoProvider;
import com.fsck.k9.crypto.PgpData;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Part;
import com.fsck.k9.mail.internet.MimeUtility;
public class MessageCryptoView extends LinearLayout {
private Context mContext;
private Activity mActivity;
private Button mDecryptButton;
private LinearLayout mCryptoSignatureLayout = null;
private ImageView mCryptoSignatureStatusImage = null;
private TextView mCryptoSignatureUserId = null;
private TextView mCryptoSignatureUserIdRest = null;
public MessageCryptoView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
public void setupChildViews() {
mCryptoSignatureLayout = (LinearLayout) findViewById(R.id.crypto_signature);
mCryptoSignatureStatusImage = (ImageView) findViewById(R.id.ic_crypto_signature_status);
mCryptoSignatureUserId = (TextView) findViewById(R.id.userId);
mCryptoSignatureUserIdRest = (TextView) findViewById(R.id.userIdRest);
mCryptoSignatureLayout.setVisibility(View.INVISIBLE);
mDecryptButton = (Button) findViewById(R.id.btn_decrypt);
}
public void setActivity(Activity activity) {
mActivity = activity;
}
public void hide () {
this.setVisibility(View.GONE);
}
/**
* Fill the decrypt layout with signature data, if known, make controls visible, if
* they should be visible.
*/
public void updateLayout(final CryptoProvider cryptoProvider, final PgpData pgpData, final Message message) {
if (pgpData.getSignatureKeyId() != 0) {
mCryptoSignatureUserIdRest.setText(
mContext.getString(R.string.key_id, Long.toHexString(pgpData.getSignatureKeyId() & 0xffffffffL)));
String userId = pgpData.getSignatureUserId();
if (userId == null) {
userId = mContext.getString(R.string.unknown_crypto_signature_user_id);
}
String chunks[] = userId.split(" <", 2);
String name = chunks[0];
if (chunks.length > 1) {
mCryptoSignatureUserIdRest.setText("<" + chunks[1]);
}
mCryptoSignatureUserId.setText(name);
if (pgpData.getSignatureSuccess()) {
mCryptoSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
} else if (pgpData.getSignatureUnknown()) {
mCryptoSignatureStatusImage.setImageResource(R.drawable.overlay_error);
} else {
mCryptoSignatureStatusImage.setImageResource(R.drawable.overlay_error);
}
mCryptoSignatureLayout.setVisibility(View.VISIBLE);
this.setVisibility(View.VISIBLE);
} else {
mCryptoSignatureLayout.setVisibility(View.INVISIBLE);
}
if ((message == null) && (pgpData.getDecryptedData() == null)) {
this.setVisibility(View.GONE);
return;
}
if (pgpData.getDecryptedData() != null) {
if (pgpData.getSignatureKeyId() == 0) {
this.setVisibility(View.GONE);
} else {
// no need to show this after decryption/verification
mDecryptButton.setVisibility(View.GONE);
}
return;
}
mDecryptButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
try {
String data = null;
Part part = MimeUtility.findFirstPartByMimeType(message, "text/plain");
if (part == null) {
part = MimeUtility.findFirstPartByMimeType(message, "text/html");
}
if (part != null) {
data = MimeUtility.getTextFromPart(part);
}
cryptoProvider.decrypt(mActivity, data, pgpData);
} catch (MessagingException me) {
Log.e(K9.LOG_TAG, "Unable to decrypt email.", me);
}
}
});
mDecryptButton.setVisibility(View.VISIBLE);
if (cryptoProvider.isEncrypted(message)) {
mDecryptButton.setText(R.string.btn_decrypt);
this.setVisibility(View.VISIBLE);
} else if (cryptoProvider.isSigned(message)) {
mDecryptButton.setText(R.string.btn_verify);
this.setVisibility(View.VISIBLE);
} else {
this.setVisibility(View.GONE);
try {
// check for PGP/MIME encryption
Part pgp = MimeUtility.findFirstPartByMimeType(message, "application/pgp-encrypted");
if (pgp != null) {
Toast.makeText(mContext, R.string.pgp_mime_unsupported, Toast.LENGTH_LONG).show();
}
} catch (MessagingException e) {
// nothing to do...
}
}
}
}

View file

@ -0,0 +1,211 @@
package com.fsck.k9.view;
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
import com.fsck.k9.R;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.crypto.CryptoProvider;
import com.fsck.k9.crypto.PgpData;
import com.fsck.k9.mail.*;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.store.LocalStore;
/**
*/
public class SingleMessageView extends LinearLayout {
private boolean mScreenReaderEnabled;
private MessageCryptoView mCryptoView;
private MessageWebView mMessageContentView;
private AccessibleWebView mAccessibleMessageContentView;
private MessageHeader mHeaderContainer;
private LinearLayout mAttachments;
private View mShowPicturesSection;
private boolean mShowPictures;
private Button mDownloadRemainder;
private LayoutInflater mInflater;
public void initialize(Activity activity, Boolean isScreenReaderActive) {
mMessageContentView = (MessageWebView) findViewById(R.id.message_content);
mAccessibleMessageContentView = (AccessibleWebView) findViewById(R.id.accessible_message_content);
mAttachments = (LinearLayout) findViewById(R.id.attachments);
mHeaderContainer = (MessageHeader) findViewById(R.id.header_container);
mCryptoView = (MessageCryptoView) findViewById(R.id.layout_decrypt);
mCryptoView.setActivity(activity);
mCryptoView.setupChildViews();
mShowPicturesSection = findViewById(R.id.show_pictures_section);
mShowPictures = false;
mInflater = activity.getLayoutInflater();
mDownloadRemainder = (Button) findViewById(R.id.download_remainder);
mMessageContentView.configure();
mAttachments.setVisibility(View.GONE);
if (isScreenReaderActive) {
mAccessibleMessageContentView.setVisibility(View.VISIBLE);
mMessageContentView.setVisibility(View.GONE);
} else {
mAccessibleMessageContentView.setVisibility(View.GONE);
mMessageContentView.setVisibility(View.VISIBLE);
}
mScreenReaderEnabled = isScreenReaderActive;
}
public SingleMessageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean showPictures() {
return mShowPictures;
}
public void setShowPictures(Boolean show) {
mShowPictures = show;
}
public void blockNetworkData(Boolean block) {
mMessageContentView.blockNetworkData(block);
}
public Button downloadRemainderButton() {
return mDownloadRemainder;
}
public void showShowPicturesSection(boolean show) {
mShowPicturesSection.setVisibility(show ? View.VISIBLE : View.GONE);
}
public void setHeaders(final Message message, Account account) {
try {
mHeaderContainer.populate(message, account);
} catch (Exception me) {
Log.e(K9.LOG_TAG, "setHeaders - error", me);
}
}
public void setShowDownloadButton(Message message) {
if (message.isSet(Flag.X_DOWNLOADED_FULL)) {
mDownloadRemainder.setVisibility(View.GONE);
} else {
mDownloadRemainder.setEnabled(true);
mDownloadRemainder.setVisibility(View.VISIBLE);
}
}
public void setOnFlagListener(OnClickListener listener) {
mHeaderContainer.setOnFlagListener(listener);
}
public void showAllHeaders() {
mHeaderContainer.onShowAdditionalHeaders();
}
public boolean additionalHeadersVisible() {
return mHeaderContainer.additionalHeadersVisible();
}
public void loadBodyFromUrl(String url) {
mMessageContentView.loadUrl(url);
mCryptoView.hide();
}
public void loadBodyFromText(CryptoProvider cryptoProvider, PgpData pgpData, Message message, String emailText, String contentType) {
if (mScreenReaderEnabled) {
mAccessibleMessageContentView.loadDataWithBaseURL("http://", emailText, contentType, "utf-8", null);
} else {
mMessageContentView.loadDataWithBaseURL("http://", emailText, contentType, "utf-8", null);
mMessageContentView.scrollTo(0, 0);
}
updateCryptoLayout(cryptoProvider, pgpData, message);
}
public void updateCryptoLayout(CryptoProvider cp, PgpData pgpData, Message message) {
mCryptoView.updateLayout(cp, pgpData, message);
}
public void setAttachmentsEnabled(boolean enabled) {
for (int i = 0, count = mAttachments.getChildCount(); i < count; i++) {
AttachmentView attachment = (AttachmentView) mAttachments.getChildAt(i);
attachment.viewButton.setEnabled(enabled);
attachment.downloadButton.setEnabled(enabled);
}
}
public void removeAllAttachments() {
for (int i = 0, count = mAttachments.getChildCount(); i < count; i++) {
mAttachments.removeView(mAttachments.getChildAt(i));
}
}
public void renderAttachments(Part part, int depth,
Message message, Account account, MessagingController controller, MessagingListener listener) throws MessagingException {
if (part.getBody() instanceof Multipart) {
Multipart mp = (Multipart) part.getBody();
for (int i = 0; i < mp.getCount(); i++) {
renderAttachments(mp.getBodyPart(i), depth + 1, message, account, controller, listener);
}
} else if (part instanceof LocalStore.LocalAttachmentBodyPart) {
String contentDisposition = MimeUtility.unfoldAndDecode(part.getDisposition());
// Inline parts with a content-id are almost certainly components of an HTML message
// not attachments. Don't show attachment download buttons for them.
if (contentDisposition != null &&
MimeUtility.getHeaderParameter(contentDisposition, null).matches("^(?i:inline)")
&& part.getHeader("Content-ID") != null) {
return;
}
AttachmentView view = (AttachmentView)mInflater.inflate(R.layout.message_view_attachment, null);
if (view.populateFromPart(part, message, account, controller, listener)) {
addAttachment(view);
}
}
}
public void addAttachment(View attachmentView) {
mAttachments.addView(attachmentView);
mAttachments.setVisibility(View.VISIBLE);
}
public void zoom(KeyEvent event) {
if (mScreenReaderEnabled) {
mAccessibleMessageContentView.zoomIn();
} else {
if (event.isShiftPressed()) {
mMessageContentView.zoomIn();
} else {
mMessageContentView.zoomOut();
}
}
}
public void beginSelectingText() {
mMessageContentView.emulateShiftHeld();
}
public void resetView() {
mMessageContentView.scrollTo(0, 0);
mHeaderContainer.setVisibility(View.GONE);
mMessageContentView.clearView();
mAttachments.removeAllViews();
}
}