[LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/systemui am: 21cbf34f75 am: e5600bcf8a am: f2ec734e9e

Original change: https://android-review.googlesource.com/c/platform/frameworks/libs/systemui/+/1589017

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ie1cfd90af5cdf71754508be841e5cbea1a756d3a
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
index 31a923e..4e1f25b 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -12,6 +12,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Paint;
 import android.graphics.PaintFlagsDrawFilter;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -19,6 +20,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
 import android.os.Build;
 import android.os.Process;
 import android.os.UserHandle;
@@ -56,6 +58,10 @@
     private Drawable mWrapperIcon;
     private int mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
 
+    private final Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+    private static final float PLACEHOLDER_TEXT_SIZE = 20f;
+    private static int PLACEHOLDER_BACKGROUND_COLOR = Color.rgb(240, 240, 240);
+
     protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize,
             boolean shapeDetection) {
         mContext = context.getApplicationContext();
@@ -68,6 +74,10 @@
 
         mCanvas = new Canvas();
         mCanvas.setDrawFilter(new PaintFlagsDrawFilter(DITHER_FLAG, FILTER_BITMAP_FLAG));
+        mTextPaint.setTextAlign(Paint.Align.CENTER);
+        mTextPaint.setColor(PLACEHOLDER_BACKGROUND_COLOR);
+        mTextPaint.setTextSize(context.getResources().getDisplayMetrics().density *
+                PLACEHOLDER_TEXT_SIZE);
         clear();
     }
 
@@ -113,6 +123,28 @@
         return null;
     }
 
