Add live wallpaper support for Grid preview

Add supprot for grid full preview first, next step is to add for grid picker.

Video: https://drive.google.com/file/d/1AH6AUno2IYxHzEt1nItNmASf0S6OEbgM/view?usp=sharing

Test: Manually
Bug: 155938545
Change-Id: If2cc9a7e7e79f346100fea4b821862c515bbc644
diff --git a/res/layout/fragment_grid_full_preview.xml b/res/layout/fragment_grid_full_preview.xml
index 80733ab..1c01743 100644
--- a/res/layout/fragment_grid_full_preview.xml
+++ b/res/layout/fragment_grid_full_preview.xml
@@ -40,13 +40,19 @@
             <ImageView
                 android:id="@+id/grid_full_preview_image"
                 android:layout_width="match_parent"
-                android:layout_height="match_parent" />
+                android:layout_height="match_parent"
+                android:background="@color/primary_color"/>
 
             <SurfaceView
-                android:id="@+id/grid_full_preview_surface"
+                android:id="@+id/grid_full_preview_option_surface"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"/>
 
+            <SurfaceView
+                android:id="@+id/grid_full_preview_wallpaper_surface"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+
         </androidx.cardview.widget.CardView>
     </FrameLayout>
 </LinearLayout>
diff --git a/src/com/android/customization/picker/grid/GridFragment.java b/src/com/android/customization/picker/grid/GridFragment.java
index b3495c6..c9af437 100644
--- a/src/com/android/customization/picker/grid/GridFragment.java
+++ b/src/com/android/customization/picker/grid/GridFragment.java
@@ -19,6 +19,7 @@
 
 import static com.android.customization.picker.ViewOnlyFullPreviewActivity.SECTION_GRID;
 import static com.android.customization.picker.grid.GridFullPreviewFragment.EXTRA_GRID_OPTION;
+import static com.android.customization.picker.grid.GridFullPreviewFragment.EXTRA_GRID_USES_SURFACE_VIEW;
 import static com.android.customization.picker.grid.GridFullPreviewFragment.EXTRA_WALLPAPER_INFO;
 import static com.android.wallpaper.widget.BottomActionBar.BottomAction.APPLY;
 
@@ -297,6 +298,7 @@
         Bundle bundle = new Bundle();
         bundle.putParcelable(EXTRA_WALLPAPER_INFO, mHomeWallpaper);
         bundle.putParcelable(EXTRA_GRID_OPTION, mSelectedOption);
+        bundle.putBoolean(EXTRA_GRID_USES_SURFACE_VIEW, mGridManager.usesSurfaceView());
         Intent intent = ViewOnlyFullPreviewActivity.newIntent(getContext(), SECTION_GRID, bundle);
         startActivityForResult(intent, FULL_PREVIEW_REQUEST_CODE);
     }
@@ -367,7 +369,8 @@
             super.setCard(card);
             mPreview = card.findViewById(R.id.grid_preview_image);
             mPreviewSurface = card.findViewById(R.id.grid_preview_surface);
-            card.setOnClickListener(view -> showFullPreview());
+            // PreviewSurface is the top of its window(card view), due to #setZOrderOnTop(true).
+            mPreviewSurface.setOnClickListener(view -> showFullPreview());
         }
 
         public void bindPreviewContent() {
diff --git a/src/com/android/customization/picker/grid/GridFullPreviewFragment.java b/src/com/android/customization/picker/grid/GridFullPreviewFragment.java
index 9e469a3..4803ca2 100644
--- a/src/com/android/customization/picker/grid/GridFullPreviewFragment.java
+++ b/src/com/android/customization/picker/grid/GridFullPreviewFragment.java
@@ -16,19 +16,24 @@
 package com.android.customization.picker.grid;
 
 import static android.app.Activity.RESULT_OK;
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
 
 import static com.android.customization.picker.grid.GridFragment.PREVIEW_FADE_DURATION_MS;
 import static com.android.wallpaper.widget.BottomActionBar.BottomAction.APPLY;
 
 import android.app.Activity;
 import android.content.Intent;
-import android.graphics.drawable.BitmapDrawable;
+import android.graphics.Rect;
+import android.graphics.RectF;
 import android.os.Bundle;
 import android.os.Message;
 import android.os.RemoteException;
+import android.service.wallpaper.WallpaperService;
 import android.util.DisplayMetrics;
 import android.view.LayoutInflater;
 import android.view.Surface;
+import android.view.SurfaceControlViewHost;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
@@ -38,6 +43,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.cardview.widget.CardView;
+import androidx.core.content.ContextCompat;
 
 import com.android.customization.model.grid.GridOption;
 import com.android.customization.model.grid.GridOptionsManager;
@@ -47,12 +53,15 @@
 import com.android.wallpaper.R;
 import com.android.wallpaper.asset.Asset;
 import com.android.wallpaper.asset.ContentUriAsset;
+import com.android.wallpaper.model.LiveWallpaperInfo;
 import com.android.wallpaper.model.WallpaperInfo;
 import com.android.wallpaper.module.InjectorProvider;
 import com.android.wallpaper.picker.AppbarFragment;
 import com.android.wallpaper.util.SurfaceViewUtils;
 import com.android.wallpaper.util.TileSizeCalculator;
+import com.android.wallpaper.util.WallpaperConnection;
 import com.android.wallpaper.widget.BottomActionBar;
+import com.android.wallpaper.widget.LiveTileOverlay;
 
 import com.bumptech.glide.request.RequestOptions;
 
@@ -61,15 +70,26 @@
 
     static final String EXTRA_WALLPAPER_INFO = "wallpaper_info";
     static final String EXTRA_GRID_OPTION = "grid_option";
+    static final String EXTRA_GRID_USES_SURFACE_VIEW = "uses_surface_view";
+
+    private final Rect mPreviewLocalRect = new Rect();
+    private final Rect mPreviewGlobalRect = new Rect();
+    private final int[] mLivePreviewLocation = new int[2];
 
     private GridOptionsManager mGridManager;
     private WallpaperInfo mWallpaper;
     private GridOption mGridOption;
+    private boolean mUsesSurfaceView;
 
     private CardView mCardView;
-    private ImageView mPreview;
-    private SurfaceView mPreviewSurface;
-    private BitmapDrawable mCardBackground;
+    private ImageView mHomePreview;
+    private SurfaceView mGridOptionSurface;
+    private SurfaceView mWallpaperSurface;
+    private WallpaperConnection mWallpaperConnection;
+
+    // Home workspace surface is behind the app window, and so must the home image wallpaper like
+    // the live wallpaper. This view is rendered on mWallpaperSurface for home image wallpaper.
+    private ImageView mHomeImageWallpaper;
 
     /**
      * Returns a new {@link GridFullPreviewFragment} with the provided title and bundle arguments
@@ -89,6 +109,7 @@
         super.onCreate(savedInstanceState);
         mWallpaper = getArguments().getParcelable(EXTRA_WALLPAPER_INFO);
         mGridOption = getArguments().getParcelable(EXTRA_GRID_OPTION);
+        mUsesSurfaceView = getArguments().getBoolean(EXTRA_GRID_USES_SURFACE_VIEW);
 
         CustomizationInjector injector = (CustomizationInjector) InjectorProvider.getInjector();
         ThemesUserEventLogger eventLogger = (ThemesUserEventLogger) injector.getUserEventLogger(
@@ -108,8 +129,10 @@
         setUpToolbar(view);
 
         mCardView = view.findViewById(R.id.grid_full_preview_card);
-        mPreview = view.findViewById(R.id.grid_full_preview_image);
-        mPreviewSurface = view.findViewById(R.id.grid_full_preview_surface);
+        mHomePreview = view.findViewById(R.id.grid_full_preview_image);
+        mGridOptionSurface = view.findViewById(R.id.grid_full_preview_option_surface);
+        mWallpaperSurface = view.findViewById(R.id.grid_full_preview_wallpaper_surface);
+        mGridOptionSurface.setVisibility(View.GONE);
 
         final DisplayMetrics dm = getResources().getDisplayMetrics();
         float screenAspectRatio = (float) dm.heightPixels / dm.widthPixels;
@@ -125,16 +148,19 @@
                 mCardView.setRadius(TileSizeCalculator.getPreviewCornerRadius(
                         getActivity(), mCardView.getMeasuredWidth()));
                 view.removeOnLayoutChangeListener(this);
-                loadWallpaperBackground();
             }
         });
-
-        // Needs to fetch for the result of #usesSurfaceView.
-        mGridManager.fetchOptions(grids -> bindPreviewContent(), false);
         return view;
     }
 
     @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        updateWallpaperSurface();
+        updateWorkspaceSurface();
+    }
+
+    @Override
     protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
         bottomActionBar.bindBackButtonToSystemBackKey(getActivity());
         bottomActionBar.showActionsOnly(APPLY);
@@ -142,6 +168,32 @@
         bottomActionBar.show();
     }
 
+    @Override
+    public void onResume() {
+        super.onResume();
+        if (mWallpaperConnection != null) {
+            mWallpaperConnection.setVisibility(true);
+        }
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        if (mWallpaperConnection != null) {
+            mWallpaperConnection.setVisibility(false);
+        }
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        LiveTileOverlay.INSTANCE.detach(mHomePreview.getOverlay());
+        if (mWallpaperConnection != null) {
+            mWallpaperConnection.disconnect();
+            mWallpaperConnection = null;
+        }
+    }
+
     private void finishActivityWithResultOk() {
         Activity activity = requireActivity();
         activity.overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
@@ -151,33 +203,23 @@
         activity.finish();
     }
 
-    private void loadWallpaperBackground() {
-        if (mWallpaper != null && mCardView.getMeasuredWidth() > 0
-                && mCardView.getMeasuredHeight() > 0) {
-            mWallpaper.getThumbAsset(getContext()).decodeBitmap(mCardView.getMeasuredWidth(),
-                    mCardView.getMeasuredHeight(),
-                    bitmap -> {
-                        mCardBackground = new BitmapDrawable(getResources(), bitmap);
-                        bindWallpaperIfAvailable();
-                    });
-        }
+    private void updateWallpaperSurface() {
+        mWallpaperSurface.setZOrderMediaOverlay(false);
+        mWallpaperSurface.getHolder().addCallback(mWallpaperSurfaceCallback);
     }
 
-    private void bindPreviewContent() {
-        bindWallpaperIfAvailable();
-        final boolean usesSurfaceViewForPreview = mGridManager.usesSurfaceView();
-        mPreview.setVisibility(usesSurfaceViewForPreview ? View.GONE : View.VISIBLE);
-        mPreviewSurface.setVisibility(usesSurfaceViewForPreview ? View.VISIBLE : View.GONE);
-        if (usesSurfaceViewForPreview) {
-            mPreviewSurface.setZOrderOnTop(true);
-            mPreviewSurface.getHolder().addCallback(mSurfaceCallback);
+    private void updateWorkspaceSurface() {
+        if (mUsesSurfaceView) {
+            mGridOptionSurface.setZOrderOnTop(true);
+            mGridOptionSurface.getHolder().addCallback(mGridOptionSurfaceCallback);
+            mGridOptionSurface.setVisibility(View.VISIBLE);
         } else {
             final Asset previewAsset = new ContentUriAsset(
                     getContext(),
                     mGridOption.previewImageUri,
                     RequestOptions.fitCenterTransform());
             previewAsset.loadDrawableWithTransition(getContext(),
-                    mPreview /* imageView */,
+                    mHomePreview /* imageView */,
                     PREVIEW_FADE_DURATION_MS /* duration */,
                     null /* drawableLoadedListener */,
                     getResources().getColor(android.R.color.transparent,
@@ -185,14 +227,70 @@
         }
     }
 
