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