Merge "Fix bug where folder items preview remain in low res state." into ub-launcher3-master
diff --git a/go/quickstep/res/layout/task_item_view.xml b/go/quickstep/res/layout/task_item_view.xml
new file mode 100644
index 0000000..90940c4
--- /dev/null
+++ b/go/quickstep/res/layout/task_item_view.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2019 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.
+-->
+<com.android.quickstep.views.TaskItemView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal">
+    <ImageView
+        android:id="@+id/task_icon_and_thumbnail"
+        android:layout_width="@dimen/task_thumbnail_icon_size"
+        android:layout_height="@dimen/task_thumbnail_icon_size"
+        android:layout_gravity="center_vertical"
+        android:layout_marginHorizontal="8dp"/>
+    <TextView
+        android:id="@+id/task_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginHorizontal="8dp"
+        android:singleLine="true"
+        android:textColor="@android:color/white"
+        android:textSize="24sp"/>
+</com.android.quickstep.views.TaskItemView>
diff --git a/go/quickstep/src/com/android/quickstep/TaskAdapter.java b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
index 57cd60a..d3fd240 100644
--- a/go/quickstep/src/com/android/quickstep/TaskAdapter.java
+++ b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
@@ -15,16 +15,17 @@
  */
 package com.android.quickstep;
 
+import android.view.LayoutInflater;
 import android.view.ViewGroup;
-import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 import androidx.recyclerview.widget.RecyclerView.Adapter;
 
+import com.android.launcher3.R;
+import com.android.quickstep.views.TaskItemView;
 import com.android.systemui.shared.recents.model.Task;
 
 import java.util.ArrayList;
-
 /**
  * Recycler view adapter that dynamically inflates and binds {@link TaskHolder} instances with the
  * appropriate {@link Task} from the recents task list.
@@ -42,8 +43,9 @@
     @Override
     public TaskHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         // TODO: Swap in an actual task view here (view w/ icon, label, etc.)
-        TextView stubView = new TextView(parent.getContext());
-        return new TaskHolder(stubView);
+        TaskItemView itemView = (TaskItemView) LayoutInflater.from(parent.getContext())
+                .inflate(R.layout.task_item_view, parent, false);
+        return new TaskHolder(itemView);
     }
 
     @Override
diff --git a/go/quickstep/src/com/android/quickstep/TaskHolder.java b/go/quickstep/src/com/android/quickstep/TaskHolder.java
index 1ea6d76..47398c8 100644
--- a/go/quickstep/src/com/android/quickstep/TaskHolder.java
+++ b/go/quickstep/src/com/android/quickstep/TaskHolder.java
@@ -15,10 +15,9 @@
  */
 package com.android.quickstep;
 
-import android.widget.TextView;
-
 import androidx.recyclerview.widget.RecyclerView.ViewHolder;
 
