Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6085ac8a authored by chihhangchuang's avatar chihhangchuang
Browse files

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
parent adb6f41e
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -40,10 +40,16 @@
            <ImageView
                android:id="@+id/grid_full_preview_image"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/primary_color"/>

            <SurfaceView
                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_surface"
                android:id="@+id/grid_full_preview_wallpaper_surface"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

+4 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import static android.app.Activity.RESULT_OK;

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 @@ public class GridFragment extends AppbarFragment {
        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 @@ public class GridFragment extends AppbarFragment {
            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() {
+166 −38
Original line number Diff line number Diff line
@@ -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 android.widget.ImageView;
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.customization.module.ThemesUserEventLogger;
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 @@ public class GridFullPreviewFragment extends AppbarFragment {

    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 @@ public class GridFullPreviewFragment extends AppbarFragment {
        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 @@ public class GridFullPreviewFragment extends AppbarFragment {
        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,15 +148,18 @@ public class GridFullPreviewFragment extends AppbarFragment {
                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());
@@ -142,6 +168,32 @@ public class GridFullPreviewFragment extends AppbarFragment {
        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 @@ public class GridFullPreviewFragment extends AppbarFragment {
        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 @@ public class GridFullPreviewFragment extends AppbarFragment {
        }
    }

    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 void setUpLiveWallpaperPreview(WallpaperInfo homeWallpaper) {
        Activity activity = getActivity();
        if (activity == null) {
            return;
        }

        if (mWallpaperConnection != null) {
            mWallpaperConnection.disconnect();
        }

    private final SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
        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 @@ public class GridFullPreviewFragment extends AppbarFragment {
            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 @@ public class GridFullPreviewFragment extends AppbarFragment {
        }

        @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 @@ public class GridFullPreviewFragment extends AppbarFragment {
            }
        }
    };

    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) {}
    };
}