+    /**
+     * Create a placeholder icon using the passed in text.
+     *
+     * @param placeholder used for foreground element in the icon bitmap
+     * @param color used for the foreground text color
+     * @return
+     */
+    public BitmapInfo createIconBitmap(String placeholder, int color) {
+        if (!ATLEAST_OREO) return null;
+
+        Bitmap placeholderBitmap = Bitmap.createBitmap(mIconBitmapSize, mIconBitmapSize,
+                Bitmap.Config.ARGB_8888);
+        mTextPaint.setColor(color);
+        Canvas canvas = new Canvas(placeholderBitmap);
+        canvas.drawText(placeholder, mIconBitmapSize / 2, mIconBitmapSize * 5 / 8, mTextPaint);
+        AdaptiveIconDrawable drawable = new AdaptiveIconDrawable(
+                new ColorDrawable(PLACEHOLDER_BACKGROUND_COLOR),
+                new BitmapDrawable(mContext.getResources(), placeholderBitmap));
+        Bitmap icon = createIconBitmap(drawable, 1f);
+        return BitmapInfo.of(icon, extractColor(icon));
+    }
+
     public BitmapInfo createIconBitmap(Bitmap icon) {
         if (mIconBitmapSize != icon.getWidth() || mIconBitmapSize != icon.getHeight()) {
             icon = createIconBitmap(new BitmapDrawable(mContext.getResources(), icon), 1f);
@@ -121,6 +153,20 @@
         return BitmapInfo.of(icon, extractColor(icon));
     }
 
+    /**
+     * Creates an icon from the bitmap cropped to the current device icon shape
+     */
+    public BitmapInfo createShapedIconBitmap(Bitmap icon, UserHandle user) {
+        Drawable d = new FixedSizeBitmapDrawable(icon);
+        if (ATLEAST_OREO) {
+            float inset = AdaptiveIconDrawable.getExtraInsetFraction();
+            inset = inset / (1 + 2 * inset);
+            d = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK),
+                    new InsetDrawable(d, inset, inset, inset, inset));
+        }
+        return createBadgedIconBitmap(d, user, true);
+    }
+
     public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
             boolean shrinkNonAdaptiveIcons) {
         return createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, false, null);
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
index 4c634cb..5587a64 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
@@ -396,7 +396,7 @@
         }
         if (icon != null) {
             BaseIconFactory li = getIconFactory();
-            entry.bitmap = li.createIconBitmap(icon);
+            entry.bitmap = li.createShapedIconBitmap(icon, user);
             li.close();
         }
         if (!TextUtils.isEmpty(title) && entry.bitmap.icon != null) {
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java b/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java
index ee52934..3dfb384 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java
@@ -17,19 +17,36 @@
 
 import android.os.Handler;
 
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
 /**
  * A runnable that can be posted to a {@link Handler} which can be canceled.
  */
-public abstract class HandlerRunnable implements Runnable {
+public class HandlerRunnable<T> implements Runnable {
 
-    private final Handler mHandler;
+    private final Handler mWorkerHandler;
+    private final Supplier<T> mTask;
+
+    private final Executor mCallbackExecutor;
+    private final Consumer<T> mCallback;
     private final Runnable mEndRunnable;
 
     private boolean mEnded = false;
     private boolean mCanceled = false;
 
-    public HandlerRunnable(Handler handler, Runnable endRunnable) {
-        mHandler = handler;
+    public HandlerRunnable(Handler workerHandler, Supplier<T> task, Executor callbackExecutor,
+            Consumer<T> callback) {
+        this(workerHandler, task, callbackExecutor, callback, () -> { });
+    }
+
+    public HandlerRunnable(Handler workerHandler, Supplier<T> task, Executor callbackExecutor,
+            Consumer<T> callback, Runnable endRunnable) {
+        mWorkerHandler = workerHandler;
+        mTask = task;
+        mCallbackExecutor = callbackExecutor;
+        mCallback = callback;
         mEndRunnable = endRunnable;
     }
 
@@ -37,31 +54,26 @@
      * Cancels this runnable from being run, only if it has not already run.
      */
     public void cancel() {
-        mHandler.removeCallbacks(this);
-        // TODO: This can actually cause onEnd to be called twice if the handler is already running
-        //       this runnable
-        // NOTE: This is currently run on whichever thread the caller is run on.
+        mWorkerHandler.removeCallbacks(this);
         mCanceled = true;
-        onEnd();
+        mCallbackExecutor.execute(this::onEnd);
     }
 
-    /**
-     * @return whether this runnable was canceled.
-     */
-    protected boolean isCanceled() {
-        return mCanceled;
+    @Override
+    public void run() {
+        T value = mTask.get();
+        mCallbackExecutor.execute(() -> {
+            if (!mCanceled) {
+                mCallback.accept(value);
+            }
+            onEnd();
+        });
     }
 
-    /**
-     * To be called by the implemention of this runnable. The end callback is done on whichever
-     * thread the caller is calling from.
-     */
-    public void onEnd() {
+    private void onEnd() {
         if (!mEnded) {
             mEnded = true;
-            if (mEndRunnable != null) {
-                mEndRunnable.run();
-            }
+            mEndRunnable.run();
         }
     }
 }
diff --git a/searchuilib/.gitignore b/searchuilib/.gitignore
new file mode 100644
index 0000000..6213826
--- /dev/null
+++ b/searchuilib/.gitignore
@@ -0,0 +1,13 @@
+*.iml
+.project
+.classpath
+.project.properties
+gen/
+bin/
+.idea/
+.gradle/
+local.properties
+gradle/
+build/
+gradlew*
+.DS_Store
diff --git a/searchuilib/Android.bp b/searchuilib/Android.bp
new file mode 100644
index 0000000..69695c6
--- /dev/null
+++ b/searchuilib/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2020 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.
+
+android_library {
+    name: "search_ui",
+
+    sdk_version: "current",
+    min_sdk_version: "current",
+
+    srcs: [
+        "src/**/*.java",
+    ],
+}
diff --git a/searchuilib/AndroidManifest.xml b/searchuilib/AndroidManifest.xml
new file mode 100644
index 0000000..6c6c5f6
--- /dev/null
+++ b/searchuilib/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2020 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.app.search">
+</manifest>
diff --git a/searchuilib/build.gradle b/searchuilib/build.gradle
new file mode 100644
index 0000000..4f372e3
--- /dev/null
+++ b/searchuilib/build.gradle
@@ -0,0 +1,37 @@
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion COMPILE_SDK
+    buildToolsVersion BUILD_TOOLS_VERSION
+
+    defaultConfig {
+        minSdkVersion 25
+        targetSdkVersion 28
+        versionCode 1
+        versionName "1.0"
+    }
+
+    sourceSets {
+        main {
+            java.srcDirs = ['src']
+            manifest.srcFile 'AndroidManifest.xml'
+        }
+    }
+
+    lintOptions {
+        abortOnError false
+    }
+
+    tasks.withType(JavaCompile) {
+        options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+}
+
+dependencies {
+    implementation "androidx.core:core:${ANDROID_X_VERSION}"
+}
diff --git a/searchuilib/src/com/android/app/search/LayoutType.java b/searchuilib/src/com/android/app/search/LayoutType.java
new file mode 100644
index 0000000..9661b7c
--- /dev/null
+++ b/searchuilib/src/com/android/app/search/LayoutType.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 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.app.search;
+
+/**
+ * Constants to be used with {@link SearchTarget}.
+ */
+public class LayoutType {
+
+    //     ------
+    //    | icon |
+    //     ------
+    //      text
+    public static final String ICON_SINGLE_VERTICAL_TEXT = "icon";
+
+    // Below three layouts (to be deprecated) and two layouts render
+    // {@link SearchTarget}s in following layout.
+    //     ------                            ------   ------
+    //    |      | title                    |(opt)|  |(opt)|
+    //    | icon | subtitle (optional)      | icon|  | icon|
+    //     ------                            ------  ------
+    @Deprecated
+    public static final String ICON_SINGLE_HORIZONTAL_TEXT = "icon_text_row";
+    @Deprecated
+    public static final String ICON_DOUBLE_HORIZONTAL_TEXT = "icon_texts_row";
+    @Deprecated
+    public static final String ICON_DOUBLE_HORIZONTAL_TEXT_BUTTON = "icon_texts_button";
+
+    // will replace ICON_DOUBLE_* ICON_SINGLE_* layouts
+    public static final String ICON_HORIZONTAL_TEXT = "icon_row";
+    public static final String SMALL_ICON_HORIZONTAL_TEXT = "short_icon_row";
+
+    // This layout creates square thumbnail image (currently 3 column)
+    public static final String THUMBNAIL = "thumbnail";
+
+    // This layout contains an icon and slice
+    public static final String ICON_SLICE = "slice";
+
+    // Widget bitmap preview
+    public static final String WIDGET_PREVIEW = "widget_preview";
+
+    // Live widget search result
+    public static final String WIDGET_LIVE = "widget_live";
+
+    // text based header to group various layouts in low confidence section of the results.
+    public static final String TEXT_HEADER = "header";
+
+    // horizontal bar to be inserted between fallback search results and low confidence section
+    public static final String DIVIDER = "divider";
+}