1 /* 2 * Copyright (C) 2022 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 */ 16 package com.android.wallpaper.picker; 17 18 import static android.stats.style.StyleEnums.SET_WALLPAPER_ENTRY_POINT_WALLPAPER_PREVIEW; 19 import static android.view.View.MeasureSpec.EXACTLY; 20 import static android.view.View.MeasureSpec.makeMeasureSpec; 21 22 import static com.android.wallpaper.util.WallpaperSurfaceCallback.LOW_RES_BITMAP_BLUR_RADIUS; 23 24 import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED; 25 import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN; 26 27 import android.animation.Animator; 28 import android.animation.AnimatorListenerAdapter; 29 import android.app.Activity; 30 import android.app.WallpaperManager; 31 import android.content.Context; 32 import android.content.res.Resources; 33 import android.graphics.Bitmap; 34 import android.graphics.Color; 35 import android.graphics.Point; 36 import android.graphics.PointF; 37 import android.graphics.Rect; 38 import android.graphics.RenderEffect; 39 import android.graphics.Shader; 40 import android.os.Bundle; 41 import android.os.Handler; 42 import android.util.Log; 43 import android.view.LayoutInflater; 44 import android.view.Surface; 45 import android.view.SurfaceControlViewHost; 46 import android.view.SurfaceHolder; 47 import android.view.SurfaceView; 48 import android.view.View; 49 import android.view.ViewGroup; 50 import android.view.ViewGroup.LayoutParams; 51 import android.view.animation.Interpolator; 52 import android.view.animation.PathInterpolator; 53 import android.widget.ImageView; 54 55 import androidx.annotation.NonNull; 56 import androidx.annotation.Nullable; 57 import androidx.annotation.VisibleForTesting; 58 59 import com.android.wallpaper.R; 60 import com.android.wallpaper.asset.Asset; 61 import com.android.wallpaper.asset.CurrentWallpaperAsset; 62 import com.android.wallpaper.model.SetWallpaperViewModel; 63 import com.android.wallpaper.model.WallpaperInfo.ColorInfo; 64 import com.android.wallpaper.module.BitmapCropper; 65 import com.android.wallpaper.module.Injector; 66 import com.android.wallpaper.module.InjectorProvider; 67 import com.android.wallpaper.module.WallpaperPersister.Destination; 68 import com.android.wallpaper.module.WallpaperPreferences; 69 import com.android.wallpaper.util.DisplayUtils; 70 import com.android.wallpaper.util.OnFullResImageViewStateChangedListener; 71 import com.android.wallpaper.util.ResourceUtils; 72 import com.android.wallpaper.util.RtlUtils; 73 import com.android.wallpaper.util.ScreenSizeCalculator; 74 import com.android.wallpaper.util.WallpaperColorsExtractor; 75 import com.android.wallpaper.util.WallpaperCropUtils; 76 77 import com.bumptech.glide.Glide; 78 import com.bumptech.glide.MemoryCategory; 79 import com.davemorrissey.labs.subscaleview.ImageSource; 80 import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView; 81 import com.google.android.material.bottomsheet.BottomSheetBehavior; 82 83 import java.util.concurrent.ExecutionException; 84 import java.util.concurrent.Executor; 85 import java.util.concurrent.Executors; 86 import java.util.concurrent.Future; 87 88 /** 89 * Fragment which displays the UI for previewing an individual static image wallpaper and its 90 * attribution information. 91 */ 92 public class ImagePreviewFragment extends PreviewFragment { 93 94 private static final String TAG = "ImagePreviewFragment"; 95 96 private static final float DEFAULT_WALLPAPER_MAX_ZOOM = 8f; 97 private static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f); 98 private static final Executor sExecutor = Executors.newCachedThreadPool(); 99 100 private final WallpaperSurfaceCallback mWallpaperSurfaceCallback = 101 new WallpaperSurfaceCallback(); 102 private final Injector mInjector = InjectorProvider.getInjector(); 103 104 /** 105 * Size of the screen considered for cropping the wallpaper (typically the same as 106 * {@link #mScreenSize} but it could be different on multi-display) 107 */ 108 private Point mWallpaperScreenSize; 109 /** 110 * The size of the current screen 111 */ 112 private Point mScreenSize; 113 protected Point mRawWallpaperSize; // Native size of wallpaper image. 114 private WallpaperPreferences mWallpaperPreferences; 115 protected Asset mWallpaperAsset; 116 protected Future<ColorInfo> mColorFuture; 117 private WallpaperPreviewBitmapTransformation mPreviewBitmapTransformation; 118 private BitmapCropper mBitmapCropper; 119 private WallpaperColorsExtractor mWallpaperColorsExtractor; 120 private DisplayUtils mDisplayUtils; 121 122 // UI 123 protected SurfaceView mWallpaperSurface; 124 protected ImageView mLowResImageView; 125 protected SubsamplingScaleImageView mFullResImageView; 126 127 @Override onCreate(Bundle savedInstanceState)128 public void onCreate(Bundle savedInstanceState) { 129 super.onCreate(savedInstanceState); 130 Context context = requireContext(); 131 Context appContext = context.getApplicationContext(); 132 mWallpaperAsset = mWallpaper.getAsset(appContext); 133 mColorFuture = mWallpaper.computeColorInfo(context); 134 mWallpaperPreferences = mInjector.getPreferences(context); 135 mPreviewBitmapTransformation = new WallpaperPreviewBitmapTransformation( 136 appContext, RtlUtils.isRtl(context)); 137 mBitmapCropper = mInjector.getBitmapCropper(); 138 mWallpaperColorsExtractor = new WallpaperColorsExtractor(sExecutor, Handler.getMain()); 139 } 140 141 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)142 public View onCreateView(LayoutInflater inflater, ViewGroup container, 143 Bundle savedInstanceState) { 144 View view = super.onCreateView(inflater, container, savedInstanceState); 145 if (view == null) { 146 return null; 147 } 148 // Until we have initialized mRawWallpaperSize, we can't set wallpaper 149 mSetWallpaperButton.setEnabled(false); 150 mSetWallpaperButtonContainer.setEnabled(false); 151 Activity activity = requireActivity(); 152 mDisplayUtils = mInjector.getDisplayUtils(activity); 153 ScreenSizeCalculator screenSizeCalculator = ScreenSizeCalculator.getInstance(); 154 mScreenSize = screenSizeCalculator.getScreenSize( 155 activity.getWindowManager().getDefaultDisplay()); 156 // "Wallpaper screen" size will be the size of the largest screen available 157 mWallpaperScreenSize = screenSizeCalculator.getScreenSize( 158 mDisplayUtils.getWallpaperDisplay()); 159 // Touch forwarding layout 160 setUpTouchForwardingLayout(); 161 // Wallpaper surface 162 mWallpaperSurface = view.findViewById(R.id.wallpaper_surface); 163 mWallpaperSurface.getHolder().addCallback(mWallpaperSurfaceCallback); 164 // Trim memory from Glide to make room for the full-size image in this fragment. 165 Glide.get(activity).setMemoryCategory(MemoryCategory.LOW); 166 return view; 167 } 168 169 @VisibleForTesting(otherwise = VisibleForTesting.NONE) getFullResImageView()170 public SubsamplingScaleImageView getFullResImageView() { 171 return mFullResImageView; 172 } 173 setUpTouchForwardingLayout()174 private void setUpTouchForwardingLayout() { 175 mTouchForwardingLayout.setForwardingEnabled(true); 176 mTouchForwardingLayout.setOnClickListener(v -> { 177 toggleWallpaperPreviewControl(); 178 mTouchForwardingLayout.announceForAccessibility( 179 getString(mPreviewScrim.getVisibility() == View.VISIBLE 180 ? R.string.show_preview_controls_content_description 181 : R.string.hide_preview_controls_content_description) 182 ); 183 }); 184 mFloatingSheet.addFloatingSheetCallback( 185 new BottomSheetBehavior.BottomSheetCallback() { 186 @Override 187 public void onStateChanged(@NonNull View bottomSheet, int newState) { 188 if (newState == STATE_EXPANDED) { 189 mTouchForwardingLayout.setForwardingEnabled(false); 190 } else if (newState == STATE_HIDDEN) { 191 mTouchForwardingLayout.setForwardingEnabled(true); 192 } 193 } 194 195 @Override 196 public void onSlide(@NonNull View bottomSheet, float slideOffset) { 197 } 198 }); 199 } 200 201 @Override onDestroy()202 public void onDestroy() { 203 if (mFullResImageView != null) { 204 mFullResImageView.recycle(); 205 } 206 mWallpaperSurfaceCallback.cleanUp(); 207 super.onDestroy(); 208 } 209 210 @Override setWallpaper(@estination int destination)211 protected void setWallpaper(@Destination int destination) { 212 Context context = getContext(); 213 if (context == null) { 214 return; 215 } 216 if (mRawWallpaperSize == null) { 217 // This shouldn't happen, avoid direct call into setWallpaper without initializing 218 // mRawWallpaperSize first 219 showSetWallpaperErrorDialog(); 220 return; 221 } 222 // Only crop extra wallpaper width for single display devices. 223 Rect cropRect = calculateCropRect(context, !mDisplayUtils.hasMultiInternalDisplays()); 224 float screenScale = WallpaperCropUtils.getScaleOfScreenResolution( 225 mFullResImageView.getScale(), cropRect, mWallpaperScreenSize.x, 226 mWallpaperScreenSize.y); 227 Rect scaledCropRect = new Rect( 228 Math.round((float) cropRect.left * screenScale), 229 Math.round((float) cropRect.top * screenScale), 230 Math.round((float) cropRect.right * screenScale), 231 Math.round((float) cropRect.bottom * screenScale)); 232 mWallpaperSetter.setCurrentWallpaper( 233 getActivity(), 234 mWallpaper, 235 mWallpaperAsset, 236 SET_WALLPAPER_ENTRY_POINT_WALLPAPER_PREVIEW, 237 destination, 238 mFullResImageView.getScale() * screenScale, 239 scaledCropRect, 240 mWallpaperColors, 241 SetWallpaperViewModel.getCallback(mViewModelProvider)); 242 } 243 244 /** 245 * Initializes image view by initializing tiling, setting a fallback page bitmap, and 246 * initializing a zoom-scroll observer and click listener. 247 */ initFullResView()248 private synchronized void initFullResView() { 249 if (mRawWallpaperSize == null || mFullResImageView == null 250 || mFullResImageView.isImageLoaded()) { 251 return; 252 } 253 254 final String storedWallpaperId = mWallpaper.getStoredWallpaperId(getContext()); 255 final boolean isWallpaperColorCached = 256 storedWallpaperId != null && mWallpaperPreferences.getWallpaperColors( 257 storedWallpaperId) != null; 258 if (isWallpaperColorCached) { 259 // Post-execute onWallpaperColorsChanged() to avoid UI blocking from the call 260 Handler.getMain().post(() -> onWallpaperColorsChanged( 261 mWallpaperPreferences.getWallpaperColors( 262 mWallpaper.getStoredWallpaperId(getContext())))); 263 } 264 265 // Minimum scale will only be respected under this scale type. 266 mFullResImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM); 267 // When we set a minimum scale bigger than the scale with which the full image is shown, 268 // disallow user to pan outside the view we show the wallpaper in. 269 mFullResImageView.setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE); 270 271 Point targetPageBitmapSize = new Point(mRawWallpaperSize); 272 mWallpaperAsset.decodeBitmap(targetPageBitmapSize.x, targetPageBitmapSize.y, 273 pageBitmap -> { 274 if (getActivity() == null || mFullResImageView == null) { 275 return; 276 } 277 278 if (pageBitmap == null) { 279 showLoadWallpaperErrorDialog(); 280 return; 281 } 282 283 mFullResImageView.setImage(ImageSource.bitmap(pageBitmap)); 284 setDefaultWallpaperZoomAndScroll( 285 mWallpaperAsset instanceof CurrentWallpaperAsset); 286 mFullResImageView.setOnStateChangedListener( 287 new OnFullResImageViewStateChangedListener() { 288 @Override 289 public void onDebouncedCenterChanged(PointF newCenter, int origin) { 290 recalculateColors(); 291 } 292 } 293 ); 294 if (!isWallpaperColorCached) { 295 mFullResImageView.setAlpha(0); 296 // If not cached, delay the cross fade until the colors extracted 297 extractColorFromBitmap(pageBitmap, true); 298 } else { 299 onSurfaceReady(); 300 } 301 }); 302 } 303 304 /** 305 * Recalculate the color from a new crop of the wallpaper. Note that we do not cache the 306 * extracted. We only cache the color the first time we extract from the wallpaper as its 307 * original size. 308 */ recalculateColors()309 private void recalculateColors() { 310 Context context = getContext(); 311 if (context == null) { 312 return; 313 } 314 315 mBitmapCropper.cropAndScaleBitmap(mWallpaperAsset, mFullResImageView.getScale(), 316 calculateCropRect(context, /* cropExtraWidth= */ true), /* adjustForRtl= */ false, 317 new BitmapCropper.Callback() { 318 @Override 319 public void onBitmapCropped(Bitmap croppedBitmap) { 320 extractColorFromBitmap(croppedBitmap, false); 321 } 322 323 @Override 324 public void onError(@Nullable Throwable e) { 325 Log.w(TAG, "Recalculate colors, crop and scale bitmap failed.", e); 326 } 327 }); 328 } 329 extractColorFromBitmap(Bitmap croppedBitmap, boolean cacheColor)330 private void extractColorFromBitmap(Bitmap croppedBitmap, boolean cacheColor) { 331 Context context = getContext(); 332 if (context == null) { 333 return; 334 } 335 336 mWallpaperColorsExtractor.extractWallpaperColors(croppedBitmap, 337 colors -> { 338 if (mFullResImageView.getAlpha() == 0) { 339 onSurfaceReady(); 340 } 341 onWallpaperColorsChanged(colors); 342 if (cacheColor) { 343 mWallpaperPreferences.storeWallpaperColors( 344 mWallpaper.getStoredWallpaperId(context), colors); 345 } 346 }); 347 } 348 349 /** 350 * This should be called when the full resolution image is loaded and the wallpaper color is 351 * ready, either extracted from the wallpaper or retrieved from cache. 352 */ onSurfaceReady()353 private void onSurfaceReady() { 354 mProgressBar.setVisibility(View.GONE); 355 crossFadeInFullResView(); 356 // Set button enabled for the visual change 357 mSetWallpaperButton.setEnabled(true); 358 // Set button container enabled to make it clickable 359 mSetWallpaperButtonContainer.setEnabled(true); 360 } 361 362 /** 363 * Fade in the full resolution view. 364 */ crossFadeInFullResView()365 protected void crossFadeInFullResView() { 366 if (getActivity() == null || !isAdded()) { 367 return; 368 } 369 long shortAnimationDuration = getResources().getInteger( 370 android.R.integer.config_shortAnimTime); 371 372 mFullResImageView.setAlpha(0f); 373 mFullResImageView.animate() 374 .alpha(1f) 375 .setInterpolator(ALPHA_OUT) 376 .setDuration(shortAnimationDuration) 377 .setListener(new AnimatorListenerAdapter() { 378 @Override 379 public void onAnimationEnd(Animator animation) { 380 if (mLowResImageView != null) { 381 mLowResImageView.setImageBitmap(null); 382 } 383 } 384 }); 385 } 386 387 /** 388 * Sets the default wallpaper zoom and scroll position based on a "crop surface" (with extra 389 * width to account for parallax) superimposed on the screen. Shows as much of the wallpaper as 390 * possible on the crop surface and align screen to crop surface such that the default preview 391 * matches what would be seen by the user in the left-most home screen. 392 * 393 * <p>This method is called once in the Fragment lifecycle after the wallpaper asset has loaded 394 * and rendered to the layout. 395 * 396 * @param offsetToStart {@code true} if we want to offset the visible rectangle to the start 397 * side of the raw wallpaper; {@code false} otherwise. 398 */ setDefaultWallpaperZoomAndScroll(boolean offsetToStart)399 private void setDefaultWallpaperZoomAndScroll(boolean offsetToStart) { 400 // Determine minimum zoom to fit maximum visible area of wallpaper on crop surface. 401 int cropWidth = mWallpaperSurface.getMeasuredWidth(); 402 int cropHeight = mWallpaperSurface.getMeasuredHeight(); 403 Point crop = new Point(cropWidth, cropHeight); 404 Rect visibleRawWallpaperRect = 405 WallpaperCropUtils.calculateVisibleRect(mRawWallpaperSize, crop); 406 if (offsetToStart && mDisplayUtils.isSingleDisplayOrUnfoldedHorizontalHinge( 407 requireActivity())) { 408 if (RtlUtils.isRtl(requireContext())) { 409 visibleRawWallpaperRect.offsetTo(mRawWallpaperSize.x 410 - visibleRawWallpaperRect.width(), visibleRawWallpaperRect.top); 411 } else { 412 visibleRawWallpaperRect.offsetTo(/* newLeft= */ 0, visibleRawWallpaperRect.top); 413 } 414 } 415 416 final PointF centerPosition = new PointF(visibleRawWallpaperRect.centerX(), 417 visibleRawWallpaperRect.centerY()); 418 419 Point visibleRawWallpaperSize = new Point(visibleRawWallpaperRect.width(), 420 visibleRawWallpaperRect.height()); 421 422 final float defaultWallpaperZoom = WallpaperCropUtils.calculateMinZoom( 423 visibleRawWallpaperSize, crop); 424 425 // Set min wallpaper zoom and max zoom for the full resolution image view 426 mFullResImageView.setMaxScale(Math.max(DEFAULT_WALLPAPER_MAX_ZOOM, defaultWallpaperZoom)); 427 mFullResImageView.setMinScale(defaultWallpaperZoom); 428 429 // Set center to composite positioning between scaled wallpaper and screen 430 mFullResImageView.setScaleAndCenter(defaultWallpaperZoom, centerPosition); 431 } 432 calculateCropRect(Context context, boolean cropExtraWidth)433 private Rect calculateCropRect(Context context, boolean cropExtraWidth) { 434 float wallpaperZoom = mFullResImageView.getScale(); 435 Context appContext = context.getApplicationContext(); 436 437 Rect visibleFileRect = new Rect(); 438 mFullResImageView.visibleFileRect(visibleFileRect); 439 440 int cropWidth = mWallpaperSurface.getMeasuredWidth(); 441 int cropHeight = mWallpaperSurface.getMeasuredHeight(); 442 int maxCrop = Math.max(cropWidth, cropHeight); 443 int minCrop = Math.min(cropWidth, cropHeight); 444 Point hostViewSize = new Point(cropWidth, cropHeight); 445 446 Resources res = appContext.getResources(); 447 Point cropSurfaceSize = WallpaperCropUtils.calculateCropSurfaceSize(res, maxCrop, minCrop, 448 cropWidth, cropHeight); 449 Rect result = WallpaperCropUtils.calculateCropRect(appContext, hostViewSize, 450 cropSurfaceSize, mRawWallpaperSize, visibleFileRect, wallpaperZoom, cropExtraWidth); 451 452 // Cancel the rescaling in the multi crop case. In that case the crop will be sent to 453 // WallpaperManager. WallpaperManager expects a crop that is not yet rescaled to match 454 // the screen size (as opposed to BitmapCropper which is used in the single crop case). 455 // TODO(b/270726737, b/281648899) clean that comment and that part of the code 456 if (WallpaperManager.isMultiCropEnabled()) result.scale(1f / mFullResImageView.getScale()); 457 return result; 458 } 459 460 /** 461 * surfaceCreated() is called right after Fragment.onResume() and surfaceDestroyed() is called 462 * after Fragment.onPause(). We do not clean up the surface when surfaceDestroyed() and hold 463 * it till the next onResume(). We do not need to decode the image again and thus can skip the 464 * whole logic in surfaceCreated(). 465 */ 466 private class WallpaperSurfaceCallback implements SurfaceHolder.Callback { 467 private Surface mLastSurface; 468 private SurfaceControlViewHost mHost; 469 470 @Override surfaceCreated(SurfaceHolder holder)471 public void surfaceCreated(SurfaceHolder holder) { 472 Context context = getContext(); 473 Activity activity = getActivity(); 474 if (context == null || activity == null || mLastSurface == holder.getSurface()) { 475 return; 476 } 477 478 mLastSurface = holder.getSurface(); 479 if (mFullResImageView != null) { 480 mFullResImageView.recycle(); 481 } 482 483 mProgressBar.setVisibility(View.VISIBLE); 484 View wallpaperPreviewContainer = LayoutInflater.from(context).inflate( 485 R.layout.fullscreen_wallpaper_preview_old, null); 486 mFullResImageView = wallpaperPreviewContainer.findViewById(R.id.full_res_image); 487 mLowResImageView = wallpaperPreviewContainer.findViewById(R.id.low_res_image); 488 mLowResImageView.setRenderEffect( 489 RenderEffect.createBlurEffect(LOW_RES_BITMAP_BLUR_RADIUS, 490 LOW_RES_BITMAP_BLUR_RADIUS, Shader.TileMode.CLAMP)); 491 // Calculate the size of mWallpaperSurface based on system zoom's scale and 492 // on the larger screen size (if more than one) so that the wallpaper is 493 // rendered in a larger surface than what preview shows, simulating the behavior of 494 // the actual wallpaper surface and so we can crop it to a size that fits in all 495 // screens. 496 float scale = WallpaperCropUtils.getSystemWallpaperMaximumScale(context); 497 int origWidth = mWallpaperSurface.getWidth(); 498 int origHeight = mWallpaperSurface.getHeight(); 499 500 int scaledOrigWidth = origWidth; 501 int scaledOrigHeight = origHeight; 502 503 if (mDisplayUtils.hasMultiInternalDisplays()) { 504 final Point maxDisplaysDimen = mDisplayUtils.getMaxDisplaysDimension(); 505 scaledOrigWidth = Math.round( 506 origWidth * Math.max(1, (float) maxDisplaysDimen.x / mScreenSize.x)); 507 scaledOrigHeight = Math.round( 508 origHeight * Math.max(1, (float) maxDisplaysDimen.y / mScreenSize.y)); 509 } 510 int width = (int) (scaledOrigWidth * scale); 511 int height = (int) (scaledOrigHeight * scale); 512 int left = (origWidth - width) / 2; 513 int top = (origHeight - height) / 2; 514 515 if (RtlUtils.isRtl(context)) { 516 left *= -1; 517 } 518 519 LayoutParams params = mWallpaperSurface.getLayoutParams(); 520 params.width = width; 521 params.height = height; 522 mWallpaperSurface.setX(left); 523 mWallpaperSurface.setY(top); 524 mWallpaperSurface.setLayoutParams(params); 525 mWallpaperSurface.requestLayout(); 526 527 // Load low res image first before the full res image is available 528 int placeHolderColor = ResourceUtils.getColorAttr(activity, 529 android.R.attr.colorBackground); 530 if (mColorFuture.isDone()) { 531 try { 532 int colorValue = mColorFuture.get().getPlaceholderColor(); 533 if (colorValue != Color.TRANSPARENT) { 534 placeHolderColor = colorValue; 535 } 536 } catch (InterruptedException | ExecutionException e) { 537 // Do nothing intended 538 } 539 } 540 mWallpaperAsset.loadLowResDrawable(activity, mLowResImageView, placeHolderColor, 541 mPreviewBitmapTransformation); 542 543 wallpaperPreviewContainer.measure( 544 makeMeasureSpec(width, EXACTLY), 545 makeMeasureSpec(height, EXACTLY)); 546 wallpaperPreviewContainer.layout(0, 0, width, height); 547 mTouchForwardingLayout.setTargetView(mFullResImageView); 548 549 cleanUp(); 550 mHost = new SurfaceControlViewHost(context, 551 context.getDisplay(), mWallpaperSurface.getHostToken()); 552 mHost.setView(wallpaperPreviewContainer, wallpaperPreviewContainer.getWidth(), 553 wallpaperPreviewContainer.getHeight()); 554 mWallpaperSurface.setChildSurfacePackage(mHost.getSurfacePackage()); 555 556 mWallpaperAsset.decodeRawDimensions(getActivity(), dimensions -> { 557 if (getActivity() == null) { 558 return; 559 } 560 561 if (dimensions == null) { 562 showLoadWallpaperErrorDialog(); 563 return; 564 } 565 566 mRawWallpaperSize = dimensions; 567 // We can enable set wallpaper now but defer to full res view ready 568 initFullResView(); 569 }); 570 } 571 572 @Override surfaceChanged(SurfaceHolder holder, int format, int width, int height)573 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 574 // Do nothing intended 575 } 576 577 @Override surfaceDestroyed(SurfaceHolder holder)578 public void surfaceDestroyed(SurfaceHolder holder) { 579 // Do nothing intended 580 } 581 cleanUp()582 public void cleanUp() { 583 if (mHost != null) { 584 mHost.release(); 585 mHost = null; 586 } 587 } 588 } 589 } 590