+import com.android.quickstep.views.TaskItemView;
 import com.android.systemui.shared.recents.model.Task;
 
 /**
@@ -27,22 +26,21 @@
  */
 final class TaskHolder extends ViewHolder {
 
-    // TODO: Implement the actual task view to be held.
-    // For now, we just use a simple text view.
-    private final TextView mStubView;
+    private final TaskItemView mTaskItemView;
 
-    public TaskHolder(TextView stubView) {
-        super(stubView);
-        mStubView = stubView;
+    public TaskHolder(TaskItemView itemView) {
+        super(itemView);
+        mTaskItemView = itemView;
     }
 
     /**
      * Bind task content to the view. This includes the task icon and title as well as binding
      * input handlers such as which task to launch/remove.
      *
-     * @param task the task to bind to the view this
+     * @param task the task to bind to the view
      */
     public void bindTask(Task task) {
-        mStubView.setText("Stub task view: " + task.titleDescription);
+        mTaskItemView.setLabel(task.titleDescription);
+        mTaskItemView.setIcon(task.icon);
     }
 }
diff --git a/go/quickstep/src/com/android/quickstep/TaskListLoader.java b/go/quickstep/src/com/android/quickstep/TaskListLoader.java
index 9f359b4..c798cef 100644
--- a/go/quickstep/src/com/android/quickstep/TaskListLoader.java
+++ b/go/quickstep/src/com/android/quickstep/TaskListLoader.java
@@ -85,34 +85,40 @@
     }
 
     /**
-     * Loads task content for a list of tasks, including the label and the icon. Uses the list of
-     * tasks since the last load as a cache for loaded content.
+     * Loads task content for a list of tasks, including the label, icon, and thumbnail. For content
+     * that isn't cached, load the content asynchronously in the background.
      *
      * @param tasksToLoad list of tasks that need to load their content
-     * @param onLoadedCallback runnable to run after all tasks have loaded their content
+     * @param onFullyLoadedCallback runnable to run after all tasks have loaded their content
      */
     private void loadTaskContents(ArrayList<Task> tasksToLoad,
-            @Nullable Runnable onLoadedCallback) {
-        AtomicInteger loadRequestsCount = new AtomicInteger(0);
+            @Nullable Runnable onFullyLoadedCallback) {
+        // Make two load requests per task, one for the icon/title and one for the thumbnail.
+        AtomicInteger loadRequestsCount = new AtomicInteger(tasksToLoad.size() * 2);
+        Runnable itemLoadedRunnable = () -> {
+            if (loadRequestsCount.decrementAndGet() == 0 && onFullyLoadedCallback != null) {
+                onFullyLoadedCallback.run();
+            }
+        };
         for (Task task : tasksToLoad) {
+            // Load icon and title.
             int index = mTaskList.indexOf(task);
             if (index >= 0) {
                 // If we've already loaded the task and have its content then just copy it over.
                 Task loadedTask = mTaskList.get(index);
                 task.titleDescription = loadedTask.titleDescription;
                 task.icon = loadedTask.icon;
+                itemLoadedRunnable.run();
             } else {
                 // Otherwise, load the content in the background.
-                loadRequestsCount.getAndIncrement();
-                mRecentsModel.getIconCache().updateIconInBackground(task, loadedTask -> {
-                    if (loadRequestsCount.decrementAndGet() == 0 && onLoadedCallback != null) {
-                        onLoadedCallback.run();
-                    }
-                });
+                mRecentsModel.getIconCache().updateIconInBackground(task,
+                        loadedTask -> itemLoadedRunnable.run());
             }
-        }
-        if (loadRequestsCount.get() == 0 && onLoadedCallback != null) {
-            onLoadedCallback.run();
+
+            // Load the thumbnail. May return immediately and synchronously if the thumbnail is
+            // cached.
+            mRecentsModel.getThumbnailCache().updateThumbnailInBackground(task,
+                    thumbnail -> itemLoadedRunnable.run());
         }
     }
 }
diff --git a/go/quickstep/src/com/android/quickstep/views/TaskItemView.java b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
new file mode 100644
index 0000000..ce3947d
--- /dev/null
+++ b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 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.quickstep.views;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.launcher3.R;
+
+/**
+ * View representing an individual task item with the icon + thumbnail adjacent to the task label.
+ */
+public final class TaskItemView extends LinearLayout {
+
+    private TextView mLabelView;
+    private ImageView mIconView;
+
+    public TaskItemView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mLabelView = findViewById(R.id.task_label);
+        mIconView = findViewById(R.id.task_icon_and_thumbnail);
+    }
+
+    /**
+     * Set the label for the task item.
+     *
+     * @param label task label
+     */
+    public void setLabel(String label) {
+        mLabelView.setText(label);
+    }
+
+    /**
+     * Set the icon for the task item.
+     *
+     * @param icon task icon
+     */
+    public void setIcon(Drawable icon) {
+        mIconView.setImageDrawable(icon);
+        // TODO: Add in combination drawable for icon + thumbnail
+    }
+}
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index d6e450a..cb239b3 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -21,6 +21,9 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 
 import androidx.annotation.GuardedBy;
@@ -256,6 +259,16 @@
         @Override
         public void initialize(Context context) {
             contentResolver = context.getContentResolver();
+            contentResolver.registerContentObserver(Settings.Global.getUriFor(getKey()), true,
+                    new ContentObserver(new Handler(Looper.getMainLooper())) {
+                        @Override
+                        public void onChange(boolean selfChange) {
+                            superInitialize(context);
+                    }});
+            superInitialize(context);
+        }
+
+        private void superInitialize(Context context) {
             super.initialize(context);
         }
 
@@ -274,10 +287,5 @@
             }
             return Settings.Global.getInt(contentResolver, getKey(), defaultValue ? 1 : 0) == 1;
         }
-
-        @Override
-        public boolean get() {
-            return getFromStorage(null, getDefaultValue());
-        }
     }
 }