blob: 41df2ba45f345595fb64ef84e993df4c09978715 [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;
28import android.content.Context;
Santiago Etchebeheref172aef2020-07-04 18:48:35 -070029import android.content.res.Resources;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070030import android.graphics.Bitmap;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070031import android.graphics.Color;
32import android.graphics.Point;
33import android.graphics.PointF;
34import android.graphics.Rect;
35import android.os.Bundle;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070036import android.view.LayoutInflater;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070037import android.view.Surface;
38import android.view.SurfaceControlViewHost;
39import android.view.SurfaceHolder;
40import android.view.SurfaceView;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070041import android.view.View;
42import android.view.ViewGroup;
43import android.widget.ImageView;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070044
Chuck Liaofc1b8c92020-05-21 20:54:15 +080045import androidx.annotation.NonNull;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070046import androidx.annotation.Nullable;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070047import androidx.cardview.widget.CardView;
Tracy Zhou3eb234c2020-05-05 15:17:33 -070048import androidx.constraintlayout.widget.ConstraintLayout;
49import androidx.constraintlayout.widget.ConstraintSet;
50import androidx.core.content.ContextCompat;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070051import androidx.fragment.app.FragmentActivity;
52
53import com.android.wallpaper.R;
54import com.android.wallpaper.asset.Asset;
“Chuckffd832c2020-03-22 02:15:58 +080055import com.android.wallpaper.model.WallpaperInfo;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070056import com.android.wallpaper.module.WallpaperPersister.Destination;
57import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback;
58import com.android.wallpaper.util.ScreenSizeCalculator;
Santiago Etchebehere53c63432020-05-07 18:55:35 -070059import com.android.wallpaper.util.SizeCalculator;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070060import com.android.wallpaper.util.WallpaperCropUtils;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070061import com.android.wallpaper.widget.BottomActionBar;
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +080062import com.android.wallpaper.widget.BottomActionBar.AccessibilityCallback;
chihhangchuang287d4b72020-06-25 01:09:09 +080063import com.android.wallpaper.widget.LockScreenPreviewer;
Chuck Liaofc1b8c92020-05-21 20:54:15 +080064import com.android.wallpaper.widget.WallpaperColorsLoader;
Tracy Zhou35997422020-05-01 13:42:06 -070065import com.android.wallpaper.widget.WallpaperInfoView;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070066
67import com.bumptech.glide.Glide;
68import com.bumptech.glide.MemoryCategory;
69import com.davemorrissey.labs.subscaleview.ImageSource;
70import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070071
chihhangchuang923e29b2020-07-02 19:09:36 +080072import java.util.Locale;
73
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070074/**
Santiago Etchebehere4ecb6aa2019-11-07 11:48:58 -080075 * Fragment which displays the UI for previewing an individual static wallpaper and its attribution
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070076 * information.
77 */
78public class ImagePreviewFragment extends PreviewFragment {
79
80 private static final float DEFAULT_WALLPAPER_MAX_ZOOM = 8f;
81
Tracy Zhou4421a3d2020-06-15 14:56:18 -070082 private final WallpaperSurfaceCallback mWallpaperSurfaceCallback =
83 new WallpaperSurfaceCallback();
Tracy Zhouc5a6bad2020-05-20 23:28:22 -070084
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070085 private SubsamplingScaleImageView mFullResImageView;
86 private Asset mWallpaperAsset;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070087 private Point mScreenSize;
88 private Point mRawWallpaperSize; // Native size of wallpaper image.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070089 private ImageView mLowResImageView;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070090 private TouchForwardingLayout mTouchForwardingLayout;
Tracy Zhou3eb234c2020-05-05 15:17:33 -070091 private ConstraintLayout mContainer;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070092 private SurfaceView mWorkspaceSurface;
Tracy Zhou3eb234c2020-05-05 15:17:33 -070093 private WorkspaceSurfaceHolderCallback mWorkspaceSurfaceCallback;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070094 private SurfaceView mWallpaperSurface;
chihhangchuang287d4b72020-06-25 01:09:09 +080095 private ViewGroup mLockPreviewContainer;
96 private LockScreenPreviewer mLockScreenPreviewer;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070097 private View mTabs;
Tracy Zhou35997422020-05-01 13:42:06 -070098 private WallpaperInfoView mWallpaperInfoView;
Wesley.CW Wangf21486b2020-06-02 18:30:32 +080099 private View mLock;
100 private View mHome;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700101
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700102 @Override
103 public void onCreate(Bundle savedInstanceState) {
104 super.onCreate(savedInstanceState);
105 mWallpaperAsset = mWallpaper.getAsset(requireContext().getApplicationContext());
106 }
107
108 @Override
109 protected int getLayoutResId() {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700110 return R.layout.fragment_image_preview_v2;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700111 }
112
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700113 @Override
Santiago Etchebeheredc55b192019-11-08 13:56:52 -0800114 protected int getLoadingIndicatorResId() {
115 return R.id.loading_indicator;
116 }
117
118 @Override
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700119 public View onCreateView(LayoutInflater inflater, ViewGroup container,
Michel Comin Escudeb3e1fef2019-11-22 11:41:53 -0800120 Bundle savedInstanceState) {
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700121 View view = super.onCreateView(inflater, container, savedInstanceState);
122
123 Activity activity = requireActivity();
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700124 mScreenSize = ScreenSizeCalculator.getInstance().getScreenSize(
125 activity.getWindowManager().getDefaultDisplay());
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700126
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700127 // TODO: Consider moving some part of this to the base class when live preview is ready.
128 view.findViewById(R.id.low_res_image).setVisibility(View.GONE);
129 view.findViewById(R.id.full_res_image).setVisibility(View.GONE);
130 mLoadingProgressBar.hide();
131 mContainer = view.findViewById(R.id.container);
132 mTouchForwardingLayout = mContainer.findViewById(R.id.touch_forwarding_layout);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700133
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700134 // Set aspect ratio on the preview card dynamically.
135 ConstraintSet set = new ConstraintSet();
136 set.clone(mContainer);
chihhangchuang923e29b2020-07-02 19:09:36 +0800137 String ratio = String.format(Locale.US, "%d:%d", mScreenSize.x, mScreenSize.y);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700138 set.setDimensionRatio(mTouchForwardingLayout.getId(), ratio);
139 set.applyTo(mContainer);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700140
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700141 mWorkspaceSurface = mContainer.findViewById(R.id.workspace_surface);
142 mWorkspaceSurfaceCallback = new WorkspaceSurfaceHolderCallback(mWorkspaceSurface,
143 getContext());
144 mWallpaperSurface = mContainer.findViewById(R.id.wallpaper_surface);
chihhangchuang287d4b72020-06-25 01:09:09 +0800145 mLockPreviewContainer = mContainer.findViewById(R.id.lock_screen_preview_container);
146 mLockScreenPreviewer = new LockScreenPreviewer(getLifecycle(), getActivity(),
147 mLockPreviewContainer);
Chuck Liaofc1b8c92020-05-21 20:54:15 +0800148
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700149 mTabs = view.findViewById(R.id.tabs_container);
Wesley.CW Wangf21486b2020-06-02 18:30:32 +0800150 mLock = mTabs.findViewById(R.id.lock);
151 mHome = mTabs.findViewById(R.id.home);
152 mLock.setOnClickListener(v -> updateScreenPreview(/* isHomeSelected= */ false));
153 mHome.setOnClickListener(v -> updateScreenPreview(/* isHomeSelected= */ true));
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700154
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700155 view.measure(makeMeasureSpec(mScreenSize.x, EXACTLY),
156 makeMeasureSpec(mScreenSize.y, EXACTLY));
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700157
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700158 ((CardView) mWorkspaceSurface.getParent())
159 .setRadius(SizeCalculator.getPreviewCornerRadius(
160 activity, mContainer.getMeasuredWidth()));
161 renderImageWallpaper();
162 renderWorkspaceSurface();
Ching-Sung Liba4f1fe2020-06-10 15:59:15 +0800163 updateScreenPreview(/* isHomeSelected= */ mViewAsHome);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700164
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700165 // Trim some memory from Glide to make room for the full-size image in this fragment.
166 Glide.get(activity).setMemoryCategory(MemoryCategory.LOW);
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800167 setUpLoadingIndicator();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700168 return view;
169 }
170
Santiago Etchebehere4ecb6aa2019-11-07 11:48:58 -0800171 @Override
Chuck Liaofc1b8c92020-05-21 20:54:15 +0800172 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
173 super.onViewCreated(view, savedInstanceState);
chihhangchuang90f902c2020-06-03 16:14:40 +0800174 WallpaperColorsLoader.getWallpaperColors(getContext(),
175 mWallpaper.getThumbAsset(getContext()),
chihhangchuang287d4b72020-06-25 01:09:09 +0800176 mLockScreenPreviewer::setColor);
Santiago Etchebehere4ecb6aa2019-11-07 11:48:58 -0800177 }
178
Santiago Etchebeheredc55b192019-11-08 13:56:52 -0800179 @Override
180 protected boolean isLoaded() {
181 return mFullResImageView != null && mFullResImageView.hasImage();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700182 }
183
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700184 @Override
185 public void onClickOk() {
186 FragmentActivity activity = getActivity();
187 if (activity != null) {
188 activity.finish();
189 }
190 }
191
192 @Override
193 public void onDestroy() {
194 super.onDestroy();
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800195 if (mLoadingProgressBar != null) {
196 mLoadingProgressBar.hide();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700197 }
198 mFullResImageView.recycle();
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700199
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700200 mWallpaperSurfaceCallback.cleanUp();
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700201 mWorkspaceSurfaceCallback.cleanUp();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700202 }
203
204 @Override
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700205 protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700206 super.onBottomActionBarReady(bottomActionBar);
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700207
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700208 mWallpaperInfoView = (WallpaperInfoView)
209 LayoutInflater.from(getContext()).inflate(
210 R.layout.wallpaper_info_view, /* root= */null);
211 mBottomActionBar.attachViewToBottomSheetAndBindAction(mWallpaperInfoView, INFORMATION);
212 mBottomActionBar.showActionsOnly(INFORMATION, EDIT, APPLY);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700213 mBottomActionBar.setActionClickListener(EDIT, v ->
Tracy Zhou16112e32020-05-27 13:13:23 -0700214 setEditingEnabled(mBottomActionBar.isActionSelected(EDIT))
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700215 );
Chihhang Chuangca7c8252020-06-17 17:32:46 +0800216 mBottomActionBar.setActionSelectedListener(EDIT, this::setEditingEnabled);
217 mBottomActionBar.setActionClickListener(APPLY, this::onSetWallpaperClicked);
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +0800218
219 // Update target view's accessibility param since it will be blocked by the bottom sheet
220 // when expanded.
221 mBottomActionBar.setAccessibilityCallback(new AccessibilityCallback() {
222 @Override
223 public void onBottomSheetCollapsed() {
Wesley.CW Wangb8e51a22020-07-02 18:40:31 +0800224 mContainer.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +0800225 mTabs.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
226 }
227
228 @Override
229 public void onBottomSheetExpanded() {
Wesley.CW Wangb8e51a22020-07-02 18:40:31 +0800230 mContainer.setImportantForAccessibility(
231 View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +0800232 mTabs.setImportantForAccessibility(
233 View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
234 }
235 });
236
Chihhang Chuangca7c8252020-06-17 17:32:46 +0800237 // Will trigger onActionSelected callback to update the editing state.
238 mBottomActionBar.setDefaultSelectedButton(EDIT);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700239 mBottomActionBar.show();
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700240
chihhangchuang13cb1fe2020-06-30 16:46:59 +0800241 mBottomActionBar.disableActions();
242 mWallpaperAsset.decodeRawDimensions(getActivity(), dimensions -> {
243 if (mBottomActionBar != null) {
244 mBottomActionBar.enableActions();
245 }
246
247 // Don't continue loading the wallpaper if the Fragment is detached.
248 if (getActivity() == null) {
249 return;
250 }
251
252 // Return early and show a dialog if dimensions are null (signaling a decoding error).
253 if (dimensions == null) {
254 showLoadWallpaperErrorDialog();
255 return;
256 }
257
258 mRawWallpaperSize = dimensions;
259
260 setUpExploreIntentAndLabel(ImagePreviewFragment.this::initFullResView);
261 });
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700262 }
263
264 /**
265 * Initializes MosaicView by initializing tiling, setting a fallback page bitmap, and
266 * initializing a zoom-scroll observer and click listener.
267 */
268 private void initFullResView() {
Tracy Zhoudee07892020-06-16 20:14:30 -0700269 // Minimum scale will only be respected under this scale type.
270 mFullResImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM);
271 // When we set a minimum scale bigger than the scale with which the full image is shown,
272 // disallow user to pan outside the view we show the wallpaper in.
273 mFullResImageView.setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700274
275 // Set a solid black "page bitmap" so MosaicView draws a black background while waiting
276 // for the image to load or a transparent one if a thumbnail already loaded.
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700277 Bitmap backgroundBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700278 int preColor = ContextCompat.getColor(getContext(), R.color.fullscreen_preview_background);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700279 int color = (mLowResImageView.getDrawable() == null) ? preColor : Color.TRANSPARENT;
280 backgroundBitmap.setPixel(0, 0, color);
281 mFullResImageView.setImage(ImageSource.bitmap(backgroundBitmap));
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700282
283 // Then set a fallback "page bitmap" to cover the whole MosaicView, which is an actual
284 // (lower res) version of the image to be displayed.
285 Point targetPageBitmapSize = new Point(mRawWallpaperSize);
286 mWallpaperAsset.decodeBitmap(targetPageBitmapSize.x, targetPageBitmapSize.y,
287 pageBitmap -> {
288 // Check that the activity is still around since the decoding task started.
289 if (getActivity() == null) {
290 return;
291 }
292
293 // Some of these may be null depending on if the Fragment is paused, stopped,
294 // or destroyed.
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800295 if (mLoadingProgressBar != null) {
296 mLoadingProgressBar.hide();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700297 }
298 // The page bitmap may be null if there was a decoding error, so show an
299 // error dialog.
300 if (pageBitmap == null) {
301 showLoadWallpaperErrorDialog();
302 return;
303 }
304 if (mFullResImageView != null) {
305 // Set page bitmap.
306 mFullResImageView.setImage(ImageSource.bitmap(pageBitmap));
307
308 setDefaultWallpaperZoomAndScroll();
309 crossFadeInMosaicView();
310 }
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700311 getActivity().invalidateOptionsMenu();
312
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700313 if (mWallpaperInfoView != null && mWallpaper != null) {
314 mWallpaperInfoView.populateWallpaperInfo(mWallpaper, mActionLabel,
315 mExploreIntent, this::onExploreClicked);
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700316 }
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700317 });
318 }
319
320 /**
321 * Makes the MosaicView visible with an alpha fade-in animation while fading out the loading
322 * indicator.
323 */
324 private void crossFadeInMosaicView() {
325 long shortAnimationDuration = getResources().getInteger(
326 android.R.integer.config_shortAnimTime);
327
328 mFullResImageView.setAlpha(0f);
329 mFullResImageView.animate()
330 .alpha(1f)
331 .setDuration(shortAnimationDuration)
332 .setListener(new AnimatorListenerAdapter() {
333 @Override
334 public void onAnimationEnd(Animator animation) {
335 // Clear the thumbnail bitmap reference to save memory since it's no longer
336 // visible.
337 if (mLowResImageView != null) {
338 mLowResImageView.setImageBitmap(null);
339 }
340 }
341 });
342
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800343 mLoadingProgressBar.animate()
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700344 .alpha(0f)
345 .setDuration(shortAnimationDuration)
346 .setListener(new AnimatorListenerAdapter() {
347 @Override
348 public void onAnimationEnd(Animator animation) {
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800349 if (mLoadingProgressBar != null) {
350 mLoadingProgressBar.hide();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700351 }
352 }
353 });
354 }
355
356 /**
Michel Comin Escudeb3e1fef2019-11-22 11:41:53 -0800357 * Sets the default wallpaper zoom and scroll position based on a "crop surface" (with extra
358 * width to account for parallax) superimposed on the screen. Shows as much of the wallpaper as
359 * possible on the crop surface and align screen to crop surface such that the default preview
360 * matches what would be seen by the user in the left-most home screen.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700361 *
362 * <p>This method is called once in the Fragment lifecycle after the wallpaper asset has loaded
363 * and rendered to the layout.
364 */
365 private void setDefaultWallpaperZoomAndScroll() {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700366 // Determine minimum zoom to fit maximum visible area of wallpaper on crop surface.
367 int cropWidth = mWorkspaceSurface.getMeasuredWidth();
368 int cropHeight = mWorkspaceSurface.getMeasuredHeight();
369 Point crop = new Point(cropWidth, cropHeight);
370 Rect visibleRawWallpaperRect =
371 WallpaperCropUtils.calculateVisibleRect(mRawWallpaperSize, crop);
Santiago Etchebeheree95b6d92020-06-08 14:19:46 -0700372
373 final PointF centerPosition = WallpaperCropUtils.calculateDefaultCenter(requireContext(),
374 mRawWallpaperSize, visibleRawWallpaperRect);
375
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700376 Point visibleRawWallpaperSize = new Point(visibleRawWallpaperRect.width(),
377 visibleRawWallpaperRect.height());
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700378
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700379 final float defaultWallpaperZoom = WallpaperCropUtils.calculateMinZoom(
380 visibleRawWallpaperSize, crop);
381 final float minWallpaperZoom = defaultWallpaperZoom;
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700382
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700383
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700384 // Set min wallpaper zoom and max zoom on MosaicView widget.
385 mFullResImageView.setMaxScale(Math.max(DEFAULT_WALLPAPER_MAX_ZOOM, defaultWallpaperZoom));
386 mFullResImageView.setMinScale(minWallpaperZoom);
387
388 // Set center to composite positioning between scaled wallpaper and screen.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700389 mFullResImageView.setScaleAndCenter(minWallpaperZoom, centerPosition);
390 }
391
392 private Rect calculateCropRect() {
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700393 float wallpaperZoom = mFullResImageView.getScale();
Chuck Liao5182a312020-03-04 20:04:18 +0800394 Context context = requireContext().getApplicationContext();
Tracy Zhou67fd7e32020-05-01 18:35:36 -0700395
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700396 Rect visibleFileRect = new Rect();
397 mFullResImageView.visibleFileRect(visibleFileRect);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700398
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700399 int cropWidth = mWorkspaceSurface.getMeasuredWidth();
400 int cropHeight = mWorkspaceSurface.getMeasuredHeight();
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700401 int maxCrop = Math.max(cropWidth, cropHeight);
402 int minCrop = Math.min(cropWidth, cropHeight);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700403 Point hostViewSize = new Point(cropWidth, cropHeight);
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700404
405 // Workaround for now to force wallpapers designed to fit one screen size to not adjust for
406 // parallax scrolling (with an extra 1 pixel to account for rounding)
407 // TODO (santie): implement a better solution
408 boolean shouldForceScreenSize = mRawWallpaperSize.x - mScreenSize.x <= 1;
409 Resources res = context.getResources();
410 Point cropSurfaceSize = shouldForceScreenSize ? hostViewSize :
411 WallpaperCropUtils.calculateCropSurfaceSize(res, maxCrop, minCrop);
412
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700413 Rect cropRect = WallpaperCropUtils.calculateCropRect(context, hostViewSize,
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700414 cropSurfaceSize, mRawWallpaperSize, visibleFileRect, wallpaperZoom);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700415 WallpaperCropUtils.adjustCropRect(context, cropRect, false /* zoomIn */);
416 return cropRect;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700417 }
418
419 @Override
420 protected void setCurrentWallpaper(@Destination int destination) {
421 mWallpaperSetter.setCurrentWallpaper(getActivity(), mWallpaper, mWallpaperAsset,
422 destination, mFullResImageView.getScale(), calculateCropRect(),
423 new SetWallpaperCallback() {
424 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800425 public void onSuccess(WallpaperInfo wallpaperInfo) {
Ching-Sung Lib5e9bd72020-06-15 14:10:55 +0800426 finishActivity(/* success= */ true);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700427 }
428
429 @Override
430 public void onError(@Nullable Throwable throwable) {
431 showSetWallpaperErrorDialog(destination);
432 }
433 });
434 }
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700435
436 private void renderWorkspaceSurface() {
437 mWorkspaceSurface.setZOrderMediaOverlay(true);
438 mWorkspaceSurface.getHolder().addCallback(mWorkspaceSurfaceCallback);
439 }
440
441 private void renderImageWallpaper() {
442 mWallpaperSurface.getHolder().addCallback(mWallpaperSurfaceCallback);
443 }
444
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700445 private class WallpaperSurfaceCallback implements SurfaceHolder.Callback {
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700446
447 private Surface mLastSurface;
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700448 private SurfaceControlViewHost mHost;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700449
450 @Override
451 public void surfaceCreated(SurfaceHolder holder) {
452 if (mLastSurface != holder.getSurface()) {
453 mLastSurface = holder.getSurface();
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700454 if (mFullResImageView != null) {
455 mFullResImageView.recycle();
456 }
457 View wallpaperPreviewContainer = LayoutInflater.from(getContext()).inflate(
458 R.layout.fullscreen_wallpaper_preview, null);
459 mFullResImageView = wallpaperPreviewContainer.findViewById(R.id.full_res_image);
460 mLowResImageView = wallpaperPreviewContainer.findViewById(R.id.low_res_image);
Chuck Liaoca1d1292020-06-19 01:29:53 +0800461 // Load a low-res placeholder image if there's a thumbnail available from the asset
462 // that can be shown to the user more quickly than the full-sized image.
463 if (mWallpaperAsset.hasLowResDataSource()) {
464 Activity activity = requireActivity();
465 mWallpaperAsset.loadLowResDrawable(activity, mLowResImageView, Color.BLACK,
466 new WallpaperPreviewBitmapTransformation(
467 activity.getApplicationContext(), isRtl()));
468 }
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700469 wallpaperPreviewContainer.measure(
470 makeMeasureSpec(mWallpaperSurface.getWidth(), EXACTLY),
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700471 makeMeasureSpec(mWallpaperSurface.getHeight(), EXACTLY));
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700472 wallpaperPreviewContainer.layout(0, 0, mWallpaperSurface.getWidth(),
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700473 mWallpaperSurface.getHeight());
Ching-Sung Lib9404622020-05-18 22:38:45 +0800474 mTouchForwardingLayout.setTargetView(mFullResImageView);
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700475
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700476 cleanUp();
477 mHost = new SurfaceControlViewHost(getContext(),
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700478 getContext().getDisplay(), mWallpaperSurface.getHostToken());
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700479 mHost.setView(wallpaperPreviewContainer, wallpaperPreviewContainer.getWidth(),
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700480 wallpaperPreviewContainer.getHeight());
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700481 mWallpaperSurface.setChildSurfacePackage(mHost.getSurfacePackage());
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700482 }
483 }
484
485 @Override
486 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
487
488 @Override
489 public void surfaceDestroyed(SurfaceHolder holder) { }
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700490
491 public void cleanUp() {
492 if (mHost != null) {
493 mHost.release();
494 mHost = null;
495 }
496 }
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700497 };
498
Tracy Zhou67fd7e32020-05-01 18:35:36 -0700499 private void setEditingEnabled(boolean enabled) {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700500 mTouchForwardingLayout.setForwardingEnabled(enabled);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700501 }
502
Wesley.CW Wangf21486b2020-06-02 18:30:32 +0800503 private void updateScreenPreview(boolean isHomeSelected) {
504 mHome.setSelected(isHomeSelected);
505 mLock.setSelected(!isHomeSelected);
chihhangchuang287d4b72020-06-25 01:09:09 +0800506 mWorkspaceSurface.setVisibility(isHomeSelected ? View.VISIBLE : View.INVISIBLE);
507 mLockPreviewContainer.setVisibility(isHomeSelected ? View.INVISIBLE : View.VISIBLE);
Tracy Zhou67fd7e32020-05-01 18:35:36 -0700508 }
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700509}