blob: b1153bb890f2b2a6b122c037863df44c22b6435e [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;
chihhangchuang45d94132020-07-08 16:18:37 +080071import com.google.android.material.tabs.TabLayout;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070072
chihhangchuang923e29b2020-07-02 19:09:36 +080073import java.util.Locale;
74
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070075/**
Santiago Etchebehere4ecb6aa2019-11-07 11:48:58 -080076 * Fragment which displays the UI for previewing an individual static wallpaper and its attribution
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070077 * information.
78 */
79public class ImagePreviewFragment extends PreviewFragment {
80
81 private static final float DEFAULT_WALLPAPER_MAX_ZOOM = 8f;
82
Tracy Zhou4421a3d2020-06-15 14:56:18 -070083 private final WallpaperSurfaceCallback mWallpaperSurfaceCallback =
84 new WallpaperSurfaceCallback();
Tracy Zhouc5a6bad2020-05-20 23:28:22 -070085
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070086 private SubsamplingScaleImageView mFullResImageView;
87 private Asset mWallpaperAsset;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070088 private Point mScreenSize;
89 private Point mRawWallpaperSize; // Native size of wallpaper image.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070090 private ImageView mLowResImageView;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070091 private TouchForwardingLayout mTouchForwardingLayout;
Tracy Zhou3eb234c2020-05-05 15:17:33 -070092 private ConstraintLayout mContainer;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070093 private SurfaceView mWorkspaceSurface;
Tracy Zhou3eb234c2020-05-05 15:17:33 -070094 private WorkspaceSurfaceHolderCallback mWorkspaceSurfaceCallback;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070095 private SurfaceView mWallpaperSurface;
chihhangchuang287d4b72020-06-25 01:09:09 +080096 private ViewGroup mLockPreviewContainer;
97 private LockScreenPreviewer mLockScreenPreviewer;
Tracy Zhou35997422020-05-01 13:42:06 -070098 private WallpaperInfoView mWallpaperInfoView;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070099
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700100 @Override
101 public void onCreate(Bundle savedInstanceState) {
102 super.onCreate(savedInstanceState);
103 mWallpaperAsset = mWallpaper.getAsset(requireContext().getApplicationContext());
104 }
105
106 @Override
107 protected int getLayoutResId() {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700108 return R.layout.fragment_image_preview_v2;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700109 }
110
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700111 @Override
Santiago Etchebeheredc55b192019-11-08 13:56:52 -0800112 protected int getLoadingIndicatorResId() {
113 return R.id.loading_indicator;
114 }
115
116 @Override
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700117 public View onCreateView(LayoutInflater inflater, ViewGroup container,
Michel Comin Escudeb3e1fef2019-11-22 11:41:53 -0800118 Bundle savedInstanceState) {
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700119 View view = super.onCreateView(inflater, container, savedInstanceState);
120
121 Activity activity = requireActivity();
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700122 mScreenSize = ScreenSizeCalculator.getInstance().getScreenSize(
123 activity.getWindowManager().getDefaultDisplay());
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700124
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700125 // TODO: Consider moving some part of this to the base class when live preview is ready.
126 view.findViewById(R.id.low_res_image).setVisibility(View.GONE);
127 view.findViewById(R.id.full_res_image).setVisibility(View.GONE);
128 mLoadingProgressBar.hide();
129 mContainer = view.findViewById(R.id.container);
130 mTouchForwardingLayout = mContainer.findViewById(R.id.touch_forwarding_layout);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700131
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700132 // Set aspect ratio on the preview card dynamically.
133 ConstraintSet set = new ConstraintSet();
134 set.clone(mContainer);
chihhangchuang923e29b2020-07-02 19:09:36 +0800135 String ratio = String.format(Locale.US, "%d:%d", mScreenSize.x, mScreenSize.y);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700136 set.setDimensionRatio(mTouchForwardingLayout.getId(), ratio);
137 set.applyTo(mContainer);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700138
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700139 mWorkspaceSurface = mContainer.findViewById(R.id.workspace_surface);
140 mWorkspaceSurfaceCallback = new WorkspaceSurfaceHolderCallback(mWorkspaceSurface,
141 getContext());
142 mWallpaperSurface = mContainer.findViewById(R.id.wallpaper_surface);
chihhangchuang287d4b72020-06-25 01:09:09 +0800143 mLockPreviewContainer = mContainer.findViewById(R.id.lock_screen_preview_container);
144 mLockScreenPreviewer = new LockScreenPreviewer(getLifecycle(), getActivity(),
145 mLockPreviewContainer);
Chuck Liaofc1b8c92020-05-21 20:54:15 +0800146
chihhangchuang45d94132020-07-08 16:18:37 +0800147 TabLayout tabs = inflater.inflate(R.layout.full_preview_tabs,
148 view.findViewById(R.id.toolbar_tabs_container))
149 .findViewById(R.id.full_preview_tabs);
150 tabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
151 @Override
152 public void onTabSelected(TabLayout.Tab tab) {
153 updateScreenPreview(tab.getPosition() == 0);
154 }
155
156 @Override
157 public void onTabUnselected(TabLayout.Tab tab) {}
158
159 @Override
160 public void onTabReselected(TabLayout.Tab tab) {}
161 });
162
163 // The TabLayout only contains below tabs, see: full_preview_tabs.xml
164 // 0. Home tab
165 // 1. Lock tab
166 tabs.getTabAt(mViewAsHome ? 0 : 1).select();
167 updateScreenPreview(mViewAsHome);
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700168
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700169 view.measure(makeMeasureSpec(mScreenSize.x, EXACTLY),
170 makeMeasureSpec(mScreenSize.y, EXACTLY));
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700171 ((CardView) mWorkspaceSurface.getParent())
172 .setRadius(SizeCalculator.getPreviewCornerRadius(
173 activity, mContainer.getMeasuredWidth()));
174 renderImageWallpaper();
175 renderWorkspaceSurface();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700176
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700177 // Trim some memory from Glide to make room for the full-size image in this fragment.
178 Glide.get(activity).setMemoryCategory(MemoryCategory.LOW);
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800179 setUpLoadingIndicator();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700180 return view;
181 }
182
Santiago Etchebehere4ecb6aa2019-11-07 11:48:58 -0800183 @Override
Chuck Liaofc1b8c92020-05-21 20:54:15 +0800184 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
185 super.onViewCreated(view, savedInstanceState);
chihhangchuang90f902c2020-06-03 16:14:40 +0800186 WallpaperColorsLoader.getWallpaperColors(getContext(),
187 mWallpaper.getThumbAsset(getContext()),
chihhangchuang287d4b72020-06-25 01:09:09 +0800188 mLockScreenPreviewer::setColor);
Santiago Etchebehere4ecb6aa2019-11-07 11:48:58 -0800189 }
190
Santiago Etchebeheredc55b192019-11-08 13:56:52 -0800191 @Override
192 protected boolean isLoaded() {
193 return mFullResImageView != null && mFullResImageView.hasImage();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700194 }
195
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700196 @Override
197 public void onClickOk() {
198 FragmentActivity activity = getActivity();
199 if (activity != null) {
200 activity.finish();
201 }
202 }
203
204 @Override
205 public void onDestroy() {
206 super.onDestroy();
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800207 if (mLoadingProgressBar != null) {
208 mLoadingProgressBar.hide();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700209 }
210 mFullResImageView.recycle();
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700211
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700212 mWallpaperSurfaceCallback.cleanUp();
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700213 mWorkspaceSurfaceCallback.cleanUp();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700214 }
215
216 @Override
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700217 protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700218 super.onBottomActionBarReady(bottomActionBar);
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700219
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700220 mWallpaperInfoView = (WallpaperInfoView)
221 LayoutInflater.from(getContext()).inflate(
222 R.layout.wallpaper_info_view, /* root= */null);
223 mBottomActionBar.attachViewToBottomSheetAndBindAction(mWallpaperInfoView, INFORMATION);
224 mBottomActionBar.showActionsOnly(INFORMATION, EDIT, APPLY);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700225 mBottomActionBar.setActionClickListener(EDIT, v ->
Tracy Zhou16112e32020-05-27 13:13:23 -0700226 setEditingEnabled(mBottomActionBar.isActionSelected(EDIT))
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700227 );
Chihhang Chuangca7c8252020-06-17 17:32:46 +0800228 mBottomActionBar.setActionSelectedListener(EDIT, this::setEditingEnabled);
229 mBottomActionBar.setActionClickListener(APPLY, this::onSetWallpaperClicked);
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +0800230
231 // Update target view's accessibility param since it will be blocked by the bottom sheet
232 // when expanded.
233 mBottomActionBar.setAccessibilityCallback(new AccessibilityCallback() {
234 @Override
235 public void onBottomSheetCollapsed() {
Wesley.CW Wangb8e51a22020-07-02 18:40:31 +0800236 mContainer.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +0800237 }
238
239 @Override
240 public void onBottomSheetExpanded() {
Wesley.CW Wangb8e51a22020-07-02 18:40:31 +0800241 mContainer.setImportantForAccessibility(
242 View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +0800243 }
244 });
245
Chihhang Chuangca7c8252020-06-17 17:32:46 +0800246 // Will trigger onActionSelected callback to update the editing state.
247 mBottomActionBar.setDefaultSelectedButton(EDIT);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700248 mBottomActionBar.show();
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700249
chihhangchuang13cb1fe2020-06-30 16:46:59 +0800250 mBottomActionBar.disableActions();
251 mWallpaperAsset.decodeRawDimensions(getActivity(), dimensions -> {
252 if (mBottomActionBar != null) {
253 mBottomActionBar.enableActions();
254 }
255
256 // Don't continue loading the wallpaper if the Fragment is detached.
257 if (getActivity() == null) {
258 return;
259 }
260
261 // Return early and show a dialog if dimensions are null (signaling a decoding error).
262 if (dimensions == null) {
263 showLoadWallpaperErrorDialog();
264 return;
265 }
266
267 mRawWallpaperSize = dimensions;
268
269 setUpExploreIntentAndLabel(ImagePreviewFragment.this::initFullResView);
270 });
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700271 }
272
273 /**
274 * Initializes MosaicView by initializing tiling, setting a fallback page bitmap, and
275 * initializing a zoom-scroll observer and click listener.
276 */
277 private void initFullResView() {
Tracy Zhoudee07892020-06-16 20:14:30 -0700278 // Minimum scale will only be respected under this scale type.
279 mFullResImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM);
280 // When we set a minimum scale bigger than the scale with which the full image is shown,
281 // disallow user to pan outside the view we show the wallpaper in.
282 mFullResImageView.setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700283
284 // Set a solid black "page bitmap" so MosaicView draws a black background while waiting
285 // for the image to load or a transparent one if a thumbnail already loaded.
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700286 Bitmap backgroundBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700287 int preColor = ContextCompat.getColor(getContext(), R.color.fullscreen_preview_background);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700288 int color = (mLowResImageView.getDrawable() == null) ? preColor : Color.TRANSPARENT;
289 backgroundBitmap.setPixel(0, 0, color);
290 mFullResImageView.setImage(ImageSource.bitmap(backgroundBitmap));
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700291
292 // Then set a fallback "page bitmap" to cover the whole MosaicView, which is an actual
293 // (lower res) version of the image to be displayed.
294 Point targetPageBitmapSize = new Point(mRawWallpaperSize);
295 mWallpaperAsset.decodeBitmap(targetPageBitmapSize.x, targetPageBitmapSize.y,
296 pageBitmap -> {
297 // Check that the activity is still around since the decoding task started.
298 if (getActivity() == null) {
299 return;
300 }
301
302 // Some of these may be null depending on if the Fragment is paused, stopped,
303 // or destroyed.
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800304 if (mLoadingProgressBar != null) {
305 mLoadingProgressBar.hide();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700306 }
307 // The page bitmap may be null if there was a decoding error, so show an
308 // error dialog.
309 if (pageBitmap == null) {
310 showLoadWallpaperErrorDialog();
311 return;
312 }
313 if (mFullResImageView != null) {
314 // Set page bitmap.
315 mFullResImageView.setImage(ImageSource.bitmap(pageBitmap));
316
317 setDefaultWallpaperZoomAndScroll();
318 crossFadeInMosaicView();
319 }
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700320 getActivity().invalidateOptionsMenu();
321
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700322 if (mWallpaperInfoView != null && mWallpaper != null) {
323 mWallpaperInfoView.populateWallpaperInfo(mWallpaper, mActionLabel,
324 mExploreIntent, this::onExploreClicked);
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700325 }
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700326 });
327 }
328
329 /**
330 * Makes the MosaicView visible with an alpha fade-in animation while fading out the loading
331 * indicator.
332 */
333 private void crossFadeInMosaicView() {
334 long shortAnimationDuration = getResources().getInteger(
335 android.R.integer.config_shortAnimTime);
336
337 mFullResImageView.setAlpha(0f);
338 mFullResImageView.animate()
339 .alpha(1f)
340 .setDuration(shortAnimationDuration)
341 .setListener(new AnimatorListenerAdapter() {
342 @Override
343 public void onAnimationEnd(Animator animation) {
344 // Clear the thumbnail bitmap reference to save memory since it's no longer
345 // visible.
346 if (mLowResImageView != null) {
347 mLowResImageView.setImageBitmap(null);
348 }
349 }
350 });
351
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800352 mLoadingProgressBar.animate()
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700353 .alpha(0f)
354 .setDuration(shortAnimationDuration)
355 .setListener(new AnimatorListenerAdapter() {
356 @Override
357 public void onAnimationEnd(Animator animation) {
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800358 if (mLoadingProgressBar != null) {
359 mLoadingProgressBar.hide();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700360 }
361 }
362 });
363 }
364
365 /**
Michel Comin Escudeb3e1fef2019-11-22 11:41:53 -0800366 * Sets the default wallpaper zoom and scroll position based on a "crop surface" (with extra
367 * width to account for parallax) superimposed on the screen. Shows as much of the wallpaper as
368 * possible on the crop surface and align screen to crop surface such that the default preview
369 * matches what would be seen by the user in the left-most home screen.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700370 *
371 * <p>This method is called once in the Fragment lifecycle after the wallpaper asset has loaded
372 * and rendered to the layout.
373 */
374 private void setDefaultWallpaperZoomAndScroll() {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700375 // Determine minimum zoom to fit maximum visible area of wallpaper on crop surface.
376 int cropWidth = mWorkspaceSurface.getMeasuredWidth();
377 int cropHeight = mWorkspaceSurface.getMeasuredHeight();
378 Point crop = new Point(cropWidth, cropHeight);
379 Rect visibleRawWallpaperRect =
380 WallpaperCropUtils.calculateVisibleRect(mRawWallpaperSize, crop);
Santiago Etchebeheree95b6d92020-06-08 14:19:46 -0700381
382 final PointF centerPosition = WallpaperCropUtils.calculateDefaultCenter(requireContext(),
383 mRawWallpaperSize, visibleRawWallpaperRect);
384
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700385 Point visibleRawWallpaperSize = new Point(visibleRawWallpaperRect.width(),
386 visibleRawWallpaperRect.height());
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700387
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700388 final float defaultWallpaperZoom = WallpaperCropUtils.calculateMinZoom(
389 visibleRawWallpaperSize, crop);
390 final float minWallpaperZoom = defaultWallpaperZoom;
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700391
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700392
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700393 // Set min wallpaper zoom and max zoom on MosaicView widget.
394 mFullResImageView.setMaxScale(Math.max(DEFAULT_WALLPAPER_MAX_ZOOM, defaultWallpaperZoom));
395 mFullResImageView.setMinScale(minWallpaperZoom);
396
397 // Set center to composite positioning between scaled wallpaper and screen.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700398 mFullResImageView.setScaleAndCenter(minWallpaperZoom, centerPosition);
399 }
400
401 private Rect calculateCropRect() {
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700402 float wallpaperZoom = mFullResImageView.getScale();
Chuck Liao5182a312020-03-04 20:04:18 +0800403 Context context = requireContext().getApplicationContext();
Tracy Zhou67fd7e32020-05-01 18:35:36 -0700404
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700405 Rect visibleFileRect = new Rect();
406 mFullResImageView.visibleFileRect(visibleFileRect);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700407
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700408 int cropWidth = mWorkspaceSurface.getMeasuredWidth();
409 int cropHeight = mWorkspaceSurface.getMeasuredHeight();
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700410 int maxCrop = Math.max(cropWidth, cropHeight);
411 int minCrop = Math.min(cropWidth, cropHeight);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700412 Point hostViewSize = new Point(cropWidth, cropHeight);
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700413
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700414 Resources res = context.getResources();
Santiago Etchebeherebcd6bb62020-07-09 12:09:21 -0700415 Point cropSurfaceSize = WallpaperCropUtils.calculateCropSurfaceSize(res, maxCrop, minCrop);
416 WallpaperCropUtils.scaleSize(context, hostViewSize);
417 WallpaperCropUtils.scaleSize(context, cropSurfaceSize);
418
419 WallpaperCropUtils.adjustCropRect(context, visibleFileRect, false);
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700420
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700421 Rect cropRect = WallpaperCropUtils.calculateCropRect(context, hostViewSize,
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700422 cropSurfaceSize, mRawWallpaperSize, visibleFileRect, wallpaperZoom);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700423 return cropRect;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700424 }
425
426 @Override
427 protected void setCurrentWallpaper(@Destination int destination) {
428 mWallpaperSetter.setCurrentWallpaper(getActivity(), mWallpaper, mWallpaperAsset,
429 destination, mFullResImageView.getScale(), calculateCropRect(),
430 new SetWallpaperCallback() {
431 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800432 public void onSuccess(WallpaperInfo wallpaperInfo) {
Ching-Sung Lib5e9bd72020-06-15 14:10:55 +0800433 finishActivity(/* success= */ true);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700434 }
435
436 @Override
437 public void onError(@Nullable Throwable throwable) {
438 showSetWallpaperErrorDialog(destination);
439 }
440 });
441 }
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700442
443 private void renderWorkspaceSurface() {
444 mWorkspaceSurface.setZOrderMediaOverlay(true);
445 mWorkspaceSurface.getHolder().addCallback(mWorkspaceSurfaceCallback);
446 }
447
448 private void renderImageWallpaper() {
449 mWallpaperSurface.getHolder().addCallback(mWallpaperSurfaceCallback);
450 }
451
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700452 private class WallpaperSurfaceCallback implements SurfaceHolder.Callback {
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700453
454 private Surface mLastSurface;
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700455 private SurfaceControlViewHost mHost;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700456
457 @Override
458 public void surfaceCreated(SurfaceHolder holder) {
459 if (mLastSurface != holder.getSurface()) {
460 mLastSurface = holder.getSurface();
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700461 if (mFullResImageView != null) {
462 mFullResImageView.recycle();
463 }
464 View wallpaperPreviewContainer = LayoutInflater.from(getContext()).inflate(
465 R.layout.fullscreen_wallpaper_preview, null);
466 mFullResImageView = wallpaperPreviewContainer.findViewById(R.id.full_res_image);
467 mLowResImageView = wallpaperPreviewContainer.findViewById(R.id.low_res_image);
Chuck Liaoca1d1292020-06-19 01:29:53 +0800468 // Load a low-res placeholder image if there's a thumbnail available from the asset
469 // that can be shown to the user more quickly than the full-sized image.
470 if (mWallpaperAsset.hasLowResDataSource()) {
471 Activity activity = requireActivity();
472 mWallpaperAsset.loadLowResDrawable(activity, mLowResImageView, Color.BLACK,
473 new WallpaperPreviewBitmapTransformation(
474 activity.getApplicationContext(), isRtl()));
475 }
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700476 wallpaperPreviewContainer.measure(
477 makeMeasureSpec(mWallpaperSurface.getWidth(), EXACTLY),
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700478 makeMeasureSpec(mWallpaperSurface.getHeight(), EXACTLY));
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700479 wallpaperPreviewContainer.layout(0, 0, mWallpaperSurface.getWidth(),
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700480 mWallpaperSurface.getHeight());
Ching-Sung Lib9404622020-05-18 22:38:45 +0800481 mTouchForwardingLayout.setTargetView(mFullResImageView);
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700482
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700483 cleanUp();
484 mHost = new SurfaceControlViewHost(getContext(),
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700485 getContext().getDisplay(), mWallpaperSurface.getHostToken());
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700486 mHost.setView(wallpaperPreviewContainer, wallpaperPreviewContainer.getWidth(),
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700487 wallpaperPreviewContainer.getHeight());
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700488 mWallpaperSurface.setChildSurfacePackage(mHost.getSurfacePackage());
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700489 }
490 }
491
492 @Override
493 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
494
495 @Override
496 public void surfaceDestroyed(SurfaceHolder holder) { }
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700497
498 public void cleanUp() {
499 if (mHost != null) {
500 mHost.release();
501 mHost = null;
502 }
503 }
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700504 };
505
Tracy Zhou67fd7e32020-05-01 18:35:36 -0700506 private void setEditingEnabled(boolean enabled) {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700507 mTouchForwardingLayout.setForwardingEnabled(enabled);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700508 }
509
Wesley.CW Wangf21486b2020-06-02 18:30:32 +0800510 private void updateScreenPreview(boolean isHomeSelected) {
chihhangchuang287d4b72020-06-25 01:09:09 +0800511 mWorkspaceSurface.setVisibility(isHomeSelected ? View.VISIBLE : View.INVISIBLE);
512 mLockPreviewContainer.setVisibility(isHomeSelected ? View.INVISIBLE : View.VISIBLE);
Tracy Zhou67fd7e32020-05-01 18:35:36 -0700513 }
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700514}