Snap for 9406096 from 50cd81ffd52a5843203b437f3437e126da459795 to tm-qpr2-release

Change-Id: Ia8b735edb974e2c2a541400b19986fd68fac4f9d
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c238961..0faf2e1 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -399,4 +399,10 @@
 
     <!-- Label for a button which lets user try to open their photos. [CHAR LIMIT=40] -->
     <string name="open_my_photos">Open My Photos</string>
+
+    <!--
+    Name of the authority corresponding to a ContentProvider in system UI that can provide remote
+    rendering of a preview of the lock screen.
+    -->
+    <string name="lock_screen_preview_provider_authority" translatable="false">com.android.systemui.keyguard.quickaffordance</string>
 </resources>
diff --git a/src/com/android/wallpaper/model/WallpaperSectionController.java b/src/com/android/wallpaper/model/WallpaperSectionController.java
index 7963015..12babbd 100644
--- a/src/com/android/wallpaper/model/WallpaperSectionController.java
+++ b/src/com/android/wallpaper/model/WallpaperSectionController.java
@@ -59,6 +59,7 @@
 import com.android.wallpaper.picker.MyPhotosStarter;
 import com.android.wallpaper.picker.WallpaperSectionView;
 import com.android.wallpaper.picker.WorkspaceSurfaceHolderCallback;
+import com.android.wallpaper.util.PreviewUtils;
 import com.android.wallpaper.util.ResourceUtils;
 import com.android.wallpaper.util.WallpaperConnection;
 import com.android.wallpaper.util.WallpaperSurfaceCallback;
@@ -164,7 +165,9 @@
         mWorkspaceSurface = mHomePreviewCard.findViewById(R.id.workspace_surface);
         mHomePreviewProgress = mHomePreviewCard.findViewById(R.id.wallpaper_preview_spinner);
         mWorkspaceSurfaceCallback = new WorkspaceSurfaceHolderCallback(
-                mWorkspaceSurface, mAppContext);
+                mWorkspaceSurface,
+                new PreviewUtils(
+                        mAppContext, mAppContext.getString(R.string.grid_control_metadata_name)));
         mHomeWallpaperSurface = mHomePreviewCard.findViewById(R.id.wallpaper_surface);
 
         Future<ColorInfo> colorFuture = CompletableFuture.completedFuture(
diff --git a/src/com/android/wallpaper/picker/DisplayAspectRatioFrameLayout.kt b/src/com/android/wallpaper/picker/DisplayAspectRatioFrameLayout.kt
new file mode 100644
index 0000000..a2f1c67
--- /dev/null
+++ b/src/com/android/wallpaper/picker/DisplayAspectRatioFrameLayout.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 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.wallpaper.picker
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.FrameLayout
+import androidx.core.view.children
+import com.android.wallpaper.util.ScreenSizeCalculator
+
+/**
+ * [FrameLayout] that sizes its children using a fixed aspect ratio that is the same as that of the
+ * display.
+ */
+class DisplayAspectRatioFrameLayout(
+    context: Context,
+    attrs: AttributeSet?,
+) : FrameLayout(context, attrs) {
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        val screenAspectRatio = ScreenSizeCalculator.getInstance().getScreenAspectRatio(context)
+        // We're always forcing the width based on the height. This will only work if the
+        // DisplayAspectRatioFrameLayout is allowed to stretch to fill its parent (for example if
+        // the parent is a vertical LinearLayout and the DisplayAspectRatioFrameLayout has a height
+        // if 0 and a weight of 1.
+        //
+        // If you need to use this class to force the height dimension based on the width instead,
+        // you will need to flip the logic below.
+        children.forEach { child ->
+            child.measure(
+                MeasureSpec.makeMeasureSpec(
+                    (child.measuredHeight / screenAspectRatio).toInt(),
+                    MeasureSpec.EXACTLY
+                ),
+                MeasureSpec.makeMeasureSpec(
+                    child.measuredHeight,
+                    MeasureSpec.EXACTLY,
+                ),
+            )
+        }
+    }
+}
diff --git a/src/com/android/wallpaper/picker/PreviewFragment.java b/src/com/android/wallpaper/picker/PreviewFragment.java
index e1eaca2..e9e78c8 100755
--- a/src/com/android/wallpaper/picker/PreviewFragment.java
+++ b/src/com/android/wallpaper/picker/PreviewFragment.java
@@ -58,6 +58,7 @@
 import com.android.wallpaper.module.WallpaperPreferences;
 import com.android.wallpaper.module.WallpaperSetter;
 import com.android.wallpaper.util.FullScreenAnimation;
