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.app.Activity.RESULT_OK; 19 import static android.app.WallpaperManager.FLAG_LOCK; 20 import static android.app.WallpaperManager.FLAG_SYSTEM; 21 import static android.stats.style.StyleEnums.SET_WALLPAPER_ENTRY_POINT_WALLPAPER_PREVIEW; 22 import static android.view.View.GONE; 23 import static android.view.View.VISIBLE; 24 25 import static com.android.wallpaper.module.WallpaperPersister.destinationToFlags; 26 27 import android.annotation.SuppressLint; 28 import android.app.Activity; 29 import android.app.AlertDialog; 30 import android.app.WallpaperColors; 31 import android.app.WallpaperInfo; 32 import android.app.WallpaperManager; 33 import android.content.ComponentName; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.content.pm.ActivityInfo; 37 import android.content.pm.PackageManager; 38 import android.graphics.Color; 39 import android.net.Uri; 40 import android.os.Bundle; 41 import android.os.RemoteException; 42 import android.service.wallpaper.IWallpaperConnection; 43 import android.service.wallpaper.WallpaperService; 44 import android.service.wallpaper.WallpaperSettingsActivity; 45 import android.util.Log; 46 import android.view.LayoutInflater; 47 import android.view.MotionEvent; 48 import android.view.SurfaceView; 49 import android.view.View; 50 import android.view.ViewGroup; 51 import android.widget.ImageView; 52 53 import androidx.activity.OnBackPressedCallback; 54 import androidx.activity.result.ActivityResultCallback; 55 import androidx.activity.result.ActivityResultLauncher; 56 import androidx.annotation.NonNull; 57 import androidx.annotation.Nullable; 58 import androidx.fragment.app.FragmentActivity; 59 60 import com.android.wallpaper.R; 61 import com.android.wallpaper.model.CreativeWallpaperInfo; 62 import com.android.wallpaper.model.SetWallpaperViewModel; 63 import com.android.wallpaper.model.WallpaperAction; 64 import com.android.wallpaper.model.WallpaperInfo.ColorInfo; 65 import com.android.wallpaper.module.WallpaperPersister; 66 import com.android.wallpaper.util.DeletableUtils; 67 import com.android.wallpaper.util.ResourceUtils; 68 import com.android.wallpaper.util.RtlUtils; 69 import com.android.wallpaper.util.WallpaperConnection; 70 import com.android.wallpaper.util.WallpaperSurfaceCallback2; 71 import com.android.wallpaper.widget.FloatingSheet; 72 import com.android.wallpaper.widget.WallpaperColorsLoader; 73 import com.android.wallpaper.widget.WallpaperControlButtonGroup; 74 import com.android.wallpaper.widget.floatingsheetcontent.PreviewCustomizeSettingsContent; 75 import com.android.wallpaper.widget.floatingsheetcontent.WallpaperActionSelectionBottomSheetContent; 76 import com.android.wallpaper.widget.floatingsheetcontent.WallpaperActionsToggleAdapter; 77 78 import java.util.ArrayList; 79 import java.util.concurrent.ExecutionException; 80 import java.util.concurrent.ExecutorService; 81 import java.util.concurrent.Executors; 82 import java.util.concurrent.Future; 83 import java.util.concurrent.TimeUnit; 84 import java.util.concurrent.TimeoutException; 85 86 /** 87 * Fragment which displays the UI for previewing an individual live wallpaper, its attribution 88 * information and settings slices if available. 89 */ 90 public class LivePreviewFragment extends PreviewFragment { 91 92 public static final String EXTRA_LIVE_WALLPAPER_INFO = "android.live_wallpaper.info"; 93 public static final String KEY_ACTION_DELETE_LIVE_WALLPAPER = "action_delete_live_wallpaper"; 94 95 private static final String TAG = "LivePreviewFragment"; 96 private static final String KEY_TOOLBAR_GONE = "toolbar_gone"; 97 private static final ExecutorService sExecutorService = Executors.newCachedThreadPool(); 98 private ActivityResultLauncher<Void> mSettingsActivityResult; 99 private ActivityResultLauncher<Void> mShareActivityResult; 100 private Intent mSettingsActivityIntent; 101 private WallpaperActionSelectionBottomSheetContent mWallpaperActionSelectionBottomSheetContent; 102 private OnBackPressedCallback mSettingsOnBackPressedCallback; 103 private boolean mHasCalledOnSaveInstanceState = false; 104 private boolean mHideOverlaysForShowingSettingsActivity = false; 105 private Future<ColorInfo> mColorFuture; 106 /** 107 * Instance of {@link WallpaperConnection} used to bind to the live wallpaper service to show 108 * it in this preview fragment. 109 * 110 * @see IWallpaperConnection 111 */ 112 private WallpaperConnection mWallpaperConnection; 113 private WallpaperSurfaceCallback2 mWallpaperSurfaceCallback; 114 private SurfaceView mWallpaperSurface; 115 116 @Override setWallpaper(int destination)117 protected void setWallpaper(int destination) { 118 WallpaperPersister.SetWallpaperCallback callback = SetWallpaperViewModel.getCallback( 119 mViewModelProvider); 120 if (mWallpaperConnection != null) { 121 try { 122 mWallpaperConnection.setWallpaperFlags(destinationToFlags(destination)); 123 } catch (RemoteException e) { 124 callback.onError(e); 125 return; 126 } 127 } 128 mWallpaperSetter.setCurrentWallpaper( 129 getActivity(), 130 mWallpaper, 131 null, 132 SET_WALLPAPER_ENTRY_POINT_WALLPAPER_PREVIEW, 133 destination, 134 0, 135 null, 136 mWallpaperColors != null ? mWallpaperColors : getColorInfo().getWallpaperColors(), 137 callback); 138 } 139 140 141 @Override onCreate(Bundle savedInstanceState)142 public void onCreate(Bundle savedInstanceState) { 143 super.onCreate(savedInstanceState); 144 Context context = requireContext(); 145 mColorFuture = mWallpaper.computeColorInfo(context); 146 mSettingsActivityIntent = getSettingsActivityIntent(getContext(), 147 mWallpaper.getWallpaperComponent()); 148 mSettingsOnBackPressedCallback = new OnBackPressedCallback(true) { 149 @Override 150 public void handleOnBackPressed() { 151 launchSettingsAsOverlay(/* isLaunched= */ false); 152 } 153 }; 154 if (mWallpaper instanceof CreativeWallpaperInfo) { 155 mSettingsActivityResult = registerForActivityResult( 156 CreativeWallpaperInfo.getContract(mSettingsActivityIntent), 157 getCreativeWallpaperPreviewResultCallback()); 158 CreativeWallpaperInfo creativeWallpaper = (CreativeWallpaperInfo) mWallpaper; 159 if (creativeWallpaper.canBeShared()) { 160 mShareActivityResult = registerForActivityResult(CreativeWallpaperInfo.getContract( 161 creativeWallpaper.getShareIntent()), 162 unused -> mWallpaperControlButtonGroup.setChecked( 163 WallpaperControlButtonGroup.SHARE, /* checked= */ false)); 164 } 165 } 166 } 167 getCreativeWallpaperPreviewResultCallback()168 private ActivityResultCallback<Integer> getCreativeWallpaperPreviewResultCallback() { 169 return result -> { 170 CreativeWallpaperInfo creativeWallpaper = (CreativeWallpaperInfo) mWallpaper; 171 WallpaperManager wallpaperManager = WallpaperManager.getInstance(getContext()); 172 boolean isCreativeWallpaperApplied = creativeWallpaper.isApplied( 173 wallpaperManager.getWallpaperInfo(FLAG_SYSTEM), 174 wallpaperManager.getWallpaperInfo(FLAG_LOCK)); 175 if (result == RESULT_OK) { 176 if (creativeWallpaper.canBeDeleted() || isCreativeWallpaperApplied) { 177 // When editing an existing wallpaper and pressing "Done" button causing the 178 // overlays to become visible 179 showOverlays(); 180 overrideOnBackPressed(new OnBackPressedCallback(true) { 181 @Override 182 public void handleOnBackPressed() { 183 getActivity().finish(); 184 } 185 }); 186 } else { 187 // When in the process of creating a new wallpaper and pressing "Done" button. 188 showOverlays(); 189 overrideOnBackPressed(mSettingsOnBackPressedCallback); 190 } 191 } else { 192 // When you initiate the editing process for a wallpaper and then decide to exit 193 // by pressing the back button during editing. 194 if (creativeWallpaper.canBeDeleted() || isCreativeWallpaperApplied) { 195 showOverlays(); 196 } else { 197 // Flow where user opens a template (so the settings activity is launched) 198 // but user just simply presses back (without moving on to the next screen) 199 // TODO: This should ideally be a slide transition, but custom slide transition 200 // does not work properly, so having a fade transition for now 201 finishActivityWithFadeTransition(); 202 } 203 } 204 }; 205 } 206 207 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)208 public View onCreateView(LayoutInflater inflater, ViewGroup container, 209 Bundle savedInstanceState) { 210 View view = super.onCreateView(inflater, container, savedInstanceState); 211 if (view == null) { 212 return null; 213 } 214 // Live wallpaper surface 215 Context context = requireContext(); 216 mWallpaperSurface = view.findViewById(R.id.wallpaper_surface); 217 mWallpaperSurfaceCallback = new WallpaperSurfaceCallback2(context, mWallpaperSurface, 218 mColorFuture, this::previewLiveWallpaper); 219 mWallpaperSurface.getHolder().addCallback(mWallpaperSurfaceCallback); 220 mWallpaperSurface.setZOrderMediaOverlay(true); 221 setUpLiveWallpaperTouchForwarding(mTouchForwardingLayout); 222 showLiveWallpaperControl(); 223 return view; 224 } 225 getEffectSwitchListener( Context context, CreativeWallpaperInfo creativeWallpaper)226 private WallpaperActionsToggleAdapter.WallpaperEffectSwitchListener getEffectSwitchListener( 227 Context context, CreativeWallpaperInfo creativeWallpaper) { 228 return (checkedItem) -> { 229 for (WallpaperAction wallpaperActionToggle : creativeWallpaper.getEffectsToggles()) { 230 wallpaperActionToggle.setToggled(false); 231 } 232 233 if (checkedItem >= 0) { 234 WallpaperAction currentEffect = 235 creativeWallpaper.getEffectsToggles().get( 236 checkedItem); 237 currentEffect.setToggled(true); 238 creativeWallpaper 239 .setCurrentlyAppliedEffectId( 240 currentEffect.getEffectId()); 241 creativeWallpaper.applyEffect(context, 242 currentEffect.getApplyActionUri()); 243 mWallpaperActionSelectionBottomSheetContent.setCurrentlyAppliedEffect( 244 currentEffect.getEffectId()); 245 } else { 246 creativeWallpaper.setCurrentlyAppliedEffectId(null); 247 creativeWallpaper.clearEffects(context); 248 mWallpaperActionSelectionBottomSheetContent.setCurrentlyAppliedEffect(null); 249 } 250 }; 251 } 252 253 @SuppressLint("ClickableViewAccessibility") 254 private void setUpLiveWallpaperTouchForwarding(TouchForwardingLayout touchForwardingLayout) { 255 touchForwardingLayout.setTargetView(mWallpaperSurface); 256 touchForwardingLayout.setForwardingEnabled(true); 257 touchForwardingLayout.setOnClickListener(v -> { 258 toggleWallpaperPreviewControl(); 259 mTouchForwardingLayout.announceForAccessibility( 260 getString(mPreviewScrim.getVisibility() == View.VISIBLE 261 ? R.string.show_preview_controls_content_description 262 : R.string.hide_preview_controls_content_description) 263 ); 264 }); 265 mWallpaperSurface.setOnTouchListener((v, ev) -> { 266 dispatchTouchEventOnLiveWallpaperSurface(ev); 267 return false; 268 }); 269 } 270 271 private void dispatchTouchEventOnLiveWallpaperSurface(MotionEvent ev) { 272 if (mWallpaperConnection != null && mWallpaperConnection.getEngine() != null) { 273 int action = ev.getActionMasked(); 274 MotionEvent dup = MotionEvent.obtainNoHistory(ev); 275 dup.setLocation(ev.getX(), ev.getY()); 276 try { 277 mWallpaperConnection.getEngine().dispatchPointer(dup); 278 if (action == MotionEvent.ACTION_UP) { 279 mWallpaperConnection.getEngine().dispatchWallpaperCommand( 280 WallpaperManager.COMMAND_TAP, 281 (int) ev.getX(), (int) ev.getY(), 0, null); 282 } else if (action == MotionEvent.ACTION_POINTER_UP) { 283 int pointerIndex = ev.getActionIndex(); 284 mWallpaperConnection.getEngine().dispatchWallpaperCommand( 285 WallpaperManager.COMMAND_SECONDARY_TAP, 286 (int) ev.getX(pointerIndex), (int) ev.getY(pointerIndex), 0, 287 null); 288 } 289 } catch (RemoteException e) { 290 Log.e(TAG, "Remote exception of wallpaper connection"); 291 } 292 } 293 } 294 295 protected void showLiveWallpaperControl() { 296 mSetWallpaperButton.setVisibility(VISIBLE); 297 if (mWallpaper instanceof CreativeWallpaperInfo) { 298 CreativeWallpaperInfo creativeWallpaper = (CreativeWallpaperInfo) mWallpaper; 299 mWallpaperControlButtonGroup.showButton( 300 WallpaperControlButtonGroup.EDIT, 301 (buttonView, isChecked) -> { 302 if (isChecked) { 303 launchSettingsAsOverlay(/* isLaunched= */ false); 304 } 305 mWallpaperControlButtonGroup.setChecked( 306 WallpaperControlButtonGroup.EDIT, false); 307 }); 308 WallpaperManager wallpaperManager = WallpaperManager.getInstance(getContext()); 309 boolean isCreativeWallpaperApplied = creativeWallpaper.isApplied( 310 wallpaperManager.getWallpaperInfo(FLAG_SYSTEM), 311 wallpaperManager.getWallpaperInfo(FLAG_LOCK)); 312 if (!isCreativeWallpaperApplied && creativeWallpaper.canBeDeleted()) { 313 mWallpaperControlButtonGroup.showButton( 314 WallpaperControlButtonGroup.DELETE, 315 (buttonView, isChecked) -> { 316 if (isChecked) { 317 showDeleteConfirmDialog( 318 () -> creativeWallpaper.requestDelete(requireContext())); 319 } 320 }); 321 } else { 322 mWallpaperControlButtonGroup.hideButton(WallpaperControlButtonGroup.DELETE); 323 } 324 if (creativeWallpaper.canBeShared() && mShareActivityResult != null) { 325 mWallpaperControlButtonGroup.showButton( 326 WallpaperControlButtonGroup.SHARE, 327 (buttonView, isChecked) -> { 328 if (isChecked) { 329 mShareActivityResult.launch(null); 330 } 331 }); 332 } 333 334 if (creativeWallpaper.doesSupportWallpaperEffects()) { 335 showWallpaperEffectsButton(); 336 } 337 } else if (DeletableUtils.canBeDeleted(requireContext(), 338 mWallpaper.getWallpaperComponent())) { 339 mWallpaperControlButtonGroup.showButton(WallpaperControlButtonGroup.DELETE, 340 (buttonView, isChecked) -> { 341 if (isChecked) { 342 showDeleteConfirmDialog(() -> { 343 Context context = getContext(); 344 if (context != null) { 345 DeletableUtils.deleteLiveWallpaper(context, mWallpaper); 346 } 347 } 348 ); 349 } 350 }); 351 } 352 WallpaperInfo info = mWallpaper.getWallpaperComponent(); 353 Uri uriSettingsSlice = getSettingsSliceUri(info); 354 if (uriSettingsSlice != null) { 355 mFloatingSheet.putFloatingSheetContent(FloatingSheet.CUSTOMIZE, 356 new PreviewCustomizeSettingsContent(requireContext(), uriSettingsSlice)); 357 mWallpaperControlButtonGroup.showButton(WallpaperControlButtonGroup.CUSTOMIZE, 358 getFloatingSheetControlButtonChangeListener( 359 WallpaperControlButtonGroup.CUSTOMIZE, FloatingSheet.CUSTOMIZE)); 360 } else if (mSettingsActivityIntent != null 361 && !(mWallpaper instanceof CreativeWallpaperInfo)) { 362 mWallpaperControlButtonGroup.showButton( 363 WallpaperControlButtonGroup.CUSTOMIZE, 364 (buttonView, isChecked) -> startActivity(mSettingsActivityIntent)); 365 } 366 // update button group top margin 367 ViewGroup.MarginLayoutParams params = 368 (ViewGroup.MarginLayoutParams) mWallpaperControlButtonGroup.getLayoutParams(); 369 params.topMargin = getResources().getDimensionPixelSize( 370 R.dimen.wallpaper_control_button_group_margin_top); 371 mWallpaperControlButtonGroup.requestLayout(); 372 } 373 374 private void showWallpaperEffectsButton() { 375 mWallpaperControlButtonGroup.showButton(WallpaperControlButtonGroup.EFFECTS, 376 getFloatingSheetControlButtonChangeListener(WallpaperControlButtonGroup.EFFECTS, 377 FloatingSheet.EFFECTS)); 378 } 379 380 private void launchSettingsAsOverlay(boolean isLaunched) { 381 hideOverlays(); 382 mSettingsOnBackPressedCallback.remove(); 383 if (!isLaunched) { 384 mSettingsActivityResult.launch(null); 385 } 386 } 387 388 private void hideOverlays() { 389 mToolbar.setVisibility(GONE); 390 mSetWallpaperButton.setVisibility(GONE); 391 mWallpaperControlButtonGroup.setVisibility(GONE); 392 // remove callback to prevent overlay from showing again after floating sheet collapses 393 mFloatingSheet.removeFloatingSheetCallback(mShowOverlayOnHideFloatingSheetCallback); 394 mFloatingSheet.setVisibility(GONE); 395 // deselects all control buttons and sets floating sheet to collapse 396 mWallpaperControlButtonGroup.deselectAllFloatingSheetControlButtons(); 397 hideScreenPreviewOverlay(true); 398 mHideOverlaysForShowingSettingsActivity = true; 399 } 400 401 private void showOverlays() { 402 mToolbar.setVisibility(VISIBLE); 403 mSetWallpaperButton.setVisibility(VISIBLE); 404 mWallpaperControlButtonGroup.setVisibility(VISIBLE); 405 mFloatingSheet.addFloatingSheetCallback(mShowOverlayOnHideFloatingSheetCallback); 406 mFloatingSheet.setVisibility(VISIBLE); 407 hideScreenPreviewOverlay(false); 408 mHideOverlaysForShowingSettingsActivity = false; 409 } 410 411 protected void overrideOnBackPressed(OnBackPressedCallback onBackPressedCallback) { 412 FragmentActivity activity = getActivity(); 413 if (activity == null) { 414 return; 415 } 416 activity.getOnBackPressedDispatcher().addCallback( 417 getViewLifecycleOwner(), 418 onBackPressedCallback 419 ); 420 } 421 422 @Override 423 public void onSaveInstanceState(@NonNull Bundle outState) { 424 mHasCalledOnSaveInstanceState = true; 425 outState.putBoolean(KEY_TOOLBAR_GONE, mToolbar.getVisibility() == GONE); 426 super.onSaveInstanceState(outState); 427 } 428 429 private void initializeEffectButton(CreativeWallpaperInfo creativeWallpaper, Context context) { 430 if (!creativeWallpaper.doesSupportWallpaperEffects()) { 431 return; 432 } 433 434 sExecutorService.execute(() -> { 435 ArrayList<WallpaperAction> effects = creativeWallpaper.getWallpaperEffects(context); 436 if (effects == null) { 437 return; 438 } 439 440 creativeWallpaper.setEffectsToggles(effects); 441 mWallpaperActionSelectionBottomSheetContent = 442 createWallpaperActionSelectionBottomSheetContent(context, creativeWallpaper); 443 mFloatingSheet.putFloatingSheetContent(FloatingSheet.EFFECTS, 444 mWallpaperActionSelectionBottomSheetContent); 445 }); 446 } 447 448 private WallpaperActionSelectionBottomSheetContent 449 createWallpaperActionSelectionBottomSheetContent(Context context, 450 CreativeWallpaperInfo creativeWallpaper) { 451 return new WallpaperActionSelectionBottomSheetContent(context, 452 creativeWallpaper.getEffectsBottomSheetTitle(), 453 creativeWallpaper.getEffectsBottomSheetSubtitle(), 454 creativeWallpaper.getClearActionsUri(), 455 creativeWallpaper.getEffectsToggles(), 456 creativeWallpaper.getCurrentlyAppliedEffectId(), 457 getEffectSwitchListener(context, creativeWallpaper)); 458 } 459 460 @Override 461 public void onViewStateRestored(@Nullable Bundle savedInstanceState) { 462 mHasCalledOnSaveInstanceState = false; 463 if (mWallpaper instanceof CreativeWallpaperInfo) { 464 Context context = requireContext(); 465 CreativeWallpaperInfo creativeWallpaper = (CreativeWallpaperInfo) mWallpaper; 466 boolean isSettingsActivityPresent = savedInstanceState != null 467 && savedInstanceState.getBoolean(KEY_TOOLBAR_GONE, false); 468 initializeEffectButton(creativeWallpaper, context); 469 if (savedInstanceState == null) { 470 // First time at Fragment should initialize wallpaper preview. 471 creativeWallpaper.initializeWallpaperPreview(context); 472 } 473 474 if (savedInstanceState == null || isSettingsActivityPresent) { 475 WallpaperManager wallpaperManager = WallpaperManager.getInstance(context); 476 boolean isCreativeWallpaperApplied = creativeWallpaper.isApplied( 477 wallpaperManager.getWallpaperInfo(FLAG_SYSTEM), 478 wallpaperManager.getWallpaperInfo(FLAG_LOCK)); 479 // First time at Fragment or settings activity is at present. 480 if (!isCreativeWallpaperApplied && !creativeWallpaper.canBeDeleted()) { 481 // If it cannot be deleted, we must be creating a new one, launch settings. 482 // savedInstanceState != null means is rotate state and previous fragment 483 // already launch settings. 484 launchSettingsAsOverlay(/* isLaunched= */ savedInstanceState != null); 485 } else if (isSettingsActivityPresent) { 486 hideOverlays(); 487 mSettingsOnBackPressedCallback.remove(); 488 } 489 490 } else { 491 showOverlays(); 492 overrideOnBackPressed(mSettingsOnBackPressedCallback); 493 } 494 } 495 super.onViewStateRestored(savedInstanceState); 496 } 497 498 @Override 499 public void onDestroy() { 500 // Clean up the surface view 501 if (mWallpaperConnection != null) { 502 mWallpaperConnection.destroy(); 503 mWallpaperConnection = null; 504 } 505 mWallpaperSurfaceCallback.cleanUp(); 506 mWallpaperSurface.getHolder().removeCallback(mWallpaperSurfaceCallback); 507 508 if (mWallpaper instanceof CreativeWallpaperInfo) { 509 if (!mHasCalledOnSaveInstanceState) { 510 // onDestroy without rotation should clean up wallpaper preview. 511 ((CreativeWallpaperInfo) mWallpaper).cleanUpWallpaperPreview(getContext()); 512 } 513 } 514 super.onDestroy(); 515 } 516 517 private void previewLiveWallpaper() { 518 mWallpaperSurface.post(() -> { 519 ImageView homeImageWallpaper = mWallpaperSurfaceCallback.getHomeImageWallpaper(); 520 if (homeImageWallpaper != null) { 521 loadPreviewImage(homeImageWallpaper); 522 } 523 setUpLiveWallpaperPreview(mWallpaper); 524 }); 525 } 526 527 protected void loadPreviewImage(ImageView homeImageWallpaper) { 528 Context context = getContext(); 529 Context appContext = context != null ? context.getApplicationContext() : null; 530 Activity activity = getActivity(); 531 if (activity == null || appContext == null) { 532 return; 533 } 534 mWallpaperSurfaceCallback.setHomeImageWallpaperBlur(true); 535 ColorInfo colorInfo = getColorInfo(); 536 Integer placeholderColor = colorInfo.getPlaceholderColor(); 537 // This is for showing a lower resolution image before the live wallpaper shows 538 WallpaperPreviewBitmapTransformation transformation = 539 new WallpaperPreviewBitmapTransformation(appContext, RtlUtils.isRtl(context)); 540 mWallpaper.getThumbAsset(activity.getApplicationContext()) 541 .loadLowResDrawable(activity, 542 homeImageWallpaper, 543 placeholderColor != null 544 ? placeholderColor 545 : ResourceUtils.getColorAttr(activity, 546 android.R.attr.colorBackground), 547 transformation); 548 } 549 550 private ColorInfo getColorInfo() { 551 try { 552 return mColorFuture.get(50, TimeUnit.MILLISECONDS); 553 } catch (InterruptedException | ExecutionException | TimeoutException e) { 554 Log.i(TAG, "Couldn't obtain placeholder color", e); 555 } 556 return new ColorInfo(new WallpaperColors(Color.valueOf(Color.TRANSPARENT), 557 /* secondaryColor= */ null, /* tertiaryColor= */ null), 558 /* placeholderColor= */ null); 559 } 560 561 protected void setUpLiveWallpaperPreview( 562 com.android.wallpaper.model.WallpaperInfo homeWallpaper) { 563 Activity activity = getActivity(); 564 if (activity == null || activity.isFinishing()) { 565 return; 566 } 567 568 if (mWallpaperConnection != null) { 569 mWallpaperConnection.disconnect(); 570 } 571 572 if (WallpaperConnection.isPreviewAvailable()) { 573 android.app.WallpaperInfo info = homeWallpaper.getWallpaperComponent(); 574 Intent wallpaperIntent = new Intent(WallpaperService.SERVICE_INTERFACE) 575 .setClassName(info.getPackageName(), info.getServiceName()); 576 mWallpaperConnection = new WallpaperConnection( 577 wallpaperIntent, 578 activity, 579 new WallpaperConnection.WallpaperConnectionListener() { 580 @Override 581 public void onEngineShown() { 582 Activity activity = getActivity(); 583 if (activity == null) { 584 return; 585 } 586 ImageView homeImageWallpaper = 587 mWallpaperSurfaceCallback.getHomeImageWallpaper(); 588 if (homeImageWallpaper != null) { 589 homeImageWallpaper.animate() 590 .setStartDelay(250) 591 .setDuration(250) 592 .alpha(0f) 593 .setInterpolator(PreviewFragment.ALPHA_OUT) 594 .start(); 595 } 596 } 597 598 @Override 599 public void onWallpaperColorsChanged(WallpaperColors colors, 600 int displayId) { 601 LivePreviewFragment.super.onWallpaperColorsChanged(colors); 602 } 603 }, 604 mWallpaperSurface, 605 null, 606 mIsViewAsHome ? FLAG_SYSTEM : FLAG_LOCK, 607 mIsAssetIdPresent ? WallpaperConnection.WhichPreview.EDIT_NON_CURRENT 608 : WallpaperConnection.WhichPreview.EDIT_CURRENT); 609 mWallpaperConnection.setVisibility(true); 610 } else { 611 WallpaperColorsLoader.getWallpaperColors( 612 activity, 613 homeWallpaper.getThumbAsset(activity), 614 this::onWallpaperColorsChanged); 615 } 616 617 if (mWallpaperConnection != null && !mWallpaperConnection.connect()) { 618 mWallpaperConnection = null; 619 } 620 } 621 622 @Override 623 public void onResume() { 624 super.onResume(); 625 if (mWallpaperConnection != null) { 626 mWallpaperConnection.setVisibility(true); 627 } 628 } 629 630 @Override 631 public void onPause() { 632 super.onPause(); 633 if (mWallpaperConnection != null) { 634 mWallpaperConnection.setVisibility(mHideOverlaysForShowingSettingsActivity); 635 } 636 } 637 638 protected void showDeleteConfirmDialog(Runnable deleteRunnable) { 639 final AlertDialog alertDialog = new AlertDialog.Builder(getContext()) 640 .setMessage(R.string.delete_wallpaper_confirmation) 641 .setOnDismissListener(dialog -> mWallpaperControlButtonGroup.setChecked( 642 WallpaperControlButtonGroup.DELETE, false)) 643 .setPositiveButton(R.string.delete_live_wallpaper, 644 (dialog, which) -> { 645 deleteRunnable.run(); 646 finishActivityWithFadeTransition(); 647 }) 648 .setNegativeButton(android.R.string.cancel, null /* listener */) 649 .create(); 650 alertDialog.show(); 651 } 652 653 @Nullable 654 private Intent getSettingsActivityIntent(Context context, WallpaperInfo info) { 655 String settingsActivity = info.getSettingsActivity(); 656 if (context == null || settingsActivity == null) { 657 return null; 658 } 659 Intent intent = new Intent(); 660 intent.setComponent( 661 new ComponentName(info.getPackageName(), settingsActivity)); 662 intent.putExtra(WallpaperSettingsActivity.EXTRA_PREVIEW_MODE, true); 663 PackageManager pm = context.getPackageManager(); 664 ActivityInfo activityInfo = intent.resolveActivityInfo(pm, 0); 665 if (activityInfo == null) { 666 Log.i(TAG, "Couldn't find wallpaper settings activity: " + settingsActivity); 667 return null; 668 } 669 return intent; 670 } 671 672 private Uri getSettingsSliceUri(android.app.WallpaperInfo info) { 673 return info.getSettingsSliceUri(); 674 } 675 } 676