From 78684ccc795c0d5211dfc04a834cb452dccb1058 Mon Sep 17 00:00:00 2001 From: Marc Blank Date: Thu, 31 Mar 2011 13:29:23 -0700 Subject: [PATCH] Temporary search UI Change-Id: Ia138ca93f0b28fd0915aa79c965f752f7c08ee90 --- AndroidManifest.xml | 8 +- .../emailcommon/utility/TextUtilities.java | 2 +- .../ic_menu_search_holo_light.png | Bin 0 -> 858 bytes res/menu/message_list_xl_option.xml | 12 ++- res/values/strings.xml | 5 ++ res/xml/searchable.xml | 21 ++++++ src/com/android/email/Controller.java | 2 +- .../email/activity/MessageListFragment.java | 5 ++ .../email/activity/MessageListItem.java | 43 +++++++---- .../android/email/activity/MessageListXL.java | 70 ++++++++++++++++++ .../email/activity/MessagesAdapter.java | 15 +++- 11 files changed, 160 insertions(+), 23 deletions(-) create mode 100644 res/drawable-mdpi/ic_menu_search_holo_light.png create mode 100644 res/xml/searchable.xml diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 524062f34..835f28009 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -108,6 +108,7 @@ /> + + android:name=".activity.MessageListXL"> + + + + 0x00FFFF00) /*package*/ static final String HIGHLIGHT_COLOR_STRING = '#' + Integer.toHexString(HIGHLIGHT_COLOR_INT & 0x00FFFFFF); diff --git a/res/drawable-mdpi/ic_menu_search_holo_light.png b/res/drawable-mdpi/ic_menu_search_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..101eeae452a78a6e04c74b0acc164b6db1fb8c55 GIT binary patch literal 858 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(epwmK8Xr18D^?ZvQoBE=ZfFi(`n#@v~RYuMQ0rVgGRc-tW6?pWJwT3{8~R za;!Dyc)F^Q!;w`m$mB|+;7t_^3-385oR-X@SLz=rempZV>Pxe@N3%dZYt!U{2{SG& zIJo!u8@A^$_h0U-o_{`Y-N~EjbNB9heY|{a>5u)YK0#u0i+`#x9Q6=qm2?a{tD+@fdexKd_#F@XvD469Yw_e3fzi^jQOUVTp zul63(y=eCRYltrQ$phN!ejS}B8l*A%dG);VGqtwNTXk0Re!25y>)m@PK~f(BS@txu z@@P&~&KKQxFj{Tf-4z|CX1iaXe|KESC@=Z-6Q#1q6-)l_DgT+NG?VSZwFlF-nwd0; zdEXU`et$iTL1UJ~`Nzs&?1B00++uhCwQeH3U;e(C^LLTWtVy1| zB3HltI9U3A_uaDkkk_-fpR=2;T50KWI>&L^ox;QFcBZfOnKy6yeaUlkletcXh6&$q zvE#}wcrMQgE<4GzDdApW`k9?8i!O>k?(FF=4&sd4e%*W1YrS8x(lzPb3niD=-n%O? zS==kET+GYqZFn)86ZgfN{Bz&MZCT+zO?9RG@4%dur{lH;PYWrFcpaVS#BzCw>d!6b zc~qTk<1MvTp4u2TFYVrz%Zce{C02d7WhAxy^rC++o;8)0&G^{w{4XQyoEC$Xz{Se* zKW-mPvo^iEp-alfONHaDNsFqKd~~zht+NwUJ#*?z!%iQHu$;~?U+Aa!l^6RqaP4BB z2uyaWC9V-ADTyViR>?)FK#IZ0z|c_Fz);uFEX2^*%GA=zz(Ci)0!UtXcf$xpLvDUb zW?Cg~4GT9X^Z_+Uf@}!RPb(=;EJ|f?Ovz75Rq)JBOiv9;O-!jQJeg_(RK(!v>gTe~ HDWM4fpcZnl literal 0 HcmV?d00001 diff --git a/res/menu/message_list_xl_option.xml b/res/menu/message_list_xl_option.xml index 339b5abe1..0d1ad4fd5 100644 --- a/res/menu/message_list_xl_option.xml +++ b/res/menu/message_list_xl_option.xml @@ -16,8 +16,16 @@ + This should not be altered if the original string ("999+") makes sense in the target language. Typical alternatives include "+999" and ">999". [CHAR_LIMIT=4] --> 999+ + + + Email + + Search email diff --git a/res/xml/searchable.xml b/res/xml/searchable.xml new file mode 100644 index 000000000..e716bbbbb --- /dev/null +++ b/res/xml/searchable.xml @@ -0,0 +1,21 @@ + + + + diff --git a/src/com/android/email/Controller.java b/src/com/android/email/Controller.java index ffeb2987b..7a3d3926c 100644 --- a/src/com/android/email/Controller.java +++ b/src/com/android/email/Controller.java @@ -886,7 +886,7 @@ public class Controller { } catch (RemoteException e) { // TODO Change exception handling to be consistent with however this method // is implemented for other protocols - Log.e("onDownloadAttachment", "RemoteException", e); + Log.e("searchMessages", "RemoteException", e); } } } diff --git a/src/com/android/email/activity/MessageListFragment.java b/src/com/android/email/activity/MessageListFragment.java index 6a78ff3a0..17f1fe93a 100644 --- a/src/com/android/email/activity/MessageListFragment.java +++ b/src/com/android/email/activity/MessageListFragment.java @@ -1180,6 +1180,11 @@ public class MessageListFragment extends ListFragment lss = new Utility.ListStateSaver(lv); } + // If this is a search mailbox, set the query + if (mMailbox != null && mMailbox.mType == Mailbox.TYPE_SEARCH) { + mListAdapter.setQuery(mMailbox.mDisplayName); + } + // Update the list mListAdapter.swapCursor(cursor); // Show chips if combined view. diff --git a/src/com/android/email/activity/MessageListItem.java b/src/com/android/email/activity/MessageListItem.java index bb33be100..29de275f0 100644 --- a/src/com/android/email/activity/MessageListItem.java +++ b/src/com/android/email/activity/MessageListItem.java @@ -17,6 +17,7 @@ package com.android.email.activity; import com.android.email.R; +import com.android.emailcommon.utility.TextUtilities; import android.content.Context; import android.content.res.Resources; @@ -37,6 +38,7 @@ import android.text.TextPaint; import android.text.TextUtils; import android.text.TextUtils.TruncateAt; import android.text.format.DateUtils; +import android.text.style.BackgroundColorSpan; import android.text.style.StyleSpan; import android.util.AttributeSet; import android.view.MotionEvent; @@ -89,6 +91,7 @@ public class MessageListItem extends View { private static final TextPaint sDefaultPaint = new TextPaint(); private static final TextPaint sBoldPaint = new TextPaint(); private static final TextPaint sDatePaint = new TextPaint(); + private static final TextPaint sHighlightPaint = new TextPaint(); private static Bitmap sAttachmentIcon; private static Bitmap sInviteIcon; private static Bitmap sFavoriteIconOff; @@ -100,7 +103,7 @@ public class MessageListItem extends View { public String mSender; public CharSequence mText; - public String mSnippet; + public CharSequence mSnippet; public String mSubject; public boolean mRead; public long mTimestamp; @@ -208,6 +211,7 @@ public class MessageListItem extends View { sBoldPaint.setTypeface(Typeface.DEFAULT_BOLD); sBoldPaint.setTextSize(sTextSize); sBoldPaint.setAntiAlias(true); + sHighlightPaint.setColor(TextUtilities.HIGHLIGHT_COLOR_INT); sAttachmentIcon = BitmapFactory.decodeResource(r, R.drawable.ic_badge_attachment); sInviteIcon = BitmapFactory.decodeResource(r, R.drawable.ic_badge_invite); sFavoriteIconOff = @@ -444,28 +448,35 @@ public class MessageListItem extends View { mRead ? sDefaultPaint : sBoldPaint); // Draw each of the snippet lines - int subjectEnd = (mSubject == null) ? 0 : mSubject.length(); - int lineStart = 0; - TextPaint subjectPaint = mRead ? sDefaultPaint : sBoldPaint; for (int i = 0; i < MAX_SUBJECT_SNIPPET_LINES && i < mSnippetLineCount; i++) { CharSequence line = mSnippetLines[i]; int drawX = snippetX; if (line != null) { - int defaultPaintStart = 0; - if (lineStart <= subjectEnd) { - int boldPaintEnd = subjectEnd - lineStart; - if (boldPaintEnd > line.length()) { - boldPaintEnd = line.length(); + SpannableStringBuilder ssb = (SpannableStringBuilder)line; + Object[] spans = ssb.getSpans(0, line.length(), Object.class); + int curr = 0; + for (Object span: spans) { + if (span != null) { + int spanStart = ssb.getSpanStart(span); + int spanEnd = ssb.getSpanEnd(span); + if (curr < spanStart) { + canvas.drawText(line, curr, spanStart, drawX, snippetY, sDefaultPaint); + drawX += sDefaultPaint.measureText(line, curr, spanStart); + } + TextPaint spanPaint = + (span instanceof StyleSpan) ? sBoldPaint : sDefaultPaint; + float textWidth = spanPaint.measureText(line, spanStart, spanEnd); + if (span instanceof BackgroundColorSpan) { + canvas.drawRect(drawX, snippetY + ascent, drawX + textWidth, + snippetY + descent, sHighlightPaint); + } + canvas.drawText(line, spanStart, spanEnd, drawX, snippetY, spanPaint); + drawX += textWidth; + curr = spanEnd; } - // From 0 to end, do in bold or default depending on the read flag - canvas.drawText(line, 0, boldPaintEnd, drawX, snippetY, subjectPaint); - defaultPaintStart = boldPaintEnd; - drawX += subjectPaint.measureText(line, 0, boldPaintEnd); } - canvas.drawText(line, defaultPaintStart, line.length(), drawX, snippetY, - sDefaultPaint); + canvas.drawText(line, curr, line.length(), drawX, snippetY, sDefaultPaint); snippetY += lineHeight; - lineStart += line.length(); } } diff --git a/src/com/android/email/activity/MessageListXL.java b/src/com/android/email/activity/MessageListXL.java index 4fd381265..387e69594 100644 --- a/src/com/android/email/activity/MessageListXL.java +++ b/src/com/android/email/activity/MessageListXL.java @@ -29,11 +29,17 @@ import com.android.emailcommon.Logging; import com.android.emailcommon.mail.MessagingException; import com.android.emailcommon.provider.EmailContent.Account; import com.android.emailcommon.provider.EmailContent.Mailbox; +import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.utility.EmailAsyncTask; +import com.android.emailcommon.utility.Utility; import android.app.ActionBar; import android.app.Activity; import android.app.LoaderManager.LoaderCallbacks; +import android.app.SearchManager; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.Loader; @@ -227,6 +233,47 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana if (Email.DEBUG_LIFECYCLE && Email.DEBUG) Log.d(Logging.LOG_TAG, "MessageListXL onStart"); super.onStart(); mFragmentManager.onStart(); + + // STOPSHIP Temporary search UI + Intent intent = getIntent(); + if (Intent.ACTION_SEARCH.equals(intent.getAction())) { + // TODO Very temporary (e.g. no database access in UI thread) + Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA); + if (appData == null) return; // ?? + final long accountId = appData.getLong(EXTRA_ACCOUNT_ID); + final long mailboxId = appData.getLong(EXTRA_MAILBOX_ID); + final String queryString = intent.getStringExtra(SearchManager.QUERY); + Log.d(Logging.LOG_TAG, queryString); + // Switch to search mailbox + // TODO How to handle search from within the search mailbox?? + final Controller controller = Controller.getInstance(mContext); + final Mailbox searchMailbox = controller.getSearchMailbox(accountId); + if (searchMailbox == null) return; + + // Delete contents, add a placeholder + ContentResolver resolver = mContext.getContentResolver(); + resolver.delete(Message.CONTENT_URI, Message.MAILBOX_KEY + "=" + searchMailbox.mId, + null); + ContentValues cv = new ContentValues(); + cv.put(Mailbox.DISPLAY_NAME, queryString); + resolver.update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, searchMailbox.mId), cv, + null, null); + Message msg = new Message(); + msg.mMailboxKey = searchMailbox.mId; + msg.mAccountKey = accountId; + msg.mDisplayName = "Searching for " + queryString; + msg.mTimeStamp = Long.MAX_VALUE; // Sort on top + msg.save(mContext); + + actionOpenMessage(MessageListXL.this, accountId, searchMailbox.mId, msg.mId); + Utility.runAsync(new Runnable() { + @Override + public void run() { + controller.searchMessages(accountId, mailboxId, true, queryString, 10, 0, + searchMailbox.mId); + }}); + return; + } } @Override @@ -455,6 +502,17 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana @Override public boolean onPrepareOptionsMenu(Menu menu) { + // STOPSHIP Temporary search UI + // Only show search for EAS + boolean showSearch = false; + long accountId = mFragmentManager.getActualAccountId(); + if (accountId > 0) { + if ("eas".equals(Account.getProtocol(mContext, accountId))) { + showSearch = true; + } + } + menu.findItem(R.id.search).setVisible(showSearch); + ActivityHelper.updateRefreshMenuIcon( menu.findItem(R.id.refresh), shouldShowRefreshButton(), isProgressActive()); return super.onPrepareOptionsMenu(menu); @@ -466,6 +524,15 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana return -1 != mFragmentManager.getActualAccountId(); } + @Override + public boolean onSearchRequested() { + Bundle bundle = new Bundle(); + bundle.putLong(EXTRA_ACCOUNT_ID, mFragmentManager.getActualAccountId()); + bundle.putLong(EXTRA_MAILBOX_ID, mFragmentManager.getMailboxId()); + startSearch(null, false, bundle, false); + return true; + } + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { @@ -478,6 +545,9 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana case R.id.refresh: onRefresh(); return true; + case R.id.search: + onSearchRequested(); + return true; case R.id.account_settings: return onAccountSettings(); } diff --git a/src/com/android/email/activity/MessagesAdapter.java b/src/com/android/email/activity/MessagesAdapter.java index ba1741ca0..9747fed03 100644 --- a/src/com/android/email/activity/MessagesAdapter.java +++ b/src/com/android/email/activity/MessagesAdapter.java @@ -23,6 +23,7 @@ import com.android.emailcommon.Logging; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.provider.EmailContent.MessageColumns; +import com.android.emailcommon.utility.TextUtilities; import com.android.emailcommon.utility.Utility; import android.content.Context; @@ -69,6 +70,9 @@ import java.util.Set; /** If true, show color chips. */ private boolean mShowColorChips; + /** If not null, the query represented by this group of messages */ + private String mQuery; + /** * Set of seleced message IDs. */ @@ -118,6 +122,10 @@ import java.util.Set; mShowColorChips = show; } + public void setQuery(String query) { + mQuery = query; + } + public Set getSelectedSet() { return mSelectedSet; } @@ -149,6 +157,11 @@ import java.util.Set; itemView.mSnippetLineCount = MessageListItem.NEEDS_LAYOUT; itemView.mColorChipPaint = mShowColorChips ? mResourceHelper.getAccountColorPaint(accountId) : null; + + if (mQuery != null && itemView.mSnippet != null) { + itemView.mSnippet = + TextUtilities.highlightTermsInText(cursor.getString(COLUMN_SNIPPET), mQuery); + } } @Override @@ -209,7 +222,7 @@ import java.util.Set; } - private static class MessagesCursorLoader extends ThrottlingCursorLoader { + static private class MessagesCursorLoader extends ThrottlingCursorLoader { private final Context mContext; private final long mMailboxId;