Temporary search UI
Change-Id: Ia138ca93f0b28fd0915aa79c965f752f7c08ee90
This commit is contained in:
parent
2a2e42b7d8
commit
78684ccc79
|
@ -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"
|
||||
|
|
|
@ -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 |
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
/>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
// 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);
|
||||
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, defaultPaintStart, line.length(), drawX, snippetY,
|
||||
sDefaultPaint);
|
||||
canvas.drawText(line, spanStart, spanEnd, drawX, snippetY, spanPaint);
|
||||
drawX += textWidth;
|
||||
curr = spanEnd;
|
||||
}
|
||||
}
|
||||
canvas.drawText(line, curr, line.length(), drawX, snippetY, sDefaultPaint);
|
||||
snippetY += lineHeight;
|
||||
lineStart += line.length();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue