Temporary search UI

Change-Id: Ia138ca93f0b28fd0915aa79c965f752f7c08ee90
This commit is contained in:
Marc Blank 2011-03-31 13:29:23 -07:00
parent 2a2e42b7d8
commit 78684ccc79
11 changed files with 160 additions and 23 deletions

View File

@ -108,6 +108,7 @@
/>
</intent-filter>
</activity>
<!-- Must be exported in order for the AccountManager to launch it -->
<!-- Also available for continuous test systems to force account creation -->
<activity
@ -209,8 +210,11 @@
>
</activity>
<activity
android:name=".activity.MessageListXL"
>
android:name=".activity.MessageListXL">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/>
</activity>
<activity
android:name=".activity.MessageView"

View File

@ -32,7 +32,7 @@ import java.util.StringTokenizer;
public class TextUtilities {
// Highlight color is yellow, as in other apps.
// TODO Push for this to be a global (style-related?) constant
private static final int HIGHLIGHT_COLOR_INT = Color.YELLOW;
public static final int HIGHLIGHT_COLOR_INT = Color.YELLOW;
// We AND off the "alpha" from the color (i.e. 0xFFFFFF00 -> 0x00FFFF00)
/*package*/ static final String HIGHLIGHT_COLOR_STRING =
'#' + Integer.toHexString(HIGHLIGHT_COLOR_INT & 0x00FFFFFF);

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 B

View File

@ -16,8 +16,16 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/compose"
android:id="@+id/search"
android:orderInCategory="100"
android:alphabeticShortcut="s"
android:title="@string/search_action"
android:icon="@drawable/ic_menu_search_holo_light"
android:showAsAction="ifRoom"
/>
<item
android:id="@+id/compose"
android:orderInCategory="200"
android:alphabeticShortcut="c"
android:title="@string/compose_action"
android:icon="@drawable/ic_menu_compose_holo_light"
@ -25,7 +33,7 @@
/>
<item
android:id="@+id/refresh"
android:orderInCategory="200"
android:orderInCategory="300"
android:alphabeticShortcut="r"
android:title="@string/refresh_action"
android:icon="@drawable/ic_menu_refresh_holo_light"

View File

@ -1080,4 +1080,9 @@ save attachment.</string>
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] -->
<string name="more_than_999">999+</string>
<!-- Search title (should be the app name) [CHAR LIMIT=16] -->
<string name="search_title">Email</string>
<!-- The hint used in the search EditText field [CHAR LIMIT=35] -->
<string name="search_hint">Search email</string>
</resources>

21
res/xml/searchable.xml Normal file
View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2011 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_title"
android:hint="@string/search_hint"
android:icon="@drawable/ic_menu_search_holo_light"
/>

View File

@ -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);
}
}
}

View File

@ -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.

View File

@ -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();
}
}

View File

@ -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();
}

View File

@ -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<Long> 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;