| /* |
| * 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.customization.picker; |
| |
| import android.app.Activity; |
| import android.app.WallpaperColors; |
| import android.content.Intent; |
| import android.graphics.Rect; |
| import android.graphics.RenderEffect; |
| import android.graphics.Shader.TileMode; |
| import android.service.wallpaper.WallpaperService; |
| import android.view.Surface; |
| import android.view.SurfaceView; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.widget.ImageView; |
| |
| import androidx.annotation.MainThread; |
| import androidx.annotation.Nullable; |
| import androidx.cardview.widget.CardView; |
| import androidx.lifecycle.Lifecycle; |
| import androidx.lifecycle.LifecycleObserver; |
| import androidx.lifecycle.OnLifecycleEvent; |
| |
| import com.android.wallpaper.model.LiveWallpaperInfo; |
| import com.android.wallpaper.model.WallpaperInfo; |
| import com.android.wallpaper.util.ResourceUtils; |
| import com.android.wallpaper.util.ScreenSizeCalculator; |
| import com.android.wallpaper.util.SizeCalculator; |
| import com.android.wallpaper.util.VideoWallpaperUtils; |
| import com.android.wallpaper.util.WallpaperConnection; |
| import com.android.wallpaper.util.WallpaperConnection.WallpaperConnectionListener; |
| import com.android.wallpaper.util.WallpaperSurfaceCallback; |
| import com.android.wallpaper.widget.WallpaperColorsLoader; |
| |
| /** A class to load the wallpaper to the view. */ |
| public class WallpaperPreviewer implements LifecycleObserver { |
| |
| private final Rect mPreviewLocalRect = new Rect(); |
| private final Rect mPreviewGlobalRect = new Rect(); |
| private final int[] mLivePreviewLocation = new int[2]; |
| |
| private final Activity mActivity; |
| private final ImageView mHomePreview; |
| private final SurfaceView mWallpaperSurface; |
| @Nullable private final ImageView mFadeInScrim; |
| |
| private WallpaperSurfaceCallback mWallpaperSurfaceCallback; |
| private WallpaperInfo mWallpaper; |
| private WallpaperConnection mWallpaperConnection; |
| @Nullable private WallpaperColorsListener mWallpaperColorsListener; |
| |
| /** Interface for getting {@link WallpaperColors} from wallpaper. */ |
| public interface WallpaperColorsListener { |
| /** Gets called when wallpaper color is available or updated. */ |
| void onWallpaperColorsChanged(WallpaperColors colors); |
| } |
| |
| public WallpaperPreviewer(Lifecycle lifecycle, Activity activity, ImageView homePreview, |
| SurfaceView wallpaperSurface) { |
| this(lifecycle, activity, homePreview, wallpaperSurface, null); |
| } |
| |
| public WallpaperPreviewer(Lifecycle lifecycle, Activity activity, ImageView homePreview, |
| SurfaceView wallpaperSurface, @Nullable ImageView fadeInScrim) { |
| lifecycle.addObserver(this); |
| |
| mActivity = activity; |
| mHomePreview = homePreview; |
| mWallpaperSurface = wallpaperSurface; |
| mFadeInScrim = fadeInScrim; |
| mWallpaperSurfaceCallback = new WallpaperSurfaceCallback(activity, mHomePreview, |
| mWallpaperSurface, this::setUpWallpaperPreview); |
| mWallpaperSurface.setZOrderMediaOverlay(true); |
| mWallpaperSurface.getHolder().addCallback(mWallpaperSurfaceCallback); |
| |
| View rootView = homePreview.getRootView(); |
| rootView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { |
| @Override |
| public void onLayoutChange(View v, int left, int top, int right, int bottom, |
| int oldLeft, int oldTop, int oldRight, int oldBottom) { |
| updatePreviewCardRadius(); |
| rootView.removeOnLayoutChangeListener(this); |
| } |
| }); |
| } |
| |
| @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) |
| @MainThread |
| public void onResume() { |
| if (mWallpaperConnection != null) { |
| mWallpaperConnection.setVisibility(true); |
| } |
| } |
| |
| @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) |
| @MainThread |
| public void onPause() { |
| if (mWallpaperConnection != null) { |
| mWallpaperConnection.setVisibility(false); |
| } |
| } |
| |
| @OnLifecycleEvent(Lifecycle.Event.ON_STOP) |
| @MainThread |
| public void onStop() { |
| if (mWallpaperConnection != null) { |
| mWallpaperConnection.disconnect(); |
| mWallpaperConnection = null; |
| } |
| } |
| |
| @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) |
| @MainThread |
| public void onDestroy() { |
| if (mWallpaperConnection != null) { |
| mWallpaperConnection.disconnect(); |
| mWallpaperConnection = null; |
| } |
| |
| mWallpaperSurfaceCallback.cleanUp(); |
| mWallpaperSurface.getHolder().removeCallback(mWallpaperSurfaceCallback); |
| Surface surface = mWallpaperSurface.getHolder().getSurface(); |
| if (surface != null) { |
| surface.release(); |
| } |
| } |
| |
| /** |
| * Sets a wallpaper to be shown on preview screen. |
| * |
| * @param wallpaperInfo the wallpaper to preview |
| * @param listener the listener for getting the wallpaper color of {@param wallpaperInfo} |
| */ |
| public void setWallpaper(WallpaperInfo wallpaperInfo, |
| @Nullable WallpaperColorsListener listener) { |
| mWallpaper = wallpaperInfo; |
| mWallpaperColorsListener = listener; |
| if (mFadeInScrim != null && VideoWallpaperUtils.needsFadeIn(wallpaperInfo)) { |
| mFadeInScrim.animate().cancel(); |
| mFadeInScrim.setAlpha(1f); |
| mFadeInScrim.setVisibility(View.VISIBLE); |
| } |
| setUpWallpaperPreview(); |
| } |
| |
| private void setUpWallpaperPreview() { |
| ImageView homeImageWallpaper = mWallpaperSurfaceCallback.getHomeImageWallpaper(); |
| if (mWallpaper != null && homeImageWallpaper != null) { |
| homeImageWallpaper.post(() -> { |
| if (mActivity == null || mActivity.isDestroyed()) { |
| return; |
| } |
| boolean renderInImageWallpaperSurface = !(mWallpaper instanceof LiveWallpaperInfo); |
| mWallpaper.getThumbAsset(mActivity.getApplicationContext()) |
| .loadPreviewImage(mActivity, |
| renderInImageWallpaperSurface ? homeImageWallpaper : mHomePreview, |
| ResourceUtils.getColorAttr( |
| mActivity, android.R.attr.colorSecondary), |
| /* offsetToStart= */ true); |
| if (mWallpaper instanceof LiveWallpaperInfo) { |
| ImageView preview = homeImageWallpaper; |
| if (VideoWallpaperUtils.needsFadeIn(mWallpaper) && mFadeInScrim != null) { |
| preview = mFadeInScrim; |
| preview.setRenderEffect( |
| RenderEffect.createBlurEffect(150f, 150f, TileMode.CLAMP)); |
| } |
| mWallpaper.getThumbAsset(mActivity.getApplicationContext()) |
| .loadPreviewImage( |
| mActivity, |
| preview, |
| ResourceUtils.getColorAttr( |
| mActivity, android.R.attr.colorSecondary), |
| /* offsetToStart= */ true); |
| setUpLiveWallpaperPreview(mWallpaper); |
| } else { |
| // Ensure live wallpaper connection is disconnected. |
| if (mWallpaperConnection != null) { |
| mWallpaperConnection.disconnect(); |
| mWallpaperConnection = null; |
| } |
| |
| // Load wallpaper color for static wallpaper. |
| if (mWallpaperColorsListener != null) { |
| WallpaperColorsLoader.getWallpaperColors( |
| mActivity, |
| mWallpaper.getThumbAsset(mActivity), |
| mWallpaperColorsListener::onWallpaperColorsChanged); |
| } |
| } |
| }); |
| } |
| } |
| |
| private void setUpLiveWallpaperPreview(WallpaperInfo homeWallpaper) { |
| if (mActivity == null || mActivity.isFinishing()) { |
| return; |
| } |
| |
| if (mWallpaperConnection != null) { |
| mWallpaperConnection.disconnect(); |
| } |
| if (WallpaperConnection.isPreviewAvailable()) { |
| 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()), mActivity, |
| new WallpaperConnectionListener() { |
| @Override |
| public void onWallpaperColorsChanged(WallpaperColors colors, |
| int displayId) { |
| if (mWallpaperColorsListener != null) { |
| mWallpaperColorsListener.onWallpaperColorsChanged(colors); |
| } |
| } |
| |
| @Override |
| public void onEngineShown() { |
| if (mFadeInScrim != null && VideoWallpaperUtils.needsFadeIn( |
| homeWallpaper)) { |
| mFadeInScrim.animate().alpha(0.0f) |
| .setDuration(VideoWallpaperUtils.TRANSITION_MILLIS) |
| .withEndAction( |
| () -> mFadeInScrim.setVisibility(View.INVISIBLE)); |
| } |
| } |
| }, mWallpaperSurface); |
| |
| mWallpaperConnection.setVisibility(true); |
| mHomePreview.post(() -> { |
| if (mWallpaperConnection != null && !mWallpaperConnection.connect()) { |
| mWallpaperConnection = null; |
| } |
| }); |
| } else { |
| // Load wallpaper color from the thumbnail. |
| if (mWallpaperColorsListener != null) { |
| WallpaperColorsLoader.getWallpaperColors( |
| mActivity, |
| mWallpaper.getThumbAsset(mActivity), |
| mWallpaperColorsListener::onWallpaperColorsChanged); |
| } |
| } |
| } |
| |
| /** Updates the preview card view corner radius to match the device corner radius. */ |
| private void updatePreviewCardRadius() { |
| final float screenAspectRatio = |
| ScreenSizeCalculator.getInstance().getScreenAspectRatio(mActivity); |
| CardView cardView = (CardView) mHomePreview.getParent(); |
| final int cardWidth = (int) (cardView.getMeasuredHeight() / screenAspectRatio); |
| ViewGroup.LayoutParams layoutParams = cardView.getLayoutParams(); |
| layoutParams.width = cardWidth; |
| cardView.setLayoutParams(layoutParams); |
| cardView.setRadius(SizeCalculator.getPreviewCornerRadius(mActivity, cardWidth)); |
| } |
| |
| private static Intent getWallpaperIntent(android.app.WallpaperInfo info) { |
| return new Intent(WallpaperService.SERVICE_INTERFACE) |
| .setClassName(info.getPackageName(), info.getServiceName()); |
| } |
| } |