Throttling contact directory search requests.

Change-Id: I83ebb33df1c3c08f56869de454937c63227c0f0e
diff --git a/src/com/android/contacts/list/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index 708cdd8..34a439d 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -42,6 +42,7 @@
 import android.database.Cursor;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Message;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.provider.ContactsContract;
@@ -96,6 +97,9 @@
 
     private static final int DIRECTORY_LOADER_ID = -1;
 
+    private static final int DIRECTORY_SEARCH_DELAY_MILLIS = 300;
+    private static final int DIRECTORY_SEARCH_MESSAGE = 1;
+
     private boolean mSectionHeaderDisplayEnabled;
     private boolean mPhotoLoaderEnabled;
     private boolean mSearchMode;
@@ -140,6 +144,15 @@
 
     private LoaderManager mLoaderManager;
 
+    private Handler mDelayedDirectorySearchHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == DIRECTORY_SEARCH_MESSAGE) {
+                loadDirectoryPartition(msg.arg1, (DirectoryPartition) msg.obj);
+            }
+        }
+    };
+
     protected abstract View inflateView(LayoutInflater inflater, ViewGroup container);
     protected abstract T createListAdapter();
 
@@ -315,16 +328,48 @@
 
     private void startLoadingDirectoryPartition(int partitionIndex) {
         DirectoryPartition partition = (DirectoryPartition)mAdapter.getPartition(partitionIndex);
-        Bundle args = new Bundle();
         long directoryId = partition.getDirectoryId();
-        args.putLong(DIRECTORY_ID_ARG_KEY, directoryId);
         if (mForceLoad) {
-            getLoaderManager().restartLoader(partitionIndex, args, this);
+            if (directoryId == Directory.DEFAULT) {
+                loadDirectoryPartition(partitionIndex, partition);
+            } else {
+                loadDirectoryPartitionDelayed(partitionIndex, partition);
+            }
         } else {
+            Bundle args = new Bundle();
+            args.putLong(DIRECTORY_ID_ARG_KEY, directoryId);
             getLoaderManager().initLoader(partitionIndex, args, this);
         }
     }
 
+    /**
+     * Queues up a delayed request to search the specified directory. Since
+     * directory search will likely introduce a lot of network traffic, we want
+     * to wait for a pause in the user's typing before sending a directory request.
+     */
+    private void loadDirectoryPartitionDelayed(int partitionIndex, DirectoryPartition partition) {
+        mDelayedDirectorySearchHandler.removeMessages(DIRECTORY_SEARCH_MESSAGE, partition);
+        Message msg = mDelayedDirectorySearchHandler.obtainMessage(
+                DIRECTORY_SEARCH_MESSAGE, partitionIndex, 0, partition);
+        mDelayedDirectorySearchHandler.sendMessageDelayed(msg, DIRECTORY_SEARCH_DELAY_MILLIS);
+    }
+
+    /**
+     * Loads the directory partition.
+     */
+    protected void loadDirectoryPartition(int partitionIndex, DirectoryPartition partition) {
+        Bundle args = new Bundle();
+        args.putLong(DIRECTORY_ID_ARG_KEY, partition.getDirectoryId());
+        getLoaderManager().restartLoader(partitionIndex, args, this);
+    }
+
+    /**
+     * Cancels all queued directory loading requests.
+     */
+    private void removePendingDirectorySearchRequests() {
+        mDelayedDirectorySearchHandler.removeMessages(DIRECTORY_SEARCH_MESSAGE);
+    }
+
     @Override
     public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
         if (!checkProviderStatus(false)) {
@@ -336,6 +381,7 @@
 
         int loaderId = loader.getId();
         if (loaderId == DIRECTORY_LOADER_ID) {
+            removePendingDirectorySearchRequests();
             mAdapter.changeDirectories(data);
         } else {
             onPartitionLoaded(loaderId, data);
@@ -727,6 +773,7 @@
     @Override
     public void onPause() {
         super.onPause();
+        removePendingDirectorySearchRequests();
         unregisterProviderStatusObserver();
     }