-    private void bindWallpaperIfAvailable() {
-        if (mCardBackground != null) {
-            mPreview.setBackground(mCardBackground);
-            mPreviewSurface.setBackground(mCardBackground);
+    private void setUpWallpaperPreview() {
+        if (mWallpaper != null && mHomeImageWallpaper != null) {
+            boolean renderInImageWallpaperSurface = !(mWallpaper instanceof LiveWallpaperInfo);
+            mWallpaper.getThumbAsset(getContext())
+                    .loadPreviewImage(getActivity(),
+                            renderInImageWallpaperSurface ? mHomeImageWallpaper : mHomePreview,
+                            getResources().getColor(R.color.secondary_color));
+            LiveTileOverlay.INSTANCE.detach(mHomePreview.getOverlay());
+            if (mWallpaper instanceof LiveWallpaperInfo) {
+                mWallpaper.getThumbAsset(getContext().getApplicationContext())
+                        .loadPreviewImage(
+                                getActivity(),
+                                mHomeImageWallpaper,
+                                getContext().getColor(R.color.secondary_color));
+                setUpLiveWallpaperPreview(mWallpaper);
+            } else {
+                if (mWallpaperConnection != null) {
+                    mWallpaperConnection.disconnect();
+                    mWallpaperConnection = null;
+                }
+            }
         }
     }
 
-    private final SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
+    private void setUpLiveWallpaperPreview(WallpaperInfo homeWallpaper) {
+        Activity activity = getActivity();
+        if (activity == null) {
+            return;
+        }
+
+        if (mWallpaperConnection != null) {
+            mWallpaperConnection.disconnect();
+        }
+
+        mHomePreview.getLocationOnScreen(mLivePreviewLocation);
+        mPreviewGlobalRect.set(0, 0, mHomePreview.getMeasuredWidth(),
+                mHomePreview.getMeasuredHeight());
+        mPreviewLocalRect.set(mPreviewGlobalRect);
+        mPreviewGlobalRect.offset(mLivePreviewLocation[0], mLivePreviewLocation[1]);
+
+        mWallpaperConnection = new WallpaperConnection(
+                getWallpaperIntent(homeWallpaper.getWallpaperComponent()), activity,
+                new WallpaperConnection.WallpaperConnectionListener() {
+                    @Override
+                    public void onEngineShown() {}
+                }, mPreviewGlobalRect);
+
+        LiveTileOverlay.INSTANCE.update(new RectF(mPreviewLocalRect), mCardView.getRadius());
+
+        mWallpaperConnection.setVisibility(true);
+        mHomePreview.post(() -> {
+            if (!mWallpaperConnection.connect()) {
+                mWallpaperConnection = null;
+                LiveTileOverlay.INSTANCE.detach(mHomePreview.getOverlay());
+            }
+        });
+    }
+
+    private Intent getWallpaperIntent(android.app.WallpaperInfo info) {
+        return new Intent(WallpaperService.SERVICE_INTERFACE)
+                .setClassName(info.getPackageName(), info.getServiceName());
+    }
+
+    private final SurfaceHolder.Callback mGridOptionSurfaceCallback = new SurfaceHolder.Callback() {
 
         private Surface mLastSurface;
         private Message mCallback;
@@ -202,10 +300,10 @@
             if (mLastSurface != holder.getSurface()) {
                 mLastSurface = holder.getSurface();
                 Bundle result = mGridManager.renderPreview(
-                        SurfaceViewUtils.createSurfaceViewRequest(mPreviewSurface),
+                        SurfaceViewUtils.createSurfaceViewRequest(mGridOptionSurface),
                         mGridOption.name);
                 if (result != null) {
-                    mPreviewSurface.setChildSurfacePackage(
+                    mGridOptionSurface.setChildSurfacePackage(
                             SurfaceViewUtils.getSurfacePackage(result));
                     mCallback = SurfaceViewUtils.getCallback(result);
                 }
@@ -213,8 +311,7 @@
         }
 
         @Override
-        public void surfaceChanged(SurfaceHolder holder, int format, int width,
-                                   int height) {}
+        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
 
         @Override
         public void surfaceDestroyed(SurfaceHolder holder) {
@@ -229,4 +326,35 @@
             }
         }
     };
+
+    private final SurfaceHolder.Callback mWallpaperSurfaceCallback = new SurfaceHolder.Callback() {
+
+        private Surface mLastSurface;
+
+        @Override
+        public void surfaceCreated(SurfaceHolder holder) {
+            if (mLastSurface != holder.getSurface()) {
+                mLastSurface = holder.getSurface();
+                mHomeImageWallpaper = new ImageView(getContext());
+                mHomeImageWallpaper.setBackgroundColor(
+                        ContextCompat.getColor(getContext(), R.color.primary_color));
+                mHomeImageWallpaper.measure(makeMeasureSpec(mHomePreview.getWidth(), EXACTLY),
+                        makeMeasureSpec(mHomePreview.getHeight(), EXACTLY));
+                mHomeImageWallpaper.layout(0, 0, mHomePreview.getWidth(), mHomePreview.getHeight());
+
+                SurfaceControlViewHost host = new SurfaceControlViewHost(getContext(),
+                        getContext().getDisplay(), mWallpaperSurface.getHostToken());
+                host.setView(mHomeImageWallpaper, mHomeImageWallpaper.getWidth(),
+                        mHomeImageWallpaper.getHeight());
+                mWallpaperSurface.setChildSurfacePackage(host.getSurfacePackage());
+            }
+            setUpWallpaperPreview();
+        }
+
+        @Override
+        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
+
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) {}
+    };
 }