[settings-pixel-search] Add slice timeout to avoid showing empty slice view


Bug: 181810946

Test: m
Change-Id: Icd83bbf428bf7d87e3957a6f6d888142c6008da3
diff --git a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
index 330ec68..e268f56 100644
--- a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.allapps.search;
 
+import android.net.Uri;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -37,6 +38,11 @@
     }
 
     @Override
+    public void onSliceStatusUpdate(Uri sliceUri) {
+
+    }
+
+    @Override
     public boolean isSearchView(int viewType) {
         return false;
     }
diff --git a/src/com/android/launcher3/allapps/search/LiveSearchManager.java b/src/com/android/launcher3/allapps/search/LiveSearchManager.java
index 76099a6..adb882a 100644
--- a/src/com/android/launcher3/allapps/search/LiveSearchManager.java
+++ b/src/com/android/launcher3/allapps/search/LiveSearchManager.java
@@ -42,6 +42,7 @@
 import androidx.slice.SliceViewManager;
 import androidx.slice.SliceViewManager.SliceCallback;
 
+import com.android.launcher3.Alarm;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.statemanager.StateManager.StateListener;
@@ -52,6 +53,7 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.function.Consumer;
 
 /**
  * Manages Lifecycle for Live search results
@@ -60,6 +62,7 @@
 
     private static final String TAG = "LiveSearchManager";
 
+    private static final long SLICE_TIMEOUT_MS = 50;
     public static final int SEARCH_APPWIDGET_HOST_ID = 2048;
 
     private final Launcher mLauncher;
@@ -144,16 +147,50 @@
     /**
      * Adds a new observer for the provided uri and returns a callback to cancel this observer
      */
-    public SafeCloseable addObserver(Uri uri, Observer<Slice> listener) {
+    public SafeCloseable addObserver(Uri uri, Observer<Slice> listener,
+            Consumer<Uri> timeoutConsumer) {
         SliceLifeCycle slc = mUriSliceMap.get(uri);
         if (slc == null) {
             slc = new SliceLifeCycle(uri, mLauncher);
             mUriSliceMap.put(uri, slc);
         }
-        slc.addListener(listener);
+        if (slc.mLastValue != null) {
+            listener.onChanged(slc.mLastValue);
+        }
+
+        // Use a listener wrapper to handle error timeout.
+        Observer<Slice> listenerWrapper = new Observer<Slice>() {
+            final Alarm mErrorTimeout = new Alarm();
+            {
+                mErrorTimeout.setOnAlarmListener(alarm -> {
+                    alarm.cancelAlarm();
+                    timeoutConsumer.accept(uri);
+                });
+                mErrorTimeout.setAlarm(SLICE_TIMEOUT_MS);
+            }
+
+            @Override
+            public void onChanged(Slice slice) {
+                if (slice == null) {
+                    return;
+                }
+
+                if (mErrorTimeout.alarmPending()) {
+                    mErrorTimeout.cancelAlarm();
+                }
+
+                if (mUriSliceMap.get(uri) != null) {
+                    mUriSliceMap.get(uri).mLastValue = slice;
+                }
+
+                listener.onChanged(slice);
+            }
+        };
+
+        slc.addListener(listenerWrapper);
 
         final SliceLifeCycle sliceLifeCycle = slc;
-        return () -> sliceLifeCycle.removeListener(listener);
+        return () -> sliceLifeCycle.removeListener(listenerWrapper);
     }
 
     static class SearchWidgetHost extends AppWidgetHost {
@@ -184,6 +221,8 @@
         private boolean mDestroyed = false;
         private boolean mWasListening = false;
 
+        Slice mLastValue;
+
         SliceLifeCycle(Uri uri, Launcher launcher) {
             mUri = uri;
             mLauncher = launcher;
diff --git a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
index fdacd3d..0864090 100644
--- a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.allapps.search;
 
+import android.net.Uri;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -40,6 +41,11 @@
     public abstract void onBindView(AllAppsGridAdapter.ViewHolder holder, int position);
 
     /**
+     * Called from LiveSearchManager to notify slice status updates.
+     */
+    public abstract void onSliceStatusUpdate(Uri sliceUri);
+
+    /**
      * Returns whether or not viewType can be handled by searchProvider
      */
     public abstract boolean isSearchView(int viewType);