Improve wallpaper preview loading transition
- Fix WallpaperPreviewBitmapTransformation rounding error when scaling
- Precompute the thumbnail background color to use as placeholder if
possible
- Allow the placeholder to be serialized in WallpaperInfo so it's
available when opening the preview
- If available, obtain a low res preview as bitmap
- Remove unused views from wallpaper_preview_card
- Make TouchForwardingLayout transparent from loading to avoid it
showing in the fragment transition
Before/after videos: https://drive.google.com/drive/folders/1-PqL0BCOuet9pnrYVphewpwAcvVoBCwo?usp=sharing
Bug: 184111918
Test: visual check
Change-Id: Icaabafd5c430a0324899e471aa8f28453ab04f1a
diff --git a/src/com/android/wallpaper/picker/ImagePreviewFragment.java b/src/com/android/wallpaper/picker/ImagePreviewFragment.java
index 6fbfd43..feb3699 100755
--- a/src/com/android/wallpaper/picker/ImagePreviewFragment.java
+++ b/src/com/android/wallpaper/picker/ImagePreviewFragment.java
@@ -78,6 +78,8 @@
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
import java.util.Locale;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -107,11 +109,13 @@
protected WorkspaceSurfaceHolderCallback mWorkspaceSurfaceCallback;
protected ViewGroup mLockPreviewContainer;
protected LockScreenPreviewer mLockScreenPreviewer;
+ private Future<Integer> mPlaceholderColorFuture;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mWallpaperAsset = mWallpaper.getAsset(requireContext().getApplicationContext());
+ mPlaceholderColorFuture = mWallpaper.computePlaceholderColor(requireContext());
}
@Override
@@ -120,11 +124,6 @@
}
@Override
- protected int getLoadingIndicatorResId() {
- return R.id.loading_indicator;
- }
-
- @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
@@ -133,10 +132,6 @@
mScreenSize = ScreenSizeCalculator.getInstance().getScreenSize(
activity.getWindowManager().getDefaultDisplay());
- // TODO: Consider moving some part of this to the base class when live preview is ready.
- view.findViewById(R.id.low_res_image).setVisibility(View.GONE);
- view.findViewById(R.id.full_res_image).setVisibility(View.GONE);
- mLoadingProgressBar.hide();
mContainer = view.findViewById(R.id.container);
mTouchForwardingLayout = mContainer.findViewById(R.id.touch_forwarding_layout);
mTouchForwardingLayout.setForwardingEnabled(true);
@@ -152,6 +147,9 @@
mWorkspaceSurfaceCallback = createWorkspaceSurfaceCallback(mWorkspaceSurface);
mWallpaperSurface = mContainer.findViewById(R.id.wallpaper_surface);
mLockPreviewContainer = mContainer.findViewById(R.id.lock_screen_preview_container);
+ int placeHolderColor = ResourceUtils.getColorAttr(getContext(),
+ android.R.attr.colorBackground);
+ mWorkspaceSurface.setResizeBackgroundColor(placeHolderColor);
mLockScreenPreviewer = new LockScreenPreviewer(getLifecycle(), getContext(),
mLockPreviewContainer);
mLockScreenPreviewer.setDateViewVisibility(!mFullScreenAnimation.isFullScreen());
@@ -170,7 +168,6 @@
// Trim some memory from Glide to make room for the full-size image in this fragment.
Glide.get(activity).setMemoryCategory(MemoryCategory.LOW);
- setUpLoadingIndicator();
return view;
}
@@ -178,27 +175,6 @@
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- mWallpaperAsset.decodeRawDimensions(getActivity(), dimensions -> {
- // Don't continue loading the wallpaper if the Fragment is detached.
- if (getActivity() == null) {
- return;
- }
-
- // Return early and show a dialog if dimensions are null (signaling a decoding error).
- if (dimensions == null) {
- showLoadWallpaperErrorDialog();
- return;
- }
-
- // To avoid applying the wallpaper when it's not parsed. Now it's parsed, enable the
- // bottom action bar to allow applying the wallpaper.
- if (mBottomActionBar != null) {
- mBottomActionBar.enableActions();
- }
-
- mRawWallpaperSize = dimensions;
- initFullResView();
- });
}
protected void onWallpaperColorsChanged(@Nullable WallpaperColors colors) {
@@ -230,9 +206,6 @@
@Override
public void onDestroy() {
super.onDestroy();
- if (mLoadingProgressBar != null) {
- mLoadingProgressBar.hide();
- }
if (mFullResImageView != null) {
mFullResImageView.recycle();
@@ -303,14 +276,6 @@
// disallow user to pan outside the view we show the wallpaper in.
mFullResImageView.setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE);
- // Set a solid black "page bitmap" so MosaicView draws a black background while waiting
- // for the image to load or a transparent one if a thumbnail already loaded.
- Bitmap backgroundBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
- int preColor = ResourceUtils.getColorAttr(getActivity(), android.R.attr.colorSecondary);
- int color = (mLowResImageView.getDrawable() == null) ? preColor : Color.TRANSPARENT;
- backgroundBitmap.setPixel(0, 0, color);
- mFullResImageView.setImage(ImageSource.bitmap(backgroundBitmap));
-
// Then set a fallback "page bitmap" to cover the whole MosaicView, which is an actual
// (lower res) version of the image to be displayed.
Point targetPageBitmapSize = new Point(mRawWallpaperSize);
@@ -321,17 +286,15 @@
return;
}
- // Some of these may be null depending on if the Fragment is paused, stopped,
- // or destroyed.
- if (mLoadingProgressBar != null) {
- mLoadingProgressBar.hide();
- }
// The page bitmap may be null if there was a decoding error, so show an
// error dialog.
if (pageBitmap == null) {
showLoadWallpaperErrorDialog();
return;
}
+ // Some of these may be null depending on if the Fragment is paused, stopped,
+ // or destroyed.
+ mWallpaperSurface.setBackgroundColor(Color.TRANSPARENT);
if (mFullResImageView != null) {
// Set page bitmap.
mFullResImageView.setImage(ImageSource.bitmap(pageBitmap));
@@ -424,6 +387,7 @@
mFullResImageView.setAlpha(0f);
mFullResImageView.animate()
.alpha(1f)
+ .setInterpolator(ALPHA_OUT)
.setDuration(shortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
@Override
@@ -435,18 +399,6 @@
}
}
});
-
- mLoadingProgressBar.animate()
- .alpha(0f)
- .setDuration(shortAnimationDuration)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mLoadingProgressBar != null) {
- mLoadingProgressBar.hide();
- }
- }
- });
}
/**
@@ -512,9 +464,8 @@
Resources res = appContext.getResources();
Point cropSurfaceSize = WallpaperCropUtils.calculateCropSurfaceSize(res, maxCrop, minCrop);
- Rect cropRect = WallpaperCropUtils.calculateCropRect(appContext, hostViewSize,
+ return WallpaperCropUtils.calculateCropRect(appContext, hostViewSize,
cropSurfaceSize, mRawWallpaperSize, visibleFileRect, wallpaperZoom);
- return cropRect;
}
@Override
@@ -559,7 +510,28 @@
R.layout.fullscreen_wallpaper_preview, null);
mFullResImageView = wallpaperPreviewContainer.findViewById(R.id.full_res_image);
mLowResImageView = wallpaperPreviewContainer.findViewById(R.id.low_res_image);
- initFullResView();
+ mWallpaperAsset.decodeRawDimensions(getActivity(), dimensions -> {
+ // Don't continue loading the wallpaper if the Fragment is detached.
+ if (getActivity() == null) {
+ return;
+ }
+
+ // Return early and show a dialog if dimensions are null (signaling a decoding
+ // error).
+ if (dimensions == null) {
+ showLoadWallpaperErrorDialog();
+ return;
+ }
+
+ // To avoid applying the wallpaper when it's not parsed. Now it's parsed, enable
+ // the bottom action bar to allow applying the wallpaper.
+ if (mBottomActionBar != null) {
+ mBottomActionBar.enableActions();
+ }
+
+ mRawWallpaperSize = dimensions;
+ initFullResView();
+ });
// Scale the mWallpaperSurface based on system zoom's scale so that the wallpaper is
// rendered in a larger surface than what preview shows, simulating the behavior of
// the actual wallpaper surface.
@@ -585,12 +557,23 @@
// Load a low-res placeholder image if there's a thumbnail available from the asset
// that can be shown to the user more quickly than the full-sized image.
- if (mWallpaperAsset.hasLowResDataSource()) {
- Activity activity = requireActivity();
- mWallpaperAsset.loadLowResDrawable(activity, mLowResImageView, Color.BLACK,
- new WallpaperPreviewBitmapTransformation(
- activity.getApplicationContext(), isRtl()));
+ Activity activity = requireActivity();
+ int placeHolderColor = ResourceUtils.getColorAttr(activity,
+ android.R.attr.colorBackground);
+ if (mPlaceholderColorFuture.isDone()) {
+ try {
+ placeHolderColor = mWallpaper.computePlaceholderColor(context).get();
+ } catch (InterruptedException | ExecutionException e) {
+ // Do nothing
+ }
}
+ mWallpaperSurface.setResizeBackgroundColor(placeHolderColor);
+ mWallpaperSurface.setBackgroundColor(placeHolderColor);
+
+ mWallpaperAsset.loadLowResDrawable(activity, mLowResImageView, placeHolderColor,
+ new WallpaperPreviewBitmapTransformation(
+ activity.getApplicationContext(), isRtl()));
+
wallpaperPreviewContainer.measure(
makeMeasureSpec(width, EXACTLY),
makeMeasureSpec(height, EXACTLY));