+import com.android.wallpaper.util.PreviewUtils;
 import com.android.wallpaper.util.ResourceUtils;
 import com.android.wallpaper.widget.BottomActionBar;
 import com.android.wallpaper.widget.BottomActionBar.BottomSheetContent;
@@ -317,7 +318,11 @@
 
     protected WorkspaceSurfaceHolderCallback createWorkspaceSurfaceCallback(
             SurfaceView workspaceSurface) {
-        return new WorkspaceSurfaceHolderCallback(workspaceSurface, getContext());
+        return new WorkspaceSurfaceHolderCallback(
+                workspaceSurface,
+                new PreviewUtils(
+                        getContext(),
+                        getContext().getString(R.string.grid_control_metadata_name)));
     }
 
     @Override
diff --git a/src/com/android/wallpaper/picker/WorkspaceSurfaceHolderCallback.java b/src/com/android/wallpaper/picker/WorkspaceSurfaceHolderCallback.java
index 2661923..bb4c0d3 100644
--- a/src/com/android/wallpaper/picker/WorkspaceSurfaceHolderCallback.java
+++ b/src/com/android/wallpaper/picker/WorkspaceSurfaceHolderCallback.java
@@ -16,7 +16,6 @@
 package com.android.wallpaper.picker;
 
 import android.app.WallpaperColors;
-import android.content.Context;
 import android.os.Bundle;
 import android.os.Message;
 import android.os.RemoteException;
@@ -27,7 +26,6 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.wallpaper.R;
 import com.android.wallpaper.util.PreviewUtils;
 import com.android.wallpaper.util.SurfaceViewUtils;
 
@@ -60,9 +58,12 @@
     private WorkspaceRenderListener mListener;
 
     private boolean mNeedsToCleanUp;
+    @Nullable private final Bundle mExtras;
 
-    public WorkspaceSurfaceHolderCallback(SurfaceView workspaceSurface, Context context) {
-        this(workspaceSurface, context, false);
+    public WorkspaceSurfaceHolderCallback(
+            SurfaceView workspaceSurface,
+            PreviewUtils previewUtils) {
+        this(workspaceSurface, previewUtils, false, null);
     }
 
     /**
@@ -73,12 +74,33 @@
      *                                 the surface is created and wallpaper colors are set via
      *                                 {@link #setWallpaperColors(WallpaperColors)}
      */
-    public WorkspaceSurfaceHolderCallback(SurfaceView workspaceSurface, Context context,
+    public WorkspaceSurfaceHolderCallback(
+            SurfaceView workspaceSurface,
+            PreviewUtils previewUtils,
             boolean shouldUseWallpaperColors) {
+        this(
+                workspaceSurface,
+                previewUtils,
+                shouldUseWallpaperColors,
+                null);
+    }
+
+    public WorkspaceSurfaceHolderCallback(
+            SurfaceView workspaceSurface,
+            PreviewUtils previewUtils,
+            @Nullable Bundle extras) {
+        this(workspaceSurface, previewUtils, false, extras);
+    }
+
+    private WorkspaceSurfaceHolderCallback(
+            SurfaceView workspaceSurface,
+            PreviewUtils previewUtils,
+            boolean shouldUseWallpaperColors,
+            @Nullable Bundle extras) {
         mWorkspaceSurface = workspaceSurface;
-        mPreviewUtils = new PreviewUtils(context,
-                context.getString(R.string.grid_control_metadata_name));
+        mPreviewUtils = previewUtils;
         mShouldUseWallpaperColors = shouldUseWallpaperColors;
+        mExtras = extras;
     }
 
     @Override
@@ -96,7 +118,7 @@
      *
      * @param colors WallpaperColors extracted from the current wallpaper preview, or {@code null}
      *               if none are available.
-     * @see #WorkspaceSurfaceHolderCallback(SurfaceView, Context, boolean)
+     * @see #WorkspaceSurfaceHolderCallback(SurfaceView, PreviewUtils, boolean)
      */
     public void setWallpaperColors(@Nullable WallpaperColors colors) {
         if (!mShouldUseWallpaperColors) {
@@ -141,6 +163,27 @@
     public void surfaceDestroyed(SurfaceHolder holder) {
     }
 
+    /**
+     * Sends a message to the remote renderer.
+     *
+     * @param what An ID for the message (the remote side can pick this up through
+     * {@link Message#what}.
+     * @param bundle The data of the message (the remote side can pick this up through
+     * {@link Message#getData()}.
+     */
+    public void send(final int what, @Nullable Bundle bundle) {
+        if (mCallback != null) {
+            try {
+                final Message message = new Message();
+                message.what = what;
+                message.setData(bundle);
+                mCallback.replyTo.send(message);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Couldn't send message to workspace preview", e);
+            }
+        }
+    }
+
     public void cleanUp() {
         if (mCallback != null) {
             try {
@@ -170,7 +213,7 @@
                             + "crash");
             return;
         }
-        Bundle request = SurfaceViewUtils.createSurfaceViewRequest(workspaceSurface);
+        Bundle request = SurfaceViewUtils.createSurfaceViewRequest(workspaceSurface, mExtras);
         if (mWallpaperColors != null) {
             request.putParcelable(KEY_WALLPAPER_COLORS, mWallpaperColors);
         }
diff --git a/src/com/android/wallpaper/util/PreviewUtils.java b/src/com/android/wallpaper/util/PreviewUtils.java
deleted file mode 100644
index 0b8977a..0000000
--- a/src/com/android/wallpaper/util/PreviewUtils.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.wallpaper.util;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.text.TextUtils;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-/** Util class for wallpaper preview. */
-public class PreviewUtils {
-
-    private static final String PREVIEW = "preview";
-    private static final String METHOD_GET_PREVIEW = "get_preview";
-    private static final ExecutorService sExecutorService = Executors.newSingleThreadExecutor();
-
-    private final Context mContext;
-    private final String mProviderAuthority;
-    private ProviderInfo mProviderInfo;
-
-    public PreviewUtils(Context context, String authorityMetadataKey) {
-        mContext = context;
-        Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
-
-        ResolveInfo info = context.getPackageManager().resolveActivity(homeIntent,
-                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA);
-        if (info != null && info.activityInfo != null && info.activityInfo.metaData != null) {
-            mProviderAuthority = info.activityInfo.metaData.getString(authorityMetadataKey);
-        } else {
-            mProviderAuthority = null;
-        }
-
-        mProviderInfo = TextUtils.isEmpty(mProviderAuthority) ? null
-                : mContext.getPackageManager().resolveContentProvider(mProviderAuthority, 0);
-        if (mProviderInfo != null && !TextUtils.isEmpty(mProviderInfo.readPermission)) {
-            if (context.checkSelfPermission(mProviderInfo.readPermission)
-                    != PackageManager.PERMISSION_GRANTED) {
-                mProviderInfo = null;
-            }
-        }
-    }
-
-    /**
-     * Render preview under the current grid option.
-     * @param bundle request options to pass on the call
-     * @param callback to receive the results, it will be called on the main thread.
-     */
-    public void renderPreview(Bundle bundle, WorkspacePreviewCallback callback) {
-        sExecutorService.submit(() -> {
-            Bundle result = mContext.getContentResolver().call(getUri(PREVIEW),
-                    METHOD_GET_PREVIEW, null, bundle);
-            new Handler(Looper.getMainLooper()).post(() -> callback.onPreviewRendered(result));
-        });
-    }
-
-    /** Easy way to generate a Uri with the provider info from this class. */
-    public Uri getUri(String path) {
-        return new Uri.Builder()
-                .scheme(ContentResolver.SCHEME_CONTENT)
-                .authority(mProviderInfo.authority)
-                .appendPath(path)
-                .build();
-    }
-
-    /** Return whether preview is supported. */
-    public boolean supportsPreview() {
-        return mProviderInfo != null;
-    }
-
-    /**
-     * Callback for a call to the provider to render preview
-     */
-    public interface WorkspacePreviewCallback {
-        /**
-         * Called with the result from the provider.
-         */
-        void onPreviewRendered(Bundle resultBundle);
-    }
-}
diff --git a/src/com/android/wallpaper/util/PreviewUtils.kt b/src/com/android/wallpaper/util/PreviewUtils.kt
new file mode 100644
index 0000000..a2e0275
--- /dev/null
+++ b/src/com/android/wallpaper/util/PreviewUtils.kt
@@ -0,0 +1,128 @@
+/*
+ * 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.wallpaper.util
+
+import android.content.ContentResolver
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.ProviderInfo
+import android.net.Uri
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.text.TextUtils
+import java.util.concurrent.Executors
+
+/** Util class for wallpaper preview. */
+class PreviewUtils(
+    private val context: Context,
+    authorityMetadataKey: String? = null,
+    authority: String? = null,
+) {
+    /** Callback for a call to the provider to render preview */
+    interface WorkspacePreviewCallback {
+        /** Called with the result from the provider. */
+        fun onPreviewRendered(resultBundle: Bundle?)
+    }
+
+    private var providerInfo: ProviderInfo?
+
+    constructor(
+        context: Context,
+        authorityMetadataKey: String,
+    ) : this(
+        context = context,
+        authorityMetadataKey = authorityMetadataKey,
+        authority = null,
+    )
+
+    init {
+        val providerAuthority =
+            authority ?: homeAuthority(context, checkNotNull(authorityMetadataKey))
+
+        providerInfo =
+            if (!TextUtils.isEmpty(providerAuthority)) {
+                context.packageManager.resolveContentProvider(
+                    providerAuthority,
+                    0,
+                )
+            } else {
+                null
+            }
+
+        providerInfo?.let {
+            if (!TextUtils.isEmpty(it.readPermission)) {
+                if (
+                    context.checkSelfPermission(it.readPermission) !=
+                        PackageManager.PERMISSION_GRANTED
+                ) {
+                    providerInfo = null
+                }
+            }
+        }
+    }
+
+    /**
+     * Render preview under the current grid option.
+     *
+     * @param bundle request options to pass on the call.
+     * @param callback to receive the results, it will be called on the main thread.
+     */
+    fun renderPreview(bundle: Bundle?, callback: WorkspacePreviewCallback) {
+        EXECUTOR_SERVICE.submit {
+            val result =
+                context.contentResolver.call(
+                    getUri(PREVIEW),
+                    METHOD_GET_PREVIEW,
+                    null,
+                    bundle,
+                )
+            Handler(Looper.getMainLooper()).post { callback.onPreviewRendered(result) }
+        }
+    }
+
+    /** Easy way to generate a Uri with the provider info from this class. */
+    fun getUri(path: String?): Uri {
+        return Uri.Builder()
+            .scheme(ContentResolver.SCHEME_CONTENT)
+            .authority(checkNotNull(providerInfo).authority)
+            .appendPath(path)
+            .build()
+    }
+
+    /** Return whether preview is supported. */
+    fun supportsPreview(): Boolean {
+        return providerInfo != null
+    }
+
+    companion object {
+        private const val PREVIEW = "preview"
+        private const val METHOD_GET_PREVIEW = "get_preview"
+        private val EXECUTOR_SERVICE = Executors.newSingleThreadExecutor()
+
+        private fun homeAuthority(context: Context, authorityMetadataKey: String): String? {
+            val homeIntent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
+            val info =
+                context.packageManager.resolveActivity(
+                    homeIntent,
+                    PackageManager.MATCH_DEFAULT_ONLY or PackageManager.GET_META_DATA,
+                )
+
+            return info?.activityInfo?.metaData?.getString(authorityMetadataKey)
+        }
+    }
+}
diff --git a/src/com/android/wallpaper/util/SurfaceViewUtils.java b/src/com/android/wallpaper/util/SurfaceViewUtils.java
index 1656b1b..1b74f77 100644
--- a/src/com/android/wallpaper/util/SurfaceViewUtils.java
+++ b/src/com/android/wallpaper/util/SurfaceViewUtils.java
@@ -20,6 +20,8 @@
 import android.view.SurfaceControlViewHost;
 import android.view.SurfaceView;
 
+import androidx.annotation.Nullable;
+
 /** Util class to generate surface view requests and parse responses */
 public class SurfaceViewUtils {
 
@@ -32,11 +34,21 @@
 
     /** Create a surface view request. */
     public static Bundle createSurfaceViewRequest(SurfaceView surfaceView) {
+        return createSurfaceViewRequest(surfaceView, null);
+    }
+
+    /** Create a surface view request. */
+    public static Bundle createSurfaceViewRequest(
+            SurfaceView surfaceView,
+            @Nullable Bundle extras) {
         Bundle bundle = new Bundle();
         bundle.putBinder(KEY_HOST_TOKEN, surfaceView.getHostToken());
         bundle.putInt(KEY_DISPLAY_ID, surfaceView.getDisplay().getDisplayId());
         bundle.putInt(KEY_VIEW_WIDTH, surfaceView.getWidth());
         bundle.putInt(KEY_VIEW_HEIGHT, surfaceView.getHeight());
+        if (extras != null) {
+            bundle.putAll(extras);
+        }
         return bundle;
     }