Search delay fixes.

- adds a loading state to search so the user isn't left with a blank
screen for several seconds
- adds a timeout so that a warning message is shown for results that
take over 10 seconds
- use default loading/no message views in ListFragment so we don't have
to manager our own stuff

Bug: 5014107
Bug: 5037618
Change-Id: I8b03fa0967055989156c7777901affc777c4fae7
This commit is contained in:
Ben Komalo 2011-07-27 11:24:59 -07:00
parent 786285b3a6
commit 391b9d4abd
4 changed files with 120 additions and 26 deletions

View File

@ -24,16 +24,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:id="@+id/no_messages_panel"
android:text="@string/message_list_no_messages"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceLarge"
android:visibility="gone"
/>
<!-- Search header is dynamically inserted here for search results -->
<include
layout="@android:layout/list_content"
@ -42,4 +34,7 @@
android:layout_height="0dip"
android:layout_weight="1"
/>
<!-- Message list error overlays are dynamically inserted here -->
</LinearLayout>

View File

@ -0,0 +1,54 @@
<?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.
-->
<!--
The default ListFragment layout (include) + the "send outgoing message" button.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
>
<ProgressBar style="?android:attr/progressBarStyleLarge"
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/message_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dip"
android:layout_marginRight="16dip"
android:layout_marginTop="4dip"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
<TextView
android:id="@+id/message_warning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="32dip"
android:layout_marginRight="32dip"
android:layout_marginTop="4dip"
android:textAppearance="?android:attr/textAppearanceSmall"
/>
</LinearLayout>

View File

@ -1215,6 +1215,14 @@ save attachment.</string>
<string name="search_header_text_fmt"
>Search results for \"<xliff:g example="search query">%1$s</xliff:g>\"</string>
<!-- A warning title to show to the user when search results are taking a long
time. [CHAR LIMIT=NONE] -->
<string name="search_slow_warning_title">Waiting for results</string>
<!-- A warning message to show to the user when search results are taking a long
time. [CHAR LIMIT=NONE] -->
<string name="search_slow_warning_message">Some servers may take a long time.</string>
<!-- Title shown on the action bar on the mailbox list screen. [CHAR LIMIT=16] -->
<string name="action_bar_mailbox_list_title">Folders</string>

View File

@ -102,11 +102,12 @@ public class MessageListFragment extends ListFragment
private Callback mCallback = EmptyCallback.INSTANCE;
private boolean mIsViewCreated;
private View mListPanel;
private View mListFooterView;
private TextView mListFooterText;
private View mListFooterProgress;
private View mNoMessagesPanel;
private ViewGroup mSearchHeader;
private ViewGroup mWarningContainer;
private TextView mSearchHeaderText;
private TextView mSearchHeaderCount;
@ -335,7 +336,6 @@ public class MessageListFragment extends ListFragment
mRefreshManager = RefreshManager.getInstance(mActivity);
mListAdapter = new MessagesAdapter(mActivity, this);
setListAdapter(mListAdapter);
}
@Override
@ -346,8 +346,8 @@ public class MessageListFragment extends ListFragment
}
// Use a custom layout, which includes the original layout with "send messages" panel.
View root = inflater.inflate(R.layout.message_list_fragment,null);
mNoMessagesPanel = UiUtilities.getView(root, R.id.no_messages_panel);
mIsViewCreated = true;
mListPanel = UiUtilities.getView(root, R.id.list_panel);
return root;
}
@ -392,6 +392,7 @@ public class MessageListFragment extends ListFragment
mListFooterView = getActivity().getLayoutInflater().inflate(
R.layout.message_list_item_footer, lv, false);
setEmptyText(getString(R.string.message_list_no_messages));
if (savedInstanceState != null) {
// Fragment doesn't have this method. Call it manually.
@ -543,10 +544,6 @@ public class MessageListFragment extends ListFragment
}
}
/* package */MessagesAdapter getAdapterForTest() {
return mListAdapter;
}
/**
* @return true if the mailbox is refreshable. false otherwise, or unknown yet.
*/
@ -1144,11 +1141,6 @@ public class MessageListFragment extends ListFragment
&& (mMailbox == null || mMailbox.canHaveMessagesMoved());
}
private void showNoMessageText(boolean visible) {
mNoMessagesPanel.setVisibility(visible ? View.VISIBLE : View.GONE);
getListView().setVisibility(visible ? View.GONE : View.VISIBLE);
}
/**
* Adjusts message notification depending upon the state of the fragment and the currently
* viewed mailbox. If the fragment is resumed, notifications for the current mailbox may
@ -1176,7 +1168,6 @@ public class MessageListFragment extends ListFragment
Log.d(Logging.LOG_TAG, this + " startLoading");
}
// Clear the list. (ListFragment will show the "Loading" animation)
showNoMessageText(false);
showSendCommand(false);
updateSearchHeader(null);
@ -1185,6 +1176,26 @@ public class MessageListFragment extends ListFragment
lm.initLoader(LOADER_ID_MESSAGES_LOADER, null, new MessagesLoaderCallback());
}
/** Timeout to show a warning, since some IMAP searches could take a long time. */
private final int SEARCH_WARNING_DELAY_MS = 10000;
private void onSearchLoadTimeout() {
// Search is taking too long. Show an error message.
ViewGroup root = (ViewGroup) getView();
Activity host = getActivity();
if (root != null && host != null) {
mListPanel.setVisibility(View.GONE);
mWarningContainer = (ViewGroup) LayoutInflater.from(host).inflate(
R.layout.message_list_warning, root, false);
TextView title = UiUtilities.getView(mWarningContainer, R.id.message_title);
TextView message = UiUtilities.getView(mWarningContainer, R.id.message_warning);
title.setText(R.string.search_slow_warning_title);
message.setText(R.string.search_slow_warning_message);
root.addView(mWarningContainer);
}
}
/**
* Loader callbacks for message list.
*/
@ -1198,6 +1209,29 @@ public class MessageListFragment extends ListFragment
Log.d(Logging.LOG_TAG, MessageListFragment.this
+ " onCreateLoader(messages) listContext=" + listContext);
}
if (mListContext.isSearch()) {
final MessageListContext searchInfo = mListContext;
// Search results are not primed with local data, and so will usually be slow.
// In some cases, they could take a long time to return, so we need to be robust.
setListShownNoAnimation(false);
Utility.getMainThreadHandler().postDelayed(new Runnable() {
@Override
public void run() {
if (mListContext != searchInfo) {
// Different list is being shown now.
return;
}
if (!mIsFirstLoad) {
// Something already returned. No need to do anything.
return;
}
onSearchLoadTimeout();
}
}, SEARCH_WARNING_DELAY_MS);
}
mIsFirstLoad = true;
return MessagesAdapter.createLoader(getActivity(), listContext);
}
@ -1258,8 +1292,6 @@ public class MessageListFragment extends ListFragment
autoRefreshStaleMailbox();
addFooterView();
updateSelectionMode();
showNoMessageText((cursor.getCount() == 0)
&& (getListContext().isSearch() || (mListFooterMode == LIST_FOOTER_MODE_NONE)));
// We want to make visible the selection only for the first load.
// Re-load caused by content changed events shouldn't scroll the list.
@ -1269,7 +1301,12 @@ public class MessageListFragment extends ListFragment
// "post processing" seems to reset the scroll position.
lv.onRestoreInstanceState(listState);
// Clear this for next reload triggered by content changed events.
if (mIsFirstLoad) {
setListShownNoAnimation(true);
UiUtilities.setVisibilitySafe(mWarningContainer, View.GONE);
mListPanel.setVisibility(View.VISIBLE);
setListAdapter(mListAdapter);
}
mIsFirstLoad = false;
}