blob: 7e9979717c5aa4e35f70793338564f75db6a78c1 [file] [log] [blame]
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.wallpaper.picker;
17
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070018import static android.view.View.MeasureSpec.EXACTLY;
19import static android.view.View.MeasureSpec.makeMeasureSpec;
20
21import static com.android.wallpaper.widget.BottomActionBar.BottomAction.APPLY;
22import static com.android.wallpaper.widget.BottomActionBar.BottomAction.EDIT;
23import static com.android.wallpaper.widget.BottomActionBar.BottomAction.INFORMATION;
24
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070025import android.animation.Animator;
26import android.animation.AnimatorListenerAdapter;
27import android.app.Activity;
Chihhang Chuang58bd0ca2021-04-27 00:41:13 +080028import android.app.WallpaperColors;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070029import android.content.Context;
Santiago Etchebeheref172aef2020-07-04 18:48:35 -070030import android.content.res.Resources;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070031import android.graphics.Bitmap;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070032import android.graphics.Color;
33import android.graphics.Point;
34import android.graphics.PointF;
35import android.graphics.Rect;
36import android.os.Bundle;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070037import android.view.LayoutInflater;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070038import android.view.Surface;
39import android.view.SurfaceControlViewHost;
40import android.view.SurfaceHolder;
41import android.view.SurfaceView;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070042import android.view.View;
43import android.view.ViewGroup;
Santiago Etchebehere8557c462020-12-02 18:41:40 -080044import android.view.ViewGroup.LayoutParams;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070045import android.widget.ImageView;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070046
Chuck Liaofc1b8c92020-05-21 20:54:15 +080047import androidx.annotation.NonNull;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070048import androidx.annotation.Nullable;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070049import androidx.cardview.widget.CardView;
Tracy Zhou3eb234c2020-05-05 15:17:33 -070050import androidx.constraintlayout.widget.ConstraintLayout;
51import androidx.constraintlayout.widget.ConstraintSet;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070052import androidx.fragment.app.FragmentActivity;
53
54import com.android.wallpaper.R;
55import com.android.wallpaper.asset.Asset;
Chuck Liaodc424e82020-09-04 00:17:44 +080056import com.android.wallpaper.asset.CurrentWallpaperAssetVN;
“Chuckffd832c2020-03-22 02:15:58 +080057import com.android.wallpaper.model.WallpaperInfo;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070058import com.android.wallpaper.module.WallpaperPersister.Destination;
59import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback;
Tianguang Zhangd3e4f632021-04-14 00:30:15 +020060import com.android.wallpaper.util.ResourceUtils;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070061import com.android.wallpaper.util.ScreenSizeCalculator;
Santiago Etchebehere53c63432020-05-07 18:55:35 -070062import com.android.wallpaper.util.SizeCalculator;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070063import com.android.wallpaper.util.WallpaperCropUtils;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070064import com.android.wallpaper.widget.BottomActionBar;
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +080065import com.android.wallpaper.widget.BottomActionBar.AccessibilityCallback;
Chihhang Chuanga70d90e2021-04-09 15:42:27 +080066import com.android.wallpaper.widget.LockScreenPreviewer2;
Chuck Liaofc1b8c92020-05-21 20:54:15 +080067import com.android.wallpaper.widget.WallpaperColorsLoader;
Tracy Zhou35997422020-05-01 13:42:06 -070068import com.android.wallpaper.widget.WallpaperInfoView;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070069
70import com.bumptech.glide.Glide;
71import com.bumptech.glide.MemoryCategory;
72import com.davemorrissey.labs.subscaleview.ImageSource;
73import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
chihhangchuang45d94132020-07-08 16:18:37 +080074import com.google.android.material.tabs.TabLayout;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070075
chihhangchuang923e29b2020-07-02 19:09:36 +080076import java.util.Locale;
77
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070078/**
Santiago Etchebehere4ecb6aa2019-11-07 11:48:58 -080079 * Fragment which displays the UI for previewing an individual static wallpaper and its attribution
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070080 * information.
81 */
Chihhang Chuang58bd0ca2021-04-27 00:41:13 +080082public class ImagePreviewFragment extends PreviewFragment implements WallpaperColorsLoader.Callback{
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070083
84 private static final float DEFAULT_WALLPAPER_MAX_ZOOM = 8f;
85
Tracy Zhou4421a3d2020-06-15 14:56:18 -070086 private final WallpaperSurfaceCallback mWallpaperSurfaceCallback =
87 new WallpaperSurfaceCallback();
Tracy Zhouc5a6bad2020-05-20 23:28:22 -070088
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070089 private SubsamplingScaleImageView mFullResImageView;
90 private Asset mWallpaperAsset;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070091 private Point mScreenSize;
92 private Point mRawWallpaperSize; // Native size of wallpaper image.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070093 private ImageView mLowResImageView;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070094 private TouchForwardingLayout mTouchForwardingLayout;
Tracy Zhou3eb234c2020-05-05 15:17:33 -070095 private ConstraintLayout mContainer;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070096 private SurfaceView mWorkspaceSurface;
Tracy Zhou3eb234c2020-05-05 15:17:33 -070097 private WorkspaceSurfaceHolderCallback mWorkspaceSurfaceCallback;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070098 private SurfaceView mWallpaperSurface;
Tracy Zhou35997422020-05-01 13:42:06 -070099 private WallpaperInfoView mWallpaperInfoView;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700100
Chihhang Chuang58bd0ca2021-04-27 00:41:13 +0800101 protected ViewGroup mLockPreviewContainer;
102 protected LockScreenPreviewer2 mLockScreenPreviewer;
Chihhang Chuang57daaa92021-04-20 21:40:01 +0800103
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700104 @Override
105 public void onCreate(Bundle savedInstanceState) {
106 super.onCreate(savedInstanceState);
107 mWallpaperAsset = mWallpaper.getAsset(requireContext().getApplicationContext());
108 }
109
110 @Override
111 protected int getLayoutResId() {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700112 return R.layout.fragment_image_preview_v2;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700113 }
114
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700115 @Override
Santiago Etchebeheredc55b192019-11-08 13:56:52 -0800116 protected int getLoadingIndicatorResId() {
117 return R.id.loading_indicator;
118 }
119
120 @Override
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700121 public View onCreateView(LayoutInflater inflater, ViewGroup container,
Michel Comin Escudeb3e1fef2019-11-22 11:41:53 -0800122 Bundle savedInstanceState) {
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700123 View view = super.onCreateView(inflater, container, savedInstanceState);
124
125 Activity activity = requireActivity();
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700126 mScreenSize = ScreenSizeCalculator.getInstance().getScreenSize(
127 activity.getWindowManager().getDefaultDisplay());
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700128
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700129 // TODO: Consider moving some part of this to the base class when live preview is ready.
130 view.findViewById(R.id.low_res_image).setVisibility(View.GONE);
131 view.findViewById(R.id.full_res_image).setVisibility(View.GONE);
132 mLoadingProgressBar.hide();
133 mContainer = view.findViewById(R.id.container);
134 mTouchForwardingLayout = mContainer.findViewById(R.id.touch_forwarding_layout);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700135
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700136 // Set aspect ratio on the preview card dynamically.
137 ConstraintSet set = new ConstraintSet();
138 set.clone(mContainer);
chihhangchuang923e29b2020-07-02 19:09:36 +0800139 String ratio = String.format(Locale.US, "%d:%d", mScreenSize.x, mScreenSize.y);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700140 set.setDimensionRatio(mTouchForwardingLayout.getId(), ratio);
141 set.applyTo(mContainer);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700142
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700143 mWorkspaceSurface = mContainer.findViewById(R.id.workspace_surface);
144 mWorkspaceSurfaceCallback = new WorkspaceSurfaceHolderCallback(mWorkspaceSurface,
145 getContext());
146 mWallpaperSurface = mContainer.findViewById(R.id.wallpaper_surface);
chihhangchuang287d4b72020-06-25 01:09:09 +0800147 mLockPreviewContainer = mContainer.findViewById(R.id.lock_screen_preview_container);
Chihhang Chuanga70d90e2021-04-09 15:42:27 +0800148 mLockScreenPreviewer = new LockScreenPreviewer2(getLifecycle(), getContext(),
chihhangchuang287d4b72020-06-25 01:09:09 +0800149 mLockPreviewContainer);
Chuck Liaofc1b8c92020-05-21 20:54:15 +0800150
Chihhang Chuang58bd0ca2021-04-27 00:41:13 +0800151 setUpTabs(view.findViewById(R.id.pill_tabs));
chihhangchuang45d94132020-07-08 16:18:37 +0800152 updateScreenPreview(mViewAsHome);
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700153
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700154 view.measure(makeMeasureSpec(mScreenSize.x, EXACTLY),
155 makeMeasureSpec(mScreenSize.y, EXACTLY));
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700156 ((CardView) mWorkspaceSurface.getParent())
157 .setRadius(SizeCalculator.getPreviewCornerRadius(
158 activity, mContainer.getMeasuredWidth()));
Chihhang Chuang57daaa92021-04-20 21:40:01 +0800159
Chihhang Chuang58bd0ca2021-04-27 00:41:13 +0800160 renderImageWallpaper();
161 renderWorkspaceSurface();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700162
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700163 // Trim some memory from Glide to make room for the full-size image in this fragment.
164 Glide.get(activity).setMemoryCategory(MemoryCategory.LOW);
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800165 setUpLoadingIndicator();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700166 return view;
167 }
168
Santiago Etchebehere4ecb6aa2019-11-07 11:48:58 -0800169 @Override
Chuck Liaofc1b8c92020-05-21 20:54:15 +0800170 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
171 super.onViewCreated(view, savedInstanceState);
Chihhang Chuang58bd0ca2021-04-27 00:41:13 +0800172 WallpaperColorsLoader.getWallpaperColors(getContext(),
173 mWallpaper.getThumbAsset(getContext()), this);
174 }
175
176 @Override
177 public void onLoaded(@Nullable WallpaperColors colors) {
178 mLockScreenPreviewer.setColor(colors);
Santiago Etchebehere4ecb6aa2019-11-07 11:48:58 -0800179 }
180
Santiago Etchebeheredc55b192019-11-08 13:56:52 -0800181 @Override
182 protected boolean isLoaded() {
183 return mFullResImageView != null && mFullResImageView.hasImage();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700184 }
185
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700186 @Override
187 public void onClickOk() {
188 FragmentActivity activity = getActivity();
189 if (activity != null) {
190 activity.finish();
191 }
192 }
193
194 @Override
195 public void onDestroy() {
196 super.onDestroy();
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800197 if (mLoadingProgressBar != null) {
198 mLoadingProgressBar.hide();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700199 }
Chihhang Chuang57daaa92021-04-20 21:40:01 +0800200
201 if (mFullResImageView != null) {
202 mFullResImageView.recycle();
203 }
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700204
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700205 mWallpaperSurfaceCallback.cleanUp();
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700206 mWorkspaceSurfaceCallback.cleanUp();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700207 }
208
209 @Override
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700210 protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700211 super.onBottomActionBarReady(bottomActionBar);
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700212
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700213 mWallpaperInfoView = (WallpaperInfoView)
214 LayoutInflater.from(getContext()).inflate(
215 R.layout.wallpaper_info_view, /* root= */null);
216 mBottomActionBar.attachViewToBottomSheetAndBindAction(mWallpaperInfoView, INFORMATION);
217 mBottomActionBar.showActionsOnly(INFORMATION, EDIT, APPLY);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700218 mBottomActionBar.setActionClickListener(EDIT, v ->
Tracy Zhou16112e32020-05-27 13:13:23 -0700219 setEditingEnabled(mBottomActionBar.isActionSelected(EDIT))
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700220 );
Chihhang Chuangca7c8252020-06-17 17:32:46 +0800221 mBottomActionBar.setActionSelectedListener(EDIT, this::setEditingEnabled);
222 mBottomActionBar.setActionClickListener(APPLY, this::onSetWallpaperClicked);
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +0800223
224 // Update target view's accessibility param since it will be blocked by the bottom sheet
225 // when expanded.
226 mBottomActionBar.setAccessibilityCallback(new AccessibilityCallback() {
227 @Override
228 public void onBottomSheetCollapsed() {
Wesley.CW Wangb8e51a22020-07-02 18:40:31 +0800229 mContainer.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +0800230 }
231
232 @Override
233 public void onBottomSheetExpanded() {
Wesley.CW Wangb8e51a22020-07-02 18:40:31 +0800234 mContainer.setImportantForAccessibility(
235 View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +0800236 }
237 });
238
Chihhang Chuangca7c8252020-06-17 17:32:46 +0800239 // Will trigger onActionSelected callback to update the editing state.
240 mBottomActionBar.setDefaultSelectedButton(EDIT);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700241 mBottomActionBar.show();
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700242
chihhangchuang13cb1fe2020-06-30 16:46:59 +0800243 mBottomActionBar.disableActions();
244 mWallpaperAsset.decodeRawDimensions(getActivity(), dimensions -> {
chihhangchuang13cb1fe2020-06-30 16:46:59 +0800245 // Don't continue loading the wallpaper if the Fragment is detached.
246 if (getActivity() == null) {
247 return;
248 }
249
250 // Return early and show a dialog if dimensions are null (signaling a decoding error).
251 if (dimensions == null) {
252 showLoadWallpaperErrorDialog();
253 return;
254 }
255
Chuck Liaoce7f08d2020-09-22 14:39:38 +0800256 if (mBottomActionBar != null) {
257 mBottomActionBar.enableActions();
258 }
259
chihhangchuang13cb1fe2020-06-30 16:46:59 +0800260 mRawWallpaperSize = dimensions;
261
262 setUpExploreIntentAndLabel(ImagePreviewFragment.this::initFullResView);
263 });
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700264 }
265
Chihhang Chuang58bd0ca2021-04-27 00:41:13 +0800266 protected void setUpTabs(TabLayout tabs) {
267 tabs.addTab(tabs.newTab().setText(getContext().getString(R.string.home_screen_message)));
268 tabs.addTab(tabs.newTab().setText(getContext().getString(R.string.lock_screen_message)));
269 tabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
270 @Override
271 public void onTabSelected(TabLayout.Tab tab) {
272 updateScreenPreview(tab.getPosition() == 0);
273 }
274
275 @Override
276 public void onTabUnselected(TabLayout.Tab tab) {}
277
278 @Override
279 public void onTabReselected(TabLayout.Tab tab) {}
280 });
281
282 // The TabLayout only contains below tabs
283 // 0. Home tab
284 // 1. Lock tab
285 tabs.getTabAt(mViewAsHome ? 0 : 1).select();
286 }
287
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700288 /**
289 * Initializes MosaicView by initializing tiling, setting a fallback page bitmap, and
290 * initializing a zoom-scroll observer and click listener.
291 */
292 private void initFullResView() {
Tracy Zhoudee07892020-06-16 20:14:30 -0700293 // Minimum scale will only be respected under this scale type.
294 mFullResImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM);
295 // When we set a minimum scale bigger than the scale with which the full image is shown,
296 // disallow user to pan outside the view we show the wallpaper in.
297 mFullResImageView.setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700298
299 // Set a solid black "page bitmap" so MosaicView draws a black background while waiting
300 // for the image to load or a transparent one if a thumbnail already loaded.
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700301 Bitmap backgroundBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
Tianguang Zhangd3e4f632021-04-14 00:30:15 +0200302 int preColor = ResourceUtils.getColorAttr(getActivity(), android.R.attr.colorSecondary);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700303 int color = (mLowResImageView.getDrawable() == null) ? preColor : Color.TRANSPARENT;
304 backgroundBitmap.setPixel(0, 0, color);
305 mFullResImageView.setImage(ImageSource.bitmap(backgroundBitmap));
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700306
307 // Then set a fallback "page bitmap" to cover the whole MosaicView, which is an actual
308 // (lower res) version of the image to be displayed.
309 Point targetPageBitmapSize = new Point(mRawWallpaperSize);
310 mWallpaperAsset.decodeBitmap(targetPageBitmapSize.x, targetPageBitmapSize.y,
311 pageBitmap -> {
312 // Check that the activity is still around since the decoding task started.
313 if (getActivity() == null) {
314 return;
315 }
316
317 // Some of these may be null depending on if the Fragment is paused, stopped,
318 // or destroyed.
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800319 if (mLoadingProgressBar != null) {
320 mLoadingProgressBar.hide();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700321 }
322 // The page bitmap may be null if there was a decoding error, so show an
323 // error dialog.
324 if (pageBitmap == null) {
325 showLoadWallpaperErrorDialog();
326 return;
327 }
328 if (mFullResImageView != null) {
329 // Set page bitmap.
330 mFullResImageView.setImage(ImageSource.bitmap(pageBitmap));
331
Chuck Liaodc424e82020-09-04 00:17:44 +0800332 setDefaultWallpaperZoomAndScroll(
333 mWallpaperAsset instanceof CurrentWallpaperAssetVN);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700334 crossFadeInMosaicView();
335 }
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700336 getActivity().invalidateOptionsMenu();
337
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700338 if (mWallpaperInfoView != null && mWallpaper != null) {
Chuck Liao9991d682021-01-20 17:45:14 +0800339 mWallpaperInfoView.populateWallpaperInfo(
340 mWallpaper,
341 mActionLabel,
342 WallpaperInfoHelper.shouldShowExploreButton(
343 getContext(), mExploreIntent),
344 this::onExploreClicked);
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700345 }
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700346 });
347 }
348
349 /**
350 * Makes the MosaicView visible with an alpha fade-in animation while fading out the loading
351 * indicator.
352 */
353 private void crossFadeInMosaicView() {
354 long shortAnimationDuration = getResources().getInteger(
355 android.R.integer.config_shortAnimTime);
356
357 mFullResImageView.setAlpha(0f);
358 mFullResImageView.animate()
359 .alpha(1f)
360 .setDuration(shortAnimationDuration)
361 .setListener(new AnimatorListenerAdapter() {
362 @Override
363 public void onAnimationEnd(Animator animation) {
364 // Clear the thumbnail bitmap reference to save memory since it's no longer
365 // visible.
366 if (mLowResImageView != null) {
367 mLowResImageView.setImageBitmap(null);
368 }
369 }
370 });
371
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800372 mLoadingProgressBar.animate()
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700373 .alpha(0f)
374 .setDuration(shortAnimationDuration)
375 .setListener(new AnimatorListenerAdapter() {
376 @Override
377 public void onAnimationEnd(Animator animation) {
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800378 if (mLoadingProgressBar != null) {
379 mLoadingProgressBar.hide();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700380 }
381 }
382 });
383 }
384
385 /**
Michel Comin Escudeb3e1fef2019-11-22 11:41:53 -0800386 * Sets the default wallpaper zoom and scroll position based on a "crop surface" (with extra
387 * width to account for parallax) superimposed on the screen. Shows as much of the wallpaper as
388 * possible on the crop surface and align screen to crop surface such that the default preview
389 * matches what would be seen by the user in the left-most home screen.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700390 *
391 * <p>This method is called once in the Fragment lifecycle after the wallpaper asset has loaded
392 * and rendered to the layout.
Chuck Liaodc424e82020-09-04 00:17:44 +0800393 *
Santiago Etchebehere16cf0602020-12-11 17:04:18 -0800394 * @param offsetToStart {@code true} if we want to offset the visible rectangle to the start
395 * side of the raw wallpaper; {@code false} otherwise.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700396 */
Santiago Etchebehere16cf0602020-12-11 17:04:18 -0800397 private void setDefaultWallpaperZoomAndScroll(boolean offsetToStart) {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700398 // Determine minimum zoom to fit maximum visible area of wallpaper on crop surface.
Santiago Etchebehere8557c462020-12-02 18:41:40 -0800399 int cropWidth = mWallpaperSurface.getMeasuredWidth();
400 int cropHeight = mWallpaperSurface.getMeasuredHeight();
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700401 Point crop = new Point(cropWidth, cropHeight);
402 Rect visibleRawWallpaperRect =
403 WallpaperCropUtils.calculateVisibleRect(mRawWallpaperSize, crop);
Santiago Etchebehere16cf0602020-12-11 17:04:18 -0800404 if (offsetToStart) {
405 if (WallpaperCropUtils.isRtl(requireContext())) {
406 visibleRawWallpaperRect.offsetTo(mRawWallpaperSize.x
407 - visibleRawWallpaperRect.width(), visibleRawWallpaperRect.top);
408 } else {
409 visibleRawWallpaperRect.offsetTo(/* newLeft= */ 0, visibleRawWallpaperRect.top);
410 }
Chuck Liaodc424e82020-09-04 00:17:44 +0800411 }
Santiago Etchebeheree95b6d92020-06-08 14:19:46 -0700412
Santiago Etchebehere8557c462020-12-02 18:41:40 -0800413 final PointF centerPosition = new PointF(visibleRawWallpaperRect.centerX(),
414 visibleRawWallpaperRect.centerY());
Santiago Etchebeheree95b6d92020-06-08 14:19:46 -0700415
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700416 Point visibleRawWallpaperSize = new Point(visibleRawWallpaperRect.width(),
417 visibleRawWallpaperRect.height());
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700418
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700419 final float defaultWallpaperZoom = WallpaperCropUtils.calculateMinZoom(
420 visibleRawWallpaperSize, crop);
421 final float minWallpaperZoom = defaultWallpaperZoom;
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700422
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700423
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700424 // Set min wallpaper zoom and max zoom on MosaicView widget.
425 mFullResImageView.setMaxScale(Math.max(DEFAULT_WALLPAPER_MAX_ZOOM, defaultWallpaperZoom));
426 mFullResImageView.setMinScale(minWallpaperZoom);
427
428 // Set center to composite positioning between scaled wallpaper and screen.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700429 mFullResImageView.setScaleAndCenter(minWallpaperZoom, centerPosition);
430 }
431
432 private Rect calculateCropRect() {
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700433 float wallpaperZoom = mFullResImageView.getScale();
Chuck Liao5182a312020-03-04 20:04:18 +0800434 Context context = requireContext().getApplicationContext();
Tracy Zhou67fd7e32020-05-01 18:35:36 -0700435
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700436 Rect visibleFileRect = new Rect();
437 mFullResImageView.visibleFileRect(visibleFileRect);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700438
Santiago Etchebehere8557c462020-12-02 18:41:40 -0800439 int cropWidth = mWallpaperSurface.getMeasuredWidth();
440 int cropHeight = mWallpaperSurface.getMeasuredHeight();
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700441 int maxCrop = Math.max(cropWidth, cropHeight);
442 int minCrop = Math.min(cropWidth, cropHeight);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700443 Point hostViewSize = new Point(cropWidth, cropHeight);
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700444
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700445 Resources res = context.getResources();
Santiago Etchebeherebcd6bb62020-07-09 12:09:21 -0700446 Point cropSurfaceSize = WallpaperCropUtils.calculateCropSurfaceSize(res, maxCrop, minCrop);
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700447
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700448 Rect cropRect = WallpaperCropUtils.calculateCropRect(context, hostViewSize,
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700449 cropSurfaceSize, mRawWallpaperSize, visibleFileRect, wallpaperZoom);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700450 return cropRect;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700451 }
452
453 @Override
454 protected void setCurrentWallpaper(@Destination int destination) {
455 mWallpaperSetter.setCurrentWallpaper(getActivity(), mWallpaper, mWallpaperAsset,
456 destination, mFullResImageView.getScale(), calculateCropRect(),
457 new SetWallpaperCallback() {
458 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800459 public void onSuccess(WallpaperInfo wallpaperInfo) {
Ching-Sung Lib5e9bd72020-06-15 14:10:55 +0800460 finishActivity(/* success= */ true);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700461 }
462
463 @Override
464 public void onError(@Nullable Throwable throwable) {
465 showSetWallpaperErrorDialog(destination);
466 }
467 });
468 }
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700469
470 private void renderWorkspaceSurface() {
471 mWorkspaceSurface.setZOrderMediaOverlay(true);
472 mWorkspaceSurface.getHolder().addCallback(mWorkspaceSurfaceCallback);
473 }
474
475 private void renderImageWallpaper() {
476 mWallpaperSurface.getHolder().addCallback(mWallpaperSurfaceCallback);
477 }
478
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700479 private class WallpaperSurfaceCallback implements SurfaceHolder.Callback {
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700480
481 private Surface mLastSurface;
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700482 private SurfaceControlViewHost mHost;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700483
484 @Override
485 public void surfaceCreated(SurfaceHolder holder) {
486 if (mLastSurface != holder.getSurface()) {
487 mLastSurface = holder.getSurface();
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700488 if (mFullResImageView != null) {
489 mFullResImageView.recycle();
490 }
Santiago Etchebehere8557c462020-12-02 18:41:40 -0800491 Context context = getContext();
492 View wallpaperPreviewContainer = LayoutInflater.from(context).inflate(
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700493 R.layout.fullscreen_wallpaper_preview, null);
494 mFullResImageView = wallpaperPreviewContainer.findViewById(R.id.full_res_image);
495 mLowResImageView = wallpaperPreviewContainer.findViewById(R.id.low_res_image);
Santiago Etchebehere8557c462020-12-02 18:41:40 -0800496 // Scale the mWallpaperSurface based on system zoom's scale so that the wallpaper is
497 // rendered in a larger surface than what preview shows, simulating the behavior of
498 // the actual wallpaper surface.
499 float scale = WallpaperCropUtils.getSystemWallpaperMaximumScale(context);
500 int origWidth = mWallpaperSurface.getWidth();
501 int width = (int) (origWidth * scale);
502 int origHeight = mWallpaperSurface.getHeight();
503 int height = (int) (origHeight * scale);
504 int left = (origWidth - width) / 2;
505 int top = (origHeight - height) / 2;
506
507 if (WallpaperCropUtils.isRtl(context)) {
508 left *= -1;
509 }
510
511 LayoutParams params = mWallpaperSurface.getLayoutParams();
512 params.width = width;
513 params.height = height;
514 mWallpaperSurface.setX(left);
515 mWallpaperSurface.setY(top);
516 mWallpaperSurface.setLayoutParams(params);
517 mWallpaperSurface.requestLayout();
518
Chuck Liaoca1d1292020-06-19 01:29:53 +0800519 // Load a low-res placeholder image if there's a thumbnail available from the asset
520 // that can be shown to the user more quickly than the full-sized image.
521 if (mWallpaperAsset.hasLowResDataSource()) {
522 Activity activity = requireActivity();
523 mWallpaperAsset.loadLowResDrawable(activity, mLowResImageView, Color.BLACK,
524 new WallpaperPreviewBitmapTransformation(
525 activity.getApplicationContext(), isRtl()));
526 }
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700527 wallpaperPreviewContainer.measure(
Santiago Etchebehere8557c462020-12-02 18:41:40 -0800528 makeMeasureSpec(width, EXACTLY),
529 makeMeasureSpec(height, EXACTLY));
530 wallpaperPreviewContainer.layout(0, 0, width, height);
Ching-Sung Lib9404622020-05-18 22:38:45 +0800531 mTouchForwardingLayout.setTargetView(mFullResImageView);
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700532
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700533 cleanUp();
Santiago Etchebehere8557c462020-12-02 18:41:40 -0800534 mHost = new SurfaceControlViewHost(context,
535 context.getDisplay(), mWallpaperSurface.getHostToken());
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700536 mHost.setView(wallpaperPreviewContainer, wallpaperPreviewContainer.getWidth(),
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700537 wallpaperPreviewContainer.getHeight());
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700538 mWallpaperSurface.setChildSurfacePackage(mHost.getSurfacePackage());
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700539 }
540 }
541
542 @Override
543 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
544
545 @Override
546 public void surfaceDestroyed(SurfaceHolder holder) { }
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700547
548 public void cleanUp() {
549 if (mHost != null) {
550 mHost.release();
551 mHost = null;
552 }
553 }
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700554 };
555
Tracy Zhou67fd7e32020-05-01 18:35:36 -0700556 private void setEditingEnabled(boolean enabled) {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700557 mTouchForwardingLayout.setForwardingEnabled(enabled);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700558 }
559
Wesley.CW Wangf21486b2020-06-02 18:30:32 +0800560 private void updateScreenPreview(boolean isHomeSelected) {
chihhangchuang287d4b72020-06-25 01:09:09 +0800561 mWorkspaceSurface.setVisibility(isHomeSelected ? View.VISIBLE : View.INVISIBLE);
562 mLockPreviewContainer.setVisibility(isHomeSelected ? View.INVISIBLE : View.VISIBLE);
Tracy Zhou67fd7e32020-05-01 18:35:36 -0700563 }
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700564}