Fixing ModelPreload cancelling existing load

When a model preload call was made while the loader task is running
(eg: on enabling/disabling icon theme, Launcher reloads and then
launcher preview start a model-preload), it would cancel the original
loader and then start a new loader with empty callbacks. So the
model indeed get loaded, but the original callbacks never got notified
of it.

> Instead we only start preload if an existing task is not running.
> Also when preloading, we use existing callbacks, instead of using
  empty callbacks

Bug: 193851085
Bug: 195155924
Test: Verified repro steps
Change-Id: I0a96310be8489756f364aa2a12e4345e1418733d
(cherry picked from commit 57d4f748b89b2a07e2b33acdfdbcc3767df0aa41)
Merged-In:I0a96310be8489756f364aa2a12e4345e1418733d
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index eef3980..545f4c3 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -72,6 +72,7 @@
 import java.util.List;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 import java.util.function.Supplier;
 
 /**
@@ -376,7 +377,13 @@
                     loaderResults.bindWidgets();
                     return true;
                 } else {
-                    startLoaderForResults(loaderResults);
+                    stopLoader();
+                    mLoaderTask = new LoaderTask(
+                            mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, loaderResults);
+
+                    // Always post the loader task, instead of running directly
+                    // (even on same thread) so that we exit any nested synchronized blocks
+                    MODEL_EXECUTOR.post(mLoaderTask);
                 }
             }
         }
@@ -399,25 +406,17 @@
         }
     }
 
-    public void startLoaderForResults(LoaderResults results) {
+    /**
+     * Loads the model if not loaded
+     * @param callback called with the data model upon successful load or null on model thread.
+     */
+    public void loadAsync(Consumer<BgDataModel> callback) {
         synchronized (mLock) {
-            stopLoader();
-            mLoaderTask = new LoaderTask(
-                    mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, results);
-
-            // Always post the loader task, instead of running directly (even on same thread) so
-            // that we exit any nested synchronized blocks
-            MODEL_EXECUTOR.post(mLoaderTask);
-        }
-    }
-
-    public void startLoaderForResultsIfNotLoaded(LoaderResults results) {
-        synchronized (mLock) {
-            if (!isModelLoaded()) {
-                Log.d(TAG, "Workspace not loaded, loading now");
-                startLoaderForResults(results);
+            if (!mModelLoaded && !mIsLoaderTaskRunning) {
+                startLoader();
             }
         }
+        MODEL_EXECUTOR.post(() -> callback.accept(isModelLoaded() ? mBgDataModel : null));
     }
 
     @Override
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index df49359..3b140a0 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -49,7 +49,6 @@
 import com.android.launcher3.model.GridSizeMigrationTaskV2;
 import com.android.launcher3.model.LoaderTask;
 import com.android.launcher3.model.ModelDelegate;
-import com.android.launcher3.model.ModelPreload;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.Themes;
@@ -174,18 +173,13 @@
                 }
             }.run();
         } else {
-            new ModelPreload() {
-
-                @Override
-                public void onComplete(boolean isSuccess) {
-                    if (isSuccess) {
-                        MAIN_EXECUTOR.execute(() ->
-                                renderView(inflationContext, getBgDataModel(), null));
-                    } else {
-                        Log.e(TAG, "Model loading failed");
-                    }
+            LauncherAppState.getInstance(inflationContext).getModel().loadAsync(dataModel -> {
+                if (dataModel != null) {
+                    MAIN_EXECUTOR.execute(() -> renderView(inflationContext, dataModel, null));
+                } else {
+                    Log.e(TAG, "Model loading failed");
                 }
-            }.start(inflationContext);
+            });
         }
     }
 
diff --git a/src/com/android/launcher3/model/ModelPreload.java b/src/com/android/launcher3/model/ModelPreload.java
deleted file mode 100644
index 756b7da..0000000
--- a/src/com/android/launcher3/model/ModelPreload.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-package com.android.launcher3.model;
-
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-
-import android.content.Context;
-import android.util.Log;
-
-import androidx.annotation.WorkerThread;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherModel;
-import com.android.launcher3.LauncherModel.ModelUpdateTask;
-import com.android.launcher3.model.BgDataModel.Callbacks;
-
-import java.util.concurrent.Executor;
-
-/**
- * Utility class to preload LauncherModel
- */
-public class ModelPreload implements ModelUpdateTask {
-
-    private static final String TAG = "ModelPreload";
-
-    private LauncherAppState mApp;
-    private LauncherModel mModel;
-    private BgDataModel mBgDataModel;
-    private AllAppsList mAllAppsList;
-
-    @Override
-    public final void init(LauncherAppState app, LauncherModel model, BgDataModel dataModel,
-            AllAppsList allAppsList, Executor uiExecutor) {
-        mApp = app;
-        mModel = model;
-        mBgDataModel = dataModel;
-        mAllAppsList = allAppsList;
-    }
-
-    @Override
-    public final void run() {
-        mModel.startLoaderForResultsIfNotLoaded(
-                new LoaderResults(mApp, mBgDataModel, mAllAppsList, new Callbacks[0]));
-        MODEL_EXECUTOR.post(() -> {
-            Log.d(TAG, "Preload completed : " + mModel.isModelLoaded());
-            onComplete(mModel.isModelLoaded());
-        });
-    }
-
-    public BgDataModel getBgDataModel() {
-        return mBgDataModel;
-    }
-
-    /**
-     * Called when the task is complete
-     */
-    @WorkerThread
-    public void onComplete(boolean isSuccess) { }
-
-    public void start(Context context) {
-        LauncherAppState.getInstance(context).getModel().enqueueModelUpdateTask(this);
-    }
-}
\ No newline at end of file