MessageView performance improvlements by debauchedsloth++ (This includes all changes from Issue 285's MessageView.java patch)

This commit is contained in:
Jesse Vincent 2009-05-03 04:36:33 +00:00
parent 4b444b2bcf
commit 2dda469255
1 changed files with 139 additions and 129 deletions

View File

@ -29,6 +29,7 @@ import android.os.Handler;
import android.os.Process; import android.os.Process;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.util.Regex; import android.text.util.Regex;
import android.text.util.Linkify; import android.text.util.Linkify;
import android.util.Config; import android.util.Config;
@ -43,6 +44,7 @@ import android.view.View.OnClickListener;
import android.webkit.CacheManager; import android.webkit.CacheManager;
import android.webkit.UrlInterceptHandler; import android.webkit.UrlInterceptHandler;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.CacheManager.CacheResult; import android.webkit.CacheManager.CacheResult;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
@ -71,6 +73,9 @@ import com.android.email.mail.store.LocalStore.LocalAttachmentBody;
import com.android.email.mail.store.LocalStore.LocalAttachmentBodyPart; import com.android.email.mail.store.LocalStore.LocalAttachmentBodyPart;
import com.android.email.mail.store.LocalStore.LocalMessage; import com.android.email.mail.store.LocalStore.LocalMessage;
import com.android.email.provider.AttachmentProvider; import com.android.email.provider.AttachmentProvider;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MessageView extends Activity public class MessageView extends Activity
implements UrlInterceptHandler, OnClickListener { implements UrlInterceptHandler, OnClickListener {
@ -79,6 +84,7 @@ public class MessageView extends Activity
private static final String EXTRA_MESSAGE = "com.android.email.MessageView_message"; private static final String EXTRA_MESSAGE = "com.android.email.MessageView_message";
private static final String EXTRA_FOLDER_UIDS = "com.android.email.MessageView_folderUids"; private static final String EXTRA_FOLDER_UIDS = "com.android.email.MessageView_folderUids";
private static final String EXTRA_NEXT = "com.android.email.MessageView_next"; private static final String EXTRA_NEXT = "com.android.email.MessageView_next";
private static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, 1, 120000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
private static final int ACTIVITY_CHOOSE_FOLDER_MOVE = 1; private static final int ACTIVITY_CHOOSE_FOLDER_MOVE = 1;
@ -93,6 +99,10 @@ public class MessageView extends Activity
private LinearLayout mAttachments; private LinearLayout mAttachments;
private View mAttachmentIcon; private View mAttachmentIcon;
private View mShowPicturesSection; private View mShowPicturesSection;
View next;
View next_scrolling;
View previous;
View previous_scrolling;
private Account mAccount; private Account mAccount;
private String mFolder; private String mFolder;
@ -123,7 +133,7 @@ public class MessageView extends Activity
dateFormat = new java.text.SimpleDateFormat(Email.BACKUP_DATE_FORMAT); dateFormat = new java.text.SimpleDateFormat(Email.BACKUP_DATE_FORMAT);
} }
} }
return dateFormat; return dateFormat;
} }
private DateFormat getTimeFormat() private DateFormat getTimeFormat()
{ {
@ -134,12 +144,12 @@ public class MessageView extends Activity
boolean b24 = !(timeFormatS == null || timeFormatS.equals("12")); boolean b24 = !(timeFormatS == null || timeFormatS.equals("12"));
timeFormat = new java.text.SimpleDateFormat(b24 ? Email.TIME_FORMAT_24 : Email.TIME_FORMAT_12); timeFormat = new java.text.SimpleDateFormat(b24 ? Email.TIME_FORMAT_24 : Email.TIME_FORMAT_12);
} }
return timeFormat; return timeFormat;
} }
private void clearFormats() private void clearFormats()
{ {
dateFormat = null; dateFormat = null;
timeFormat = null; timeFormat = null;
} }
private Listener mListener = new Listener(); private Listener mListener = new Listener();
@ -171,10 +181,10 @@ public class MessageView extends Activity
} }
return true; } return true; }
case KeyEvent.KEYCODE_H: { case KeyEvent.KEYCODE_H: {
Toast toast = Toast.makeText(this, R.string.message_help_key, Toast.LENGTH_LONG); Toast toast = Toast.makeText(this, R.string.message_help_key, Toast.LENGTH_LONG);
toast.show(); toast.show();
return true; } return true; }
} }
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
} }
@ -372,6 +382,7 @@ public class MessageView extends Activity
mSubjectView = (TextView)findViewById(R.id.subject); mSubjectView = (TextView)findViewById(R.id.subject);
mDateView = (TextView)findViewById(R.id.date); mDateView = (TextView)findViewById(R.id.date);
mMessageContentView = (WebView)findViewById(R.id.message_content); mMessageContentView = (WebView)findViewById(R.id.message_content);
mMessageContentView.setWebViewClient(new MessageWebViewClient());
mAttachments = (LinearLayout)findViewById(R.id.attachments); mAttachments = (LinearLayout)findViewById(R.id.attachments);
mAttachmentIcon = findViewById(R.id.attachment); mAttachmentIcon = findViewById(R.id.attachment);
mShowPicturesSection = findViewById(R.id.show_pictures_section); mShowPicturesSection = findViewById(R.id.show_pictures_section);
@ -409,28 +420,17 @@ public class MessageView extends Activity
mMessageUid = intent.getStringExtra(EXTRA_MESSAGE); mMessageUid = intent.getStringExtra(EXTRA_MESSAGE);
mFolderUids = intent.getStringArrayListExtra(EXTRA_FOLDER_UIDS); mFolderUids = intent.getStringArrayListExtra(EXTRA_FOLDER_UIDS);
View next = findViewById(R.id.next); next = findViewById(R.id.next);
View previous = findViewById(R.id.previous); previous = findViewById(R.id.previous);
findSurroundingMessagesUid();
setOnClickListener(R.id.next); setOnClickListener(R.id.next);
setOnClickListener(R.id.previous); setOnClickListener(R.id.previous);
next.setEnabled(mNextMessageUid != null ); next_scrolling = findViewById(R.id.next_scrolling);
previous.setEnabled(mPreviousMessageUid != null);
View next_scrolling = findViewById(R.id.next_scrolling);
if (next_scrolling != null) {
next_scrolling.setEnabled(mNextMessageUid != null );
}
View previous_scrolling = findViewById(R.id.previous_scrolling); previous_scrolling = findViewById(R.id.previous_scrolling);
if (previous_scrolling != null) {
previous_scrolling.setEnabled(mPreviousMessageUid != null);
}
boolean goNext = intent.getBooleanExtra(EXTRA_NEXT, false); boolean goNext = intent.getBooleanExtra(EXTRA_NEXT, false);
if (goNext) { if (goNext) {
@ -439,6 +439,7 @@ public class MessageView extends Activity
Account.HideButtons hideButtons = mAccount.getHideMessageViewButtons(); Account.HideButtons hideButtons = mAccount.getHideMessageViewButtons();
MessagingController.getInstance(getApplication()).addListener(mListener);
if (Account.HideButtons.ALWAYS == hideButtons) if (Account.HideButtons.ALWAYS == hideButtons)
{ {
hideButtons(); hideButtons();
@ -459,22 +460,37 @@ public class MessageView extends Activity
showButtons(); showButtons();
} }
} }
displayMessage(mMessageUid);
MessagingController.getInstance(getApplication()).addListener(mListener); }
new Thread() {
Thread loaderThread = new Thread() {
public void run() { public void run() {
// TODO this is a spot that should be eventually handled by a MessagingController // TODO this is a spot that should be eventually handled by a MessagingController
// thread pool. We want it in a thread but it can't be blocked by the normal // thread pool. We want it in a thread but it can't be blocked by the normal
// synchronization stuff in MC. // synchronization stuff in MC.
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
MessagingController.getInstance(getApplication()).loadMessageForView( MessagingController.getInstance(getApplication()).loadMessageForView(
mAccount, mAccount,
mFolder, mFolder,
mMessageUid, mMessageUid,
null); null);
} }
}.start(); };
private void displayMessage(String uid)
{
mMessageUid = uid;
mAttachments.removeAllViews();
findSurroundingMessagesUid();
next.setEnabled(mNextMessageUid != null );
previous.setEnabled(mPreviousMessageUid != null);
if (next_scrolling != null)
next_scrolling.setEnabled(mNextMessageUid != null );
if (previous_scrolling != null)
previous_scrolling.setEnabled(mPreviousMessageUid != null);
threadPool.execute(loaderThread);
} }
private void showButtons() private void showButtons()
{ {
View buttons = findViewById(R.id.scrolling_buttons); View buttons = findViewById(R.id.scrolling_buttons);
@ -501,19 +517,14 @@ public class MessageView extends Activity
} }
private void findSurroundingMessagesUid() { private void findSurroundingMessagesUid() {
for (int i = 0, count = mFolderUids.size(); i < count; i++) { mNextMessageUid = mPreviousMessageUid = null;
String messageUid = mFolderUids.get(i); int i = mFolderUids.indexOf(mMessageUid);
if (messageUid.equals(mMessageUid)) { if(i < 0)
if (i != 0) { return;
mNextMessageUid = mFolderUids.get(i - 1); if(i != 0)
} mNextMessageUid = mFolderUids.get(i - 1);
if(i != (mFolderUids.size() - 1))
if (i != count - 1) { mPreviousMessageUid = mFolderUids.get(i + 1);
mPreviousMessageUid = mFolderUids.get(i + 1);
}
break;
}
}
} }
public void onResume() { public void onResume() {
@ -533,10 +544,11 @@ public class MessageView extends Activity
String folderForDelete = mFolder; String folderForDelete = mFolder;
Account accountForDelete = mAccount; Account accountForDelete = mAccount;
findSurroundingMessagesUid();
// Remove this message's Uid locally // Remove this message's Uid locally
mFolderUids.remove(messageToDelete.getUid()); mFolderUids.remove(messageToDelete.getUid());
findSurroundingMessagesUid();
MessagingController.getInstance(getApplication()).deleteMessage( MessagingController.getInstance(getApplication()).deleteMessage(
accountForDelete, accountForDelete,
@ -551,8 +563,6 @@ public class MessageView extends Activity
} else { } else {
finish(); finish();
} }
} }
} }
@ -667,35 +677,27 @@ public class MessageView extends Activity
private void onSendAlternate() { private void onSendAlternate() {
if (mMessage != null) { if (mMessage != null) {
MessagingController.getInstance(getApplication()).sendAlternate(this, mAccount, mMessage); MessagingController.getInstance(getApplication()).sendAlternate(this, mAccount, mMessage);
} }
} }
private void onNext() { private void onNext() {
if (mNextMessageUid == null) if (mNextMessageUid == null) {
{ Toast.makeText(this, getString(R.string.end_of_folder), Toast.LENGTH_SHORT).show();
Toast.makeText(this, return;
getString(R.string.end_of_folder), }
Toast.LENGTH_SHORT).show(); displayMessage(mNextMessageUid);
return; next.requestFocus();
}
Bundle extras = new Bundle(1);
extras.putBoolean(EXTRA_NEXT, true);
MessageView.actionView(this, mAccount, mFolder, mNextMessageUid, mFolderUids, extras);
finish();
} }
private void onPrevious() { private void onPrevious() {
if (mPreviousMessageUid == null) if (mPreviousMessageUid == null) {
{ Toast.makeText(this, getString(R.string.end_of_folder), Toast.LENGTH_SHORT).show();
Toast.makeText(this, return;
getString(R.string.end_of_folder), }
Toast.LENGTH_SHORT).show(); displayMessage(mPreviousMessageUid);
return; previous.requestFocus();
}
MessageView.actionView(this, mAccount, mFolder, mPreviousMessageUid, mFolderUids);
finish();
} }
private void onMarkAsUnread() { private void onMarkAsUnread() {
@ -1054,72 +1056,68 @@ public class MessageView extends Activity
@Override @Override
public void loadMessageForViewBodyAvailable(Account account, String folder, String uid, public void loadMessageForViewBodyAvailable(Account account, String folder, String uid,
Message message) { Message message) {
SpannableString markup; Spannable markup;
MessageView.this.mMessage = message; MessageView.this.mMessage = message;
try { try {
Part part = MimeUtility.findFirstPartByMimeType(mMessage, "text/html"); Part part = MimeUtility.findFirstPartByMimeType(mMessage, "text/html");
if (part == null) { if (part == null) {
part = MimeUtility.findFirstPartByMimeType(mMessage, "text/plain"); part = MimeUtility.findFirstPartByMimeType(mMessage, "text/plain");
}
if (part != null) {
String text = MimeUtility.getTextFromPart(part);
if (part.getMimeType().equalsIgnoreCase("text/html")) {
text = text.replaceAll("cid:", "http://cid/");
} else {
Matcher m = Regex.WEB_URL_PATTERN.matcher(text);
StringBuffer sb = new StringBuffer();
/*
* Convert plain text to HTML by replacing
* \r?\n with <br> and adding a html/body wrapper as well as escaping & < >
*/
text = text.replaceAll("&", "&amp;");
text = text.replaceAll("<", "&lt;");
text = text.replaceAll(">", "&gt;");
text = text.replaceAll("\r?\n", "<br>");
while (m.find()) {
int start = m.start();
if (start == 0 || (start != 0 && text.charAt(start - 1) != '@')) {
m.appendReplacement(sb, "<a href=\"$0\">$0</a>");
}
else {
m.appendReplacement(sb, "$0");
}
}
m.appendTail(sb);
text = "<html><body>" + text + "</body></html>";
}
/*
* TODO this should be smarter, change to regex for img, but consider how to
* get background images and a million other things that HTML allows.
*/
if (text.contains("<img")) {
mHandler.showShowPictures(true);
}
markup = new SpannableString(text);
Linkify.addLinks(markup, Linkify.ALL);
mMessageContentView.loadDataWithBaseURL("email://", markup.toString(), "text/html",
"utf-8", null);
}
else {
mMessageContentView.loadUrl("file:///android_asset/empty.html");
}
renderAttachments(mMessage, 0);
} }
if (part != null) {
String text = MimeUtility.getTextFromPart(part);
if (part.getMimeType().equalsIgnoreCase("text/html")) {
markup = new SpannableString(text.replaceAll("cid:", "http://cid/"));
Linkify.addLinks(markup, Linkify.ALL);
text = markup.toString();
} else {
if(text.length() != 0) {
/*
* Convert plain text to HTML by replacing
* \r?\n with <br> and adding a html/body wrapper.
*/
text = text.replaceAll("&", "&amp;");
text = text.replaceAll("<", "&lt;");
text = text.replaceAll(">", "&gt;");
text = text.replaceAll("\r?\n", "<br/>");
Matcher m = Regex.WEB_URL_PATTERN.matcher(text);
StringBuffer sb = new StringBuffer(text.length() + 512);
sb.append("<html><body>");
while (m.find()) {
int start = m.start();
if (start == 0 || (start != 0 && text.charAt(start - 1) != '@')) {
m.appendReplacement(sb, "<a href=\"$0\">$0</a>");
}
else {
m.appendReplacement(sb, "$0");
}
}
m.appendTail(sb);
sb.append("</body></html>");
markup = new SpannableStringBuilder(sb, 0, sb.length());
Linkify.addLinks(markup, Linkify.ALL);
text = markup.toString();
}
else
text = "<html><body></body></html>";
}
/*
* TODO this should be smarter, change to regex for img, but consider how to
* get background images and a million other things that HTML allows.
*/
mHandler.showShowPictures(text.contains("<img"));
mMessageContentView.loadDataWithBaseURL("email://", text, "text/html", "utf-8", null);
}
else
mMessageContentView.loadUrl("file:///android_asset/empty.html");
renderAttachments(mMessage, 0);
}
catch (Exception e) { catch (Exception e) {
if (Config.LOGV) { if (Config.LOGV) {
Log.v(Email.LOG_TAG, "loadMessageForViewBodyAvailable", e); Log.v(Email.LOG_TAG, "loadMessageForViewBodyAvailable", e);
}
} }
} }
}
@Override @Override
public void loadMessageForViewFailed(Account account, String folder, String uid, public void loadMessageForViewFailed(Account account, String folder, String uid,
final String message) { final String message) {
@ -1238,4 +1236,16 @@ public class MessageView extends Activity
} }
} }
} }
class MessageWebViewClient extends WebViewClient
{
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl)
{
Log.e(Email.LOG_TAG, "WebView: url '"+failingUrl+"' error "+description);
String error = String.format(getString(R.string.message_web_view_error).toString(), description);
Toast.makeText(MessageView.this, error, Toast.LENGTH_LONG).show();
}
}
} }