blob: 308e90739cd882255c4e1a56faba5fb8fa5a3160 [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;
Chuck Liaodc424e82020-09-04 00:17:44 +080055import com.android.wallpaper.asset.CurrentWallpaperAssetVN;
“Chuckffd832c2020-03-22 02:15:58 +080056import com.android.wallpaper.model.WallpaperInfo;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070057import com.android.wallpaper.module.WallpaperPersister.Destination;
58import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback;
59import com.android.wallpaper.util.ScreenSizeCalculator;
Santiago Etchebehere53c63432020-05-07 18:55:35 -070060import com.android.wallpaper.util.SizeCalculator;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070061import com.android.wallpaper.util.WallpaperCropUtils;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070062import com.android.wallpaper.widget.BottomActionBar;
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +080063import com.android.wallpaper.widget.BottomActionBar.AccessibilityCallback;
chihhangchuang287d4b72020-06-25 01:09:09 +080064import com.android.wallpaper.widget.LockScreenPreviewer;
Chuck Liaofc1b8c92020-05-21 20:54:15 +080065import com.android.wallpaper.widget.WallpaperColorsLoader;
Tracy Zhou35997422020-05-01 13:42:06 -070066import com.android.wallpaper.widget.WallpaperInfoView;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070067
68import com.bumptech.glide.Glide;
69import com.bumptech.glide.MemoryCategory;
70import com.davemorrissey.labs.subscaleview.ImageSource;
71import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
chihhangchuang45d94132020-07-08 16:18:37 +080072import com.google.android.material.tabs.TabLayout;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070073
chihhangchuang923e29b2020-07-02 19:09:36 +080074import java.util.Locale;
75
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070076/**
Santiago Etchebehere4ecb6aa2019-11-07 11:48:58 -080077 * Fragment which displays the UI for previewing an individual static wallpaper and its attribution
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070078 * information.
79 */
80public class ImagePreviewFragment extends PreviewFragment {
81
82 private static final float DEFAULT_WALLPAPER_MAX_ZOOM = 8f;
83
Tracy Zhou4421a3d2020-06-15 14:56:18 -070084 private final WallpaperSurfaceCallback mWallpaperSurfaceCallback =
85 new WallpaperSurfaceCallback();
Tracy Zhouc5a6bad2020-05-20 23:28:22 -070086
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070087 private SubsamplingScaleImageView mFullResImageView;
88 private Asset mWallpaperAsset;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070089 private Point mScreenSize;
90 private Point mRawWallpaperSize; // Native size of wallpaper image.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -070091 private ImageView mLowResImageView;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070092 private TouchForwardingLayout mTouchForwardingLayout;
Tracy Zhou3eb234c2020-05-05 15:17:33 -070093 private ConstraintLayout mContainer;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070094 private SurfaceView mWorkspaceSurface;
Tracy Zhou3eb234c2020-05-05 15:17:33 -070095 private WorkspaceSurfaceHolderCallback mWorkspaceSurfaceCallback;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -070096 private SurfaceView mWallpaperSurface;
chihhangchuang287d4b72020-06-25 01:09:09 +080097 private ViewGroup mLockPreviewContainer;
98 private LockScreenPreviewer mLockScreenPreviewer;
Tracy Zhou35997422020-05-01 13:42:06 -070099 private WallpaperInfoView mWallpaperInfoView;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700100
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700101 @Override
102 public void onCreate(Bundle savedInstanceState) {
103 super.onCreate(savedInstanceState);
104 mWallpaperAsset = mWallpaper.getAsset(requireContext().getApplicationContext());
105 }
106
107 @Override
108 protected int getLayoutResId() {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700109 return R.layout.fragment_image_preview_v2;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700110 }
111
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700112 @Override
Santiago Etchebeheredc55b192019-11-08 13:56:52 -0800113 protected int getLoadingIndicatorResId() {
114 return R.id.loading_indicator;
115 }
116
117 @Override
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700118 public View onCreateView(LayoutInflater inflater, ViewGroup container,
Michel Comin Escudeb3e1fef2019-11-22 11:41:53 -0800119 Bundle savedInstanceState) {
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700120 View view = super.onCreateView(inflater, container, savedInstanceState);
121
122 Activity activity = requireActivity();
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700123 mScreenSize = ScreenSizeCalculator.getInstance().getScreenSize(
124 activity.getWindowManager().getDefaultDisplay());
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700125
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700126 // TODO: Consider moving some part of this to the base class when live preview is ready.
127 view.findViewById(R.id.low_res_image).setVisibility(View.GONE);
128 view.findViewById(R.id.full_res_image).setVisibility(View.GONE);
129 mLoadingProgressBar.hide();
130 mContainer = view.findViewById(R.id.container);
131 mTouchForwardingLayout = mContainer.findViewById(R.id.touch_forwarding_layout);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700132
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700133 // Set aspect ratio on the preview card dynamically.
134 ConstraintSet set = new ConstraintSet();
135 set.clone(mContainer);
chihhangchuang923e29b2020-07-02 19:09:36 +0800136 String ratio = String.format(Locale.US, "%d:%d", mScreenSize.x, mScreenSize.y);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700137 set.setDimensionRatio(mTouchForwardingLayout.getId(), ratio);
138 set.applyTo(mContainer);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700139
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700140 mWorkspaceSurface = mContainer.findViewById(R.id.workspace_surface);
141 mWorkspaceSurfaceCallback = new WorkspaceSurfaceHolderCallback(mWorkspaceSurface,
142 getContext());
143 mWallpaperSurface = mContainer.findViewById(R.id.wallpaper_surface);
chihhangchuang287d4b72020-06-25 01:09:09 +0800144 mLockPreviewContainer = mContainer.findViewById(R.id.lock_screen_preview_container);
145 mLockScreenPreviewer = new LockScreenPreviewer(getLifecycle(), getActivity(),
146 mLockPreviewContainer);
Chuck Liaofc1b8c92020-05-21 20:54:15 +0800147
chihhangchuang45d94132020-07-08 16:18:37 +0800148 TabLayout tabs = inflater.inflate(R.layout.full_preview_tabs,
149 view.findViewById(R.id.toolbar_tabs_container))
150 .findViewById(R.id.full_preview_tabs);
151 tabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
152 @Override
153 public void onTabSelected(TabLayout.Tab tab) {
154 updateScreenPreview(tab.getPosition() == 0);
155 }
156
157 @Override
158 public void onTabUnselected(TabLayout.Tab tab) {}
159
160 @Override
161 public void onTabReselected(TabLayout.Tab tab) {}
162 });
163
164 // The TabLayout only contains below tabs, see: full_preview_tabs.xml
165 // 0. Home tab
166 // 1. Lock tab
167 tabs.getTabAt(mViewAsHome ? 0 : 1).select();
168 updateScreenPreview(mViewAsHome);
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700169
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700170 view.measure(makeMeasureSpec(mScreenSize.x, EXACTLY),
171 makeMeasureSpec(mScreenSize.y, EXACTLY));
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700172 ((CardView) mWorkspaceSurface.getParent())
173 .setRadius(SizeCalculator.getPreviewCornerRadius(
174 activity, mContainer.getMeasuredWidth()));
175 renderImageWallpaper();
176 renderWorkspaceSurface();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700177
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700178 // Trim some memory from Glide to make room for the full-size image in this fragment.
179 Glide.get(activity).setMemoryCategory(MemoryCategory.LOW);
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800180 setUpLoadingIndicator();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700181 return view;
182 }
183
Santiago Etchebehere4ecb6aa2019-11-07 11:48:58 -0800184 @Override
Chuck Liaofc1b8c92020-05-21 20:54:15 +0800185 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
186 super.onViewCreated(view, savedInstanceState);
chihhangchuang90f902c2020-06-03 16:14:40 +0800187 WallpaperColorsLoader.getWallpaperColors(getContext(),
188 mWallpaper.getThumbAsset(getContext()),
chihhangchuang287d4b72020-06-25 01:09:09 +0800189 mLockScreenPreviewer::setColor);
Santiago Etchebehere4ecb6aa2019-11-07 11:48:58 -0800190 }
191
Santiago Etchebeheredc55b192019-11-08 13:56:52 -0800192 @Override
193 protected boolean isLoaded() {
194 return mFullResImageView != null && mFullResImageView.hasImage();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700195 }
196
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700197 @Override
198 public void onClickOk() {
199 FragmentActivity activity = getActivity();
200 if (activity != null) {
201 activity.finish();
202 }
203 }
204
205 @Override
206 public void onDestroy() {
207 super.onDestroy();
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800208 if (mLoadingProgressBar != null) {
209 mLoadingProgressBar.hide();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700210 }
211 mFullResImageView.recycle();
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700212
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700213 mWallpaperSurfaceCallback.cleanUp();
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700214 mWorkspaceSurfaceCallback.cleanUp();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700215 }
216
217 @Override
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700218 protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700219 super.onBottomActionBarReady(bottomActionBar);
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700220
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700221 mWallpaperInfoView = (WallpaperInfoView)
222 LayoutInflater.from(getContext()).inflate(
223 R.layout.wallpaper_info_view, /* root= */null);
224 mBottomActionBar.attachViewToBottomSheetAndBindAction(mWallpaperInfoView, INFORMATION);
225 mBottomActionBar.showActionsOnly(INFORMATION, EDIT, APPLY);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700226 mBottomActionBar.setActionClickListener(EDIT, v ->
Tracy Zhou16112e32020-05-27 13:13:23 -0700227 setEditingEnabled(mBottomActionBar.isActionSelected(EDIT))
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700228 );
Chihhang Chuangca7c8252020-06-17 17:32:46 +0800229 mBottomActionBar.setActionSelectedListener(EDIT, this::setEditingEnabled);
230 mBottomActionBar.setActionClickListener(APPLY, this::onSetWallpaperClicked);
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +0800231
232 // Update target view's accessibility param since it will be blocked by the bottom sheet
233 // when expanded.
234 mBottomActionBar.setAccessibilityCallback(new AccessibilityCallback() {
235 @Override
236 public void onBottomSheetCollapsed() {
Wesley.CW Wangb8e51a22020-07-02 18:40:31 +0800237 mContainer.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +0800238 }
239
240 @Override
241 public void onBottomSheetExpanded() {
Wesley.CW Wangb8e51a22020-07-02 18:40:31 +0800242 mContainer.setImportantForAccessibility(
243 View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
Wesley.CW Wang61c28ec2020-06-19 18:58:50 +0800244 }
245 });
246
Chihhang Chuangca7c8252020-06-17 17:32:46 +0800247 // Will trigger onActionSelected callback to update the editing state.
248 mBottomActionBar.setDefaultSelectedButton(EDIT);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700249 mBottomActionBar.show();
Tracy Zhoue4a5f262020-05-26 17:40:19 -0700250
chihhangchuang13cb1fe2020-06-30 16:46:59 +0800251 mBottomActionBar.disableActions();
252 mWallpaperAsset.decodeRawDimensions(getActivity(), dimensions -> {
253 if (mBottomActionBar != null) {
254 mBottomActionBar.enableActions();
255 }
256
257 // Don't continue loading the wallpaper if the Fragment is detached.
258 if (getActivity() == null) {
259 return;
260 }
261
262 // Return early and show a dialog if dimensions are null (signaling a decoding error).
263 if (dimensions == null) {
264 showLoadWallpaperErrorDialog();
265 return;
266 }
267
268 mRawWallpaperSize = dimensions;
269
270 setUpExploreIntentAndLabel(ImagePreviewFragment.this::initFullResView);
271 });
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700272 }
273
274 /**
275 * Initializes MosaicView by initializing tiling, setting a fallback page bitmap, and
276 * initializing a zoom-scroll observer and click listener.
277 */
278 private void initFullResView() {
Tracy Zhoudee07892020-06-16 20:14:30 -0700279 // Minimum scale will only be respected under this scale type.
280 mFullResImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM);
281 // When we set a minimum scale bigger than the scale with which the full image is shown,
282 // disallow user to pan outside the view we show the wallpaper in.
283 mFullResImageView.setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700284
285 // Set a solid black "page bitmap" so MosaicView draws a black background while waiting
286 // for the image to load or a transparent one if a thumbnail already loaded.
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700287 Bitmap backgroundBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700288 int preColor = ContextCompat.getColor(getContext(), R.color.fullscreen_preview_background);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700289 int color = (mLowResImageView.getDrawable() == null) ? preColor : Color.TRANSPARENT;
290 backgroundBitmap.setPixel(0, 0, color);
291 mFullResImageView.setImage(ImageSource.bitmap(backgroundBitmap));
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700292
293 // Then set a fallback "page bitmap" to cover the whole MosaicView, which is an actual
294 // (lower res) version of the image to be displayed.
295 Point targetPageBitmapSize = new Point(mRawWallpaperSize);
296 mWallpaperAsset.decodeBitmap(targetPageBitmapSize.x, targetPageBitmapSize.y,
297 pageBitmap -> {
298 // Check that the activity is still around since the decoding task started.
299 if (getActivity() == null) {
300 return;
301 }
302
303 // Some of these may be null depending on if the Fragment is paused, stopped,
304 // or destroyed.
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800305 if (mLoadingProgressBar != null) {
306 mLoadingProgressBar.hide();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700307 }
308 // The page bitmap may be null if there was a decoding error, so show an
309 // error dialog.
310 if (pageBitmap == null) {
311 showLoadWallpaperErrorDialog();
312 return;
313 }
314 if (mFullResImageView != null) {
315 // Set page bitmap.
316 mFullResImageView.setImage(ImageSource.bitmap(pageBitmap));
317
Chuck Liaodc424e82020-09-04 00:17:44 +0800318 setDefaultWallpaperZoomAndScroll(
319 mWallpaperAsset instanceof CurrentWallpaperAssetVN);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700320 crossFadeInMosaicView();
321 }
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700322 getActivity().invalidateOptionsMenu();
323
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700324 if (mWallpaperInfoView != null && mWallpaper != null) {
325 mWallpaperInfoView.populateWallpaperInfo(mWallpaper, mActionLabel,
326 mExploreIntent, this::onExploreClicked);
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700327 }
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700328 });
329 }
330
331 /**
332 * Makes the MosaicView visible with an alpha fade-in animation while fading out the loading
333 * indicator.
334 */
335 private void crossFadeInMosaicView() {
336 long shortAnimationDuration = getResources().getInteger(
337 android.R.integer.config_shortAnimTime);
338
339 mFullResImageView.setAlpha(0f);
340 mFullResImageView.animate()
341 .alpha(1f)
342 .setDuration(shortAnimationDuration)
343 .setListener(new AnimatorListenerAdapter() {
344 @Override
345 public void onAnimationEnd(Animator animation) {
346 // Clear the thumbnail bitmap reference to save memory since it's no longer
347 // visible.
348 if (mLowResImageView != null) {
349 mLowResImageView.setImageBitmap(null);
350 }
351 }
352 });
353
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800354 mLoadingProgressBar.animate()
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700355 .alpha(0f)
356 .setDuration(shortAnimationDuration)
357 .setListener(new AnimatorListenerAdapter() {
358 @Override
359 public void onAnimationEnd(Animator animation) {
Santiago Etchebeheref4549ed2019-11-13 14:18:57 -0800360 if (mLoadingProgressBar != null) {
361 mLoadingProgressBar.hide();
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700362 }
363 }
364 });
365 }
366
367 /**
Michel Comin Escudeb3e1fef2019-11-22 11:41:53 -0800368 * Sets the default wallpaper zoom and scroll position based on a "crop surface" (with extra
369 * width to account for parallax) superimposed on the screen. Shows as much of the wallpaper as
370 * possible on the crop surface and align screen to crop surface such that the default preview
371 * matches what would be seen by the user in the left-most home screen.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700372 *
373 * <p>This method is called once in the Fragment lifecycle after the wallpaper asset has loaded
374 * and rendered to the layout.
Chuck Liaodc424e82020-09-04 00:17:44 +0800375 *
376 * @param offsetToFarLeft {@code true} if we want to offset the visible rectangle to far left of
377 * the raw wallpaper; {@code false} otherwise.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700378 */
Chuck Liaodc424e82020-09-04 00:17:44 +0800379 private void setDefaultWallpaperZoomAndScroll(boolean offsetToFarLeft) {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700380 // Determine minimum zoom to fit maximum visible area of wallpaper on crop surface.
381 int cropWidth = mWorkspaceSurface.getMeasuredWidth();
382 int cropHeight = mWorkspaceSurface.getMeasuredHeight();
383 Point crop = new Point(cropWidth, cropHeight);
384 Rect visibleRawWallpaperRect =
385 WallpaperCropUtils.calculateVisibleRect(mRawWallpaperSize, crop);
Chuck Liaodc424e82020-09-04 00:17:44 +0800386 if (offsetToFarLeft) {
387 visibleRawWallpaperRect.offsetTo(/* newLeft= */ 0, visibleRawWallpaperRect.top);
388 }
Santiago Etchebeheree95b6d92020-06-08 14:19:46 -0700389
390 final PointF centerPosition = WallpaperCropUtils.calculateDefaultCenter(requireContext(),
391 mRawWallpaperSize, visibleRawWallpaperRect);
392
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700393 Point visibleRawWallpaperSize = new Point(visibleRawWallpaperRect.width(),
394 visibleRawWallpaperRect.height());
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700395
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700396 final float defaultWallpaperZoom = WallpaperCropUtils.calculateMinZoom(
397 visibleRawWallpaperSize, crop);
398 final float minWallpaperZoom = defaultWallpaperZoom;
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700399
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700400
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700401 // Set min wallpaper zoom and max zoom on MosaicView widget.
402 mFullResImageView.setMaxScale(Math.max(DEFAULT_WALLPAPER_MAX_ZOOM, defaultWallpaperZoom));
403 mFullResImageView.setMinScale(minWallpaperZoom);
404
405 // Set center to composite positioning between scaled wallpaper and screen.
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700406 mFullResImageView.setScaleAndCenter(minWallpaperZoom, centerPosition);
407 }
408
409 private Rect calculateCropRect() {
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700410 float wallpaperZoom = mFullResImageView.getScale();
Chuck Liao5182a312020-03-04 20:04:18 +0800411 Context context = requireContext().getApplicationContext();
Tracy Zhou67fd7e32020-05-01 18:35:36 -0700412
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700413 Rect visibleFileRect = new Rect();
414 mFullResImageView.visibleFileRect(visibleFileRect);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700415
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700416 int cropWidth = mWorkspaceSurface.getMeasuredWidth();
417 int cropHeight = mWorkspaceSurface.getMeasuredHeight();
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700418 int maxCrop = Math.max(cropWidth, cropHeight);
419 int minCrop = Math.min(cropWidth, cropHeight);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700420 Point hostViewSize = new Point(cropWidth, cropHeight);
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700421
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700422 Resources res = context.getResources();
Santiago Etchebeherebcd6bb62020-07-09 12:09:21 -0700423 Point cropSurfaceSize = WallpaperCropUtils.calculateCropSurfaceSize(res, maxCrop, minCrop);
424 WallpaperCropUtils.scaleSize(context, hostViewSize);
425 WallpaperCropUtils.scaleSize(context, cropSurfaceSize);
426
427 WallpaperCropUtils.adjustCropRect(context, visibleFileRect, false);
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700428
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700429 Rect cropRect = WallpaperCropUtils.calculateCropRect(context, hostViewSize,
Santiago Etchebeheref172aef2020-07-04 18:48:35 -0700430 cropSurfaceSize, mRawWallpaperSize, visibleFileRect, wallpaperZoom);
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700431 return cropRect;
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700432 }
433
434 @Override
435 protected void setCurrentWallpaper(@Destination int destination) {
436 mWallpaperSetter.setCurrentWallpaper(getActivity(), mWallpaper, mWallpaperAsset,
437 destination, mFullResImageView.getScale(), calculateCropRect(),
438 new SetWallpaperCallback() {
439 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800440 public void onSuccess(WallpaperInfo wallpaperInfo) {
Ching-Sung Lib5e9bd72020-06-15 14:10:55 +0800441 finishActivity(/* success= */ true);
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700442 }
443
444 @Override
445 public void onError(@Nullable Throwable throwable) {
446 showSetWallpaperErrorDialog(destination);
447 }
448 });
449 }
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700450
451 private void renderWorkspaceSurface() {
452 mWorkspaceSurface.setZOrderMediaOverlay(true);
453 mWorkspaceSurface.getHolder().addCallback(mWorkspaceSurfaceCallback);
454 }
455
456 private void renderImageWallpaper() {
457 mWallpaperSurface.getHolder().addCallback(mWallpaperSurfaceCallback);
458 }
459
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700460 private class WallpaperSurfaceCallback implements SurfaceHolder.Callback {
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700461
462 private Surface mLastSurface;
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700463 private SurfaceControlViewHost mHost;
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700464
465 @Override
466 public void surfaceCreated(SurfaceHolder holder) {
467 if (mLastSurface != holder.getSurface()) {
468 mLastSurface = holder.getSurface();
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700469 if (mFullResImageView != null) {
470 mFullResImageView.recycle();
471 }
472 View wallpaperPreviewContainer = LayoutInflater.from(getContext()).inflate(
473 R.layout.fullscreen_wallpaper_preview, null);
474 mFullResImageView = wallpaperPreviewContainer.findViewById(R.id.full_res_image);
475 mLowResImageView = wallpaperPreviewContainer.findViewById(R.id.low_res_image);
Chuck Liaoca1d1292020-06-19 01:29:53 +0800476 // Load a low-res placeholder image if there's a thumbnail available from the asset
477 // that can be shown to the user more quickly than the full-sized image.
478 if (mWallpaperAsset.hasLowResDataSource()) {
479 Activity activity = requireActivity();
480 mWallpaperAsset.loadLowResDrawable(activity, mLowResImageView, Color.BLACK,
481 new WallpaperPreviewBitmapTransformation(
482 activity.getApplicationContext(), isRtl()));
483 }
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700484 wallpaperPreviewContainer.measure(
485 makeMeasureSpec(mWallpaperSurface.getWidth(), EXACTLY),
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700486 makeMeasureSpec(mWallpaperSurface.getHeight(), EXACTLY));
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700487 wallpaperPreviewContainer.layout(0, 0, mWallpaperSurface.getWidth(),
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700488 mWallpaperSurface.getHeight());
Ching-Sung Lib9404622020-05-18 22:38:45 +0800489 mTouchForwardingLayout.setTargetView(mFullResImageView);
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700490
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700491 cleanUp();
492 mHost = new SurfaceControlViewHost(getContext(),
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700493 getContext().getDisplay(), mWallpaperSurface.getHostToken());
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700494 mHost.setView(wallpaperPreviewContainer, wallpaperPreviewContainer.getWidth(),
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700495 wallpaperPreviewContainer.getHeight());
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700496 mWallpaperSurface.setChildSurfacePackage(mHost.getSurfacePackage());
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700497 }
498 }
499
500 @Override
501 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
502
503 @Override
504 public void surfaceDestroyed(SurfaceHolder holder) { }
Tracy Zhou4421a3d2020-06-15 14:56:18 -0700505
506 public void cleanUp() {
507 if (mHost != null) {
508 mHost.release();
509 mHost = null;
510 }
511 }
Tracy Zhoua19cbdd2020-04-26 12:12:11 -0700512 };
513
Tracy Zhou67fd7e32020-05-01 18:35:36 -0700514 private void setEditingEnabled(boolean enabled) {
Tracy Zhouecfd6eb2020-05-27 23:56:35 -0700515 mTouchForwardingLayout.setForwardingEnabled(enabled);
Tracy Zhou3eb234c2020-05-05 15:17:33 -0700516 }
517
Wesley.CW Wangf21486b2020-06-02 18:30:32 +0800518 private void updateScreenPreview(boolean isHomeSelected) {
chihhangchuang287d4b72020-06-25 01:09:09 +0800519 mWorkspaceSurface.setVisibility(isHomeSelected ? View.VISIBLE : View.INVISIBLE);
520 mLockPreviewContainer.setVisibility(isHomeSelected ? View.INVISIBLE : View.VISIBLE);
Tracy Zhou67fd7e32020-05-01 18:35:36 -0700521 }
Santiago Etchebehere6d3d1e62019-09-26 11:11:11 -0700522}