1 /* 2 * Copyright (C) 2017 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 com.android.wallpaper.widget.BottomActionBar.BottomAction.APPLY; 19 import static com.android.wallpaper.widget.BottomActionBar.BottomAction.EDIT; 20 21 import android.app.Activity; 22 import android.app.ActivityOptions; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.res.Resources.NotFoundException; 26 import android.graphics.drawable.Drawable; 27 import android.graphics.drawable.LayerDrawable; 28 import android.graphics.drawable.RippleDrawable; 29 import android.os.Bundle; 30 import android.os.Handler; 31 import android.util.Log; 32 import android.view.LayoutInflater; 33 import android.view.SurfaceView; 34 import android.view.View; 35 import android.view.ViewGroup; 36 import android.view.animation.Interpolator; 37 import android.view.animation.PathInterpolator; 38 import android.widget.Button; 39 import android.widget.Toast; 40 41 import androidx.activity.OnBackPressedCallback; 42 import androidx.annotation.CallSuper; 43 import androidx.annotation.IntDef; 44 import androidx.annotation.LayoutRes; 45 import androidx.annotation.Nullable; 46 import androidx.fragment.app.FragmentActivity; 47 import androidx.lifecycle.ViewModelProvider; 48 49 import com.android.wallpaper.R; 50 import com.android.wallpaper.model.LiveWallpaperInfo; 51 import com.android.wallpaper.model.SetWallpaperViewModel; 52 import com.android.wallpaper.model.WallpaperInfo; 53 import com.android.wallpaper.module.Injector; 54 import com.android.wallpaper.module.InjectorProvider; 55 import com.android.wallpaper.module.LargeScreenMultiPanesChecker; 56 import com.android.wallpaper.module.UserEventLogger; 57 import com.android.wallpaper.module.WallpaperPersister.Destination; 58 import com.android.wallpaper.module.WallpaperPreferences; 59 import com.android.wallpaper.module.WallpaperSetter; 60 import com.android.wallpaper.util.FullScreenAnimation; 61 import com.android.wallpaper.util.ResourceUtils; 62 import com.android.wallpaper.widget.BottomActionBar; 63 import com.android.wallpaper.widget.BottomActionBar.BottomSheetContent; 64 import com.android.wallpaper.widget.WallpaperInfoView; 65 66 import com.google.android.material.tabs.TabLayout; 67 68 import java.util.Date; 69 import java.util.List; 70 import java.util.Optional; 71 72 /** 73 * Base Fragment to display the UI for previewing an individual wallpaper 74 */ 75 public abstract class PreviewFragment extends AppbarFragment implements 76 SetWallpaperDialogFragment.Listener, SetWallpaperErrorDialogFragment.Listener, 77 LoadWallpaperErrorDialogFragment.Listener { 78 79 public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f); 80 81 /** 82 * User can view wallpaper and attributions in full screen, but "Set wallpaper" button is 83 * hidden. 84 */ 85 static final int MODE_VIEW_ONLY = 0; 86 87 /** 88 * User can view wallpaper and attributions in full screen and click "Set wallpaper" to set the 89 * wallpaper with pan and crop position to the device. 90 */ 91 static final int MODE_CROP_AND_SET_WALLPAPER = 1; 92 93 /** 94 * Possible preview modes for the fragment. 95 */ 96 @IntDef({ 97 MODE_VIEW_ONLY, 98 MODE_CROP_AND_SET_WALLPAPER}) 99 public @interface PreviewMode { 100 } 101 102 public static final String ARG_WALLPAPER = "wallpaper"; 103 public static final String ARG_PREVIEW_MODE = "preview_mode"; 104 public static final String ARG_VIEW_AS_HOME = "view_as_home"; 105 public static final String ARG_FULL_SCREEN = "view_full_screen"; 106 public static final String ARG_TESTING_MODE_ENABLED = "testing_mode_enabled"; 107 108 /** 109 * Creates and returns new instance of {@link ImagePreviewFragment} with the provided wallpaper 110 * set as an argument. 111 */ newInstance(WallpaperInfo wallpaperInfo, @PreviewMode int mode, boolean viewAsHome, boolean viewFullScreen, boolean testingModeEnabled)112 public static PreviewFragment newInstance(WallpaperInfo wallpaperInfo, @PreviewMode int mode, 113 boolean viewAsHome, boolean viewFullScreen, boolean testingModeEnabled) { 114 Bundle args = new Bundle(); 115 args.putParcelable(ARG_WALLPAPER, wallpaperInfo); 116 args.putInt(ARG_PREVIEW_MODE, mode); 117 args.putBoolean(ARG_VIEW_AS_HOME, viewAsHome); 118 args.putBoolean(ARG_FULL_SCREEN, viewFullScreen); 119 args.putBoolean(ARG_TESTING_MODE_ENABLED, testingModeEnabled); 120 121 PreviewFragment fragment = wallpaperInfo instanceof LiveWallpaperInfo 122 ? new LivePreviewFragment() : new ImagePreviewFragment(); 123 fragment.setArguments(args); 124 return fragment; 125 } 126 127 private static final String TAG_LOAD_WALLPAPER_ERROR_DIALOG_FRAGMENT = 128 "load_wallpaper_error_dialog"; 129 private static final String TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT = 130 "set_wallpaper_error_dialog"; 131 private static final int UNUSED_REQUEST_CODE = 1; 132 private static final String TAG = "PreviewFragment"; 133 134 /** 135 * When true, enables a test mode of operation -- in which certain UI features are disabled to 136 * allow for UI tests to run correctly. Works around issue in ProgressDialog currently where the 137 * dialog constantly keeps the UI thread alive and blocks a test forever. 138 */ 139 protected boolean mTestingModeEnabled; 140 141 protected WallpaperInfo mWallpaper; 142 protected WallpaperPreviewBitmapTransformation mPreviewBitmapTransformation; 143 protected WallpaperSetter mWallpaperSetter; 144 protected UserEventLogger mUserEventLogger; 145 protected BottomActionBar mBottomActionBar; 146 // For full screen animations. 147 protected View mRootView; 148 protected FullScreenAnimation mFullScreenAnimation; 149 @PreviewMode protected int mPreviewMode; 150 protected boolean mViewAsHome; 151 // For full screen preview in a separate Activity. 152 protected boolean mShowInFullScreen; 153 154 protected SetWallpaperViewModel mSetWallpaperViewModel; 155 protected ViewModelProvider mViewModelProvider; 156 protected Optional<Integer> mLastSelectedTabPositionOptional = Optional.empty(); 157 private OnBackPressedCallback mOnBackPressedCallback; 158 159 /** 160 * Staged error dialog fragments that were unable to be shown when the hosting activity didn't 161 * allow committing fragment transactions. 162 */ 163 private SetWallpaperErrorDialogFragment mStagedSetWallpaperErrorDialogFragment; 164 private LoadWallpaperErrorDialogFragment mStagedLoadWallpaperErrorDialogFragment; 165 166 @Override onCreate(Bundle savedInstanceState)167 public void onCreate(Bundle savedInstanceState) { 168 super.onCreate(savedInstanceState); 169 Context appContext = getContext().getApplicationContext(); 170 Injector injector = InjectorProvider.getInjector(); 171 172 mUserEventLogger = injector.getUserEventLogger(appContext); 173 mWallpaper = getArguments().getParcelable(ARG_WALLPAPER); 174 mPreviewBitmapTransformation = new WallpaperPreviewBitmapTransformation( 175 appContext, isRtl()); 176 177 //noinspection ResourceType 178 mPreviewMode = getArguments().getInt(ARG_PREVIEW_MODE); 179 mViewAsHome = getArguments().getBoolean(ARG_VIEW_AS_HOME); 180 mShowInFullScreen = getArguments().getBoolean(ARG_FULL_SCREEN); 181 182 mTestingModeEnabled = getArguments().getBoolean(ARG_TESTING_MODE_ENABLED); 183 mWallpaperSetter = new WallpaperSetter(injector.getWallpaperPersister(appContext), 184 injector.getPreferences(appContext), mUserEventLogger, mTestingModeEnabled); 185 186 mViewModelProvider = new ViewModelProvider(requireActivity()); 187 mSetWallpaperViewModel = mViewModelProvider.get(SetWallpaperViewModel.class); 188 189 Activity activity = getActivity(); 190 List<String> attributions = getAttributions(activity); 191 if (attributions.size() > 0 && attributions.get(0) != null) { 192 activity.setTitle(attributions.get(0)); 193 } 194 } 195 196 @Override getToolbarColorId()197 protected int getToolbarColorId() { 198 return android.R.color.transparent; 199 } 200 201 @Override 202 @CallSuper onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)203 public View onCreateView(LayoutInflater inflater, ViewGroup container, 204 Bundle savedInstanceState) { 205 View view = inflater.inflate(getLayoutResId(), container, false); 206 setUpToolbar(view); 207 208 mRootView = view; 209 mFullScreenAnimation = new FullScreenAnimation(view); 210 211 getActivity().getWindow().getDecorView().setOnApplyWindowInsetsListener( 212 (v, windowInsets) -> { 213 v.setPadding( 214 v.getPaddingLeft(), 215 0, 216 v.getPaddingRight(), 217 0); 218 219 mFullScreenAnimation.setWindowInsets(windowInsets); 220 mFullScreenAnimation.placeViews(); 221 222 // Update preview header's padding top to align status bar height. 223 View previewHeader = v.findViewById(R.id.preview_header); 224 previewHeader.setPadding(previewHeader.getPaddingLeft(), 225 mFullScreenAnimation.getStatusBarHeight(), 226 previewHeader.getPaddingRight(), previewHeader.getPaddingBottom()); 227 228 return windowInsets.consumeSystemWindowInsets(); 229 } 230 ); 231 232 return view; 233 } 234 235 @Override onBottomActionBarReady(BottomActionBar bottomActionBar)236 protected void onBottomActionBarReady(BottomActionBar bottomActionBar) { 237 super.onBottomActionBarReady(bottomActionBar); 238 mBottomActionBar = bottomActionBar; 239 if (!mShowInFullScreen) { 240 mBottomActionBar.setActionClickListener(EDIT, (view) -> { 241 // Starts a full preview Activity when in multi-pane resolution 242 LargeScreenMultiPanesChecker multiPanesChecker = new LargeScreenMultiPanesChecker(); 243 if (multiPanesChecker.isMultiPanesEnabled(getContext())) { 244 showInFullScreenActivity(mWallpaper); 245 } else { 246 mFullScreenAnimation.startAnimation(/* toFullScreen= */ true); 247 } 248 mBottomActionBar.deselectAction(EDIT); 249 }); 250 } else { 251 bottomActionBar.post( 252 () -> mFullScreenAnimation.startAnimation(/* toFullScreen= */ true)); 253 } 254 setFullScreenActions(mRootView.findViewById(R.id.fullscreen_buttons_container)); 255 256 if (mOnBackPressedCallback == null) { 257 mOnBackPressedCallback = new OnBackPressedCallback(true) { 258 @Override 259 public void handleOnBackPressed() { 260 if (mFullScreenAnimation.isFullScreen() && !mShowInFullScreen) { 261 mFullScreenAnimation.startAnimation(/* toFullScreen= */ false); 262 return; 263 } 264 if (mBottomActionBar != null && !mBottomActionBar.isBottomSheetCollapsed()) { 265 mBottomActionBar.collapseBottomSheetIfExpanded(); 266 return; 267 } 268 getActivity().finish(); 269 } 270 }; 271 getActivity().getOnBackPressedDispatcher().addCallback(this, mOnBackPressedCallback); 272 } 273 } 274 showInFullScreenActivity(WallpaperInfo wallpaperInfo)275 private void showInFullScreenActivity(WallpaperInfo wallpaperInfo) { 276 if (wallpaperInfo == null) { 277 return; 278 } 279 startActivity(FullPreviewActivity.newIntent(getActivity(), wallpaperInfo, 280 /* viewAsHome= */ mLastSelectedTabPositionOptional.orElse(0) == 0), 281 ActivityOptions.makeSceneTransitionAnimation(getActivity()).toBundle()); 282 } 283 setFullScreenActions(View container)284 protected void setFullScreenActions(View container) { 285 if (!mShowInFullScreen) { 286 // Update the button text for the current workspace visibility. 287 Button hideUiPreviewButton = container.findViewById(R.id.hide_ui_preview_button); 288 hideUiPreviewButton.setText(mFullScreenAnimation.getWorkspaceVisibility() 289 ? R.string.hide_ui_preview_text 290 : R.string.show_ui_preview_text); 291 hideUiPreviewButton.setOnClickListener( 292 (button) -> { 293 boolean visible = mFullScreenAnimation.getWorkspaceVisibility(); 294 // Update the button text for the next workspace visibility. 295 ((Button) button).setText(visible 296 ? R.string.show_ui_preview_text 297 : R.string.hide_ui_preview_text); 298 mFullScreenAnimation.setWorkspaceVisibility(!visible); 299 button.announceForAccessibility( 300 visible ? getString(R.string.hint_hide_ui_preview) 301 : getString(R.string.hint_show_ui_preview)); 302 } 303 ); 304 container.findViewById(R.id.set_as_wallpaper_button).setOnClickListener( 305 this::onSetWallpaperClicked); 306 } else { 307 container.findViewById(R.id.hide_ui_preview_button).setVisibility(View.GONE); 308 container.findViewById(R.id.set_as_wallpaper_button).setVisibility(View.GONE); 309 setUpToolbarMenu(R.menu.fullpreview_menu); 310 setUpToolbarMenuClickListener(R.id.action_hide_ui, view -> { 311 boolean visible = mFullScreenAnimation.getWorkspaceVisibility(); 312 mFullScreenAnimation.setWorkspaceVisibility(!visible); 313 View hideUiView = view.findViewById(R.id.hide_ui_view); 314 RippleDrawable ripple = (RippleDrawable) hideUiView.getBackground(); 315 LayerDrawable layerDrawable = (LayerDrawable) ripple.getDrawable(/* index= */ 0); 316 Drawable backgroundDrawable = layerDrawable.getDrawable(/* index= */ 0); 317 backgroundDrawable.setTint(!visible ? ResourceUtils.getColorAttr(getActivity(), 318 com.android.internal.R.attr.colorAccentSecondary) 319 : ResourceUtils.getColorAttr(getActivity(), 320 com.android.internal.R.attr.colorAccentPrimary)); 321 }); 322 setUpToolbarMenuClickListener(R.id.action_set_wallpaper, 323 view -> mWallpaperSetter.requestDestination(getActivity(), getFragmentManager(), 324 this, mWallpaper instanceof LiveWallpaperInfo)); 325 } 326 327 mFullScreenAnimation.ensureBottomActionBarIsCorrectlyLocated(); 328 } 329 getAttributions(Context context)330 protected List<String> getAttributions(Context context) { 331 return mWallpaper.getAttributions(context); 332 } 333 334 @LayoutRes getLayoutResId()335 protected abstract int getLayoutResId(); 336 createWorkspaceSurfaceCallback( SurfaceView workspaceSurface)337 protected WorkspaceSurfaceHolderCallback createWorkspaceSurfaceCallback( 338 SurfaceView workspaceSurface) { 339 return new WorkspaceSurfaceHolderCallback(workspaceSurface, getContext()); 340 } 341 342 @Override onResume()343 public void onResume() { 344 super.onResume(); 345 346 WallpaperPreferences preferences = 347 InjectorProvider.getInjector().getPreferences(getActivity()); 348 preferences.setLastAppActiveTimestamp(new Date().getTime()); 349 350 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is 351 // one that was unable to be shown earlier when this fragment's hosting activity didn't 352 // allow committing fragment transactions. 353 if (mStagedLoadWallpaperErrorDialogFragment != null) { 354 mStagedLoadWallpaperErrorDialogFragment.show( 355 requireFragmentManager(), TAG_LOAD_WALLPAPER_ERROR_DIALOG_FRAGMENT); 356 mStagedLoadWallpaperErrorDialogFragment = null; 357 } 358 if (mStagedSetWallpaperErrorDialogFragment != null) { 359 mStagedSetWallpaperErrorDialogFragment.show( 360 requireFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT); 361 mStagedSetWallpaperErrorDialogFragment = null; 362 } 363 364 mSetWallpaperViewModel.getStatus().observe(requireActivity(), setWallpaperStatus -> { 365 switch (setWallpaperStatus) { 366 case SUCCESS: 367 // Give a few millis before finishing to allow for the dialog dismiss 368 // and animations to finish 369 Handler.getMain().postDelayed(() -> finishActivity(true), 300); 370 break; 371 case ERROR: 372 showSetWallpaperErrorDialog(mSetWallpaperViewModel.getDestination()); 373 break; 374 default: 375 // Do nothing in this case, either status is pending, or unknown 376 } 377 }); 378 } 379 isLoaded()380 protected abstract boolean isLoaded(); 381 382 @Override onSet(int destination)383 public void onSet(int destination) { 384 mSetWallpaperViewModel.setDestination(destination); 385 setCurrentWallpaper(destination); 386 } 387 388 @Override onDialogDismissed(boolean withItemSelected)389 public void onDialogDismissed(boolean withItemSelected) { 390 mBottomActionBar.deselectAction(APPLY); 391 } 392 393 @Override onClickTryAgain(@estination int wallpaperDestination)394 public void onClickTryAgain(@Destination int wallpaperDestination) { 395 mSetWallpaperViewModel.setDestination(wallpaperDestination); 396 setCurrentWallpaper(wallpaperDestination); 397 } 398 399 @Override onClickOk()400 public void onClickOk() { 401 FragmentActivity activity = getActivity(); 402 if (activity != null) { 403 activity.finish(); 404 } 405 } 406 407 @Override onDestroy()408 public void onDestroy() { 409 super.onDestroy(); 410 mWallpaperSetter.cleanUp(); 411 } 412 413 @Override getDefaultTitle()414 public CharSequence getDefaultTitle() { 415 return getContext().getString(R.string.preview); 416 } 417 onSetWallpaperClicked(View button)418 protected void onSetWallpaperClicked(View button) { 419 mWallpaperSetter.requestDestination(getActivity(), getFragmentManager(), this, 420 mWallpaper instanceof LiveWallpaperInfo); 421 } 422 setUpTabs(TabLayout tabs)423 protected void setUpTabs(TabLayout tabs) { 424 tabs.addTab(tabs.newTab().setText(R.string.home_screen_message)); 425 tabs.addTab(tabs.newTab().setText(R.string.lock_screen_message)); 426 tabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { 427 @Override 428 public void onTabSelected(TabLayout.Tab tab) { 429 mLastSelectedTabPositionOptional = Optional.of(tab.getPosition()); 430 updateScreenPreview(/* isHomeSelected= */ tab.getPosition() == 0); 431 } 432 433 @Override 434 public void onTabUnselected(TabLayout.Tab tab) {} 435 436 @Override 437 public void onTabReselected(TabLayout.Tab tab) {} 438 }); 439 440 // The TabLayout only contains below tabs 441 // 0. Home tab 442 // 1. Lock tab 443 int tabPosition = mLastSelectedTabPositionOptional.orElseGet(() -> mViewAsHome ? 0 : 1); 444 tabs.getTabAt(tabPosition).select(); 445 updateScreenPreview(/* isHomeSelected= */ tabPosition == 0); 446 } 447 updateScreenPreview(boolean isHomeSelected)448 protected abstract void updateScreenPreview(boolean isHomeSelected); 449 450 /** 451 * Sets current wallpaper to the device based on current zoom and scroll state. 452 * 453 * @param destination The wallpaper destination i.e. home vs. lockscreen vs. both. 454 */ setCurrentWallpaper(@estination int destination)455 protected abstract void setCurrentWallpaper(@Destination int destination); 456 finishActivity(boolean success)457 protected void finishActivity(boolean success) { 458 Activity activity = getActivity(); 459 if (activity == null) { 460 return; 461 } 462 if (success) { 463 try { 464 Toast.makeText(activity, 465 R.string.wallpaper_set_successfully_message, Toast.LENGTH_SHORT).show(); 466 } catch (NotFoundException e) { 467 Log.e(TAG, "Could not show toast " + e); 468 } 469 activity.setResult(Activity.RESULT_OK); 470 } 471 activity.finish(); 472 activity.overridePendingTransition(R.anim.fade_in, R.anim.fade_out); 473 } 474 showSetWallpaperErrorDialog(@estination int wallpaperDestination)475 protected void showSetWallpaperErrorDialog(@Destination int wallpaperDestination) { 476 SetWallpaperErrorDialogFragment newFragment = SetWallpaperErrorDialogFragment.newInstance( 477 R.string.set_wallpaper_error_message, wallpaperDestination); 478 newFragment.setTargetFragment(this, UNUSED_REQUEST_CODE); 479 480 // Show 'set wallpaper' error dialog now if it's safe to commit fragment transactions, 481 // otherwise stage it for later when the hosting activity is in a state to commit fragment 482 // transactions. 483 BasePreviewActivity activity = (BasePreviewActivity) requireActivity(); 484 if (activity.isSafeToCommitFragmentTransaction()) { 485 newFragment.show(requireFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT); 486 } else { 487 mStagedSetWallpaperErrorDialogFragment = newFragment; 488 } 489 } 490 491 /** 492 * Shows 'load wallpaper' error dialog now or stage it to be shown when the hosting activity is 493 * in a state that allows committing fragment transactions. 494 */ showLoadWallpaperErrorDialog()495 protected void showLoadWallpaperErrorDialog() { 496 LoadWallpaperErrorDialogFragment dialogFragment = 497 LoadWallpaperErrorDialogFragment.newInstance(); 498 dialogFragment.setTargetFragment(this, UNUSED_REQUEST_CODE); 499 500 // Show 'load wallpaper' error dialog now or stage it to be shown when the hosting 501 // activity is in a state that allows committing fragment transactions. 502 BasePreviewActivity activity = (BasePreviewActivity) getActivity(); 503 if (activity != null && activity.isSafeToCommitFragmentTransaction()) { 504 dialogFragment.show(requireFragmentManager(), TAG_LOAD_WALLPAPER_ERROR_DIALOG_FRAGMENT); 505 } else { 506 mStagedLoadWallpaperErrorDialogFragment = dialogFragment; 507 } 508 } 509 510 /** 511 * Returns whether layout direction is RTL (or false for LTR). Since native RTL layout support 512 * was added in API 17, returns false for versions lower than 17. 513 */ isRtl()514 protected boolean isRtl() { 515 return getResources().getConfiguration().getLayoutDirection() 516 == View.LAYOUT_DIRECTION_RTL; 517 } 518 519 protected final class WallpaperInfoContent extends BottomSheetContent<WallpaperInfoView> { 520 521 @Nullable private Intent mExploreIntent; 522 private CharSequence mActionLabel; 523 WallpaperInfoContent(Context context)524 protected WallpaperInfoContent(Context context) { 525 super(context); 526 } 527 528 @Override getViewId()529 public int getViewId() { 530 return R.layout.wallpaper_info_view; 531 } 532 533 @Override onViewCreated(WallpaperInfoView view)534 public void onViewCreated(WallpaperInfoView view) { 535 if (mWallpaper == null) { 536 return; 537 } 538 539 if (mActionLabel == null) { 540 setUpExploreIntentAndLabel(() -> populateWallpaperInfo(view)); 541 } else { 542 populateWallpaperInfo(view); 543 } 544 } 545 setUpExploreIntentAndLabel(@ullable Runnable callback)546 private void setUpExploreIntentAndLabel(@Nullable Runnable callback) { 547 Context context = getContext(); 548 if (context == null) { 549 return; 550 } 551 552 WallpaperInfoHelper.loadExploreIntent(context, mWallpaper, 553 (actionLabel, exploreIntent) -> { 554 mActionLabel = actionLabel; 555 mExploreIntent = exploreIntent; 556 if (callback != null) { 557 callback.run(); 558 } 559 } 560 ); 561 } 562 onExploreClicked(View button)563 private void onExploreClicked(View button) { 564 Context context = getContext(); 565 if (context == null) { 566 return; 567 } 568 569 mUserEventLogger.logActionClicked(mWallpaper.getCollectionId(context), 570 mWallpaper.getActionLabelRes(context)); 571 572 startActivity(mExploreIntent); 573 } 574 populateWallpaperInfo(WallpaperInfoView view)575 private void populateWallpaperInfo(WallpaperInfoView view) { 576 view.populateWallpaperInfo( 577 mWallpaper, 578 mActionLabel, 579 WallpaperInfoHelper.shouldShowExploreButton( 580 getContext(), mExploreIntent), 581 this::onExploreClicked); 582 } 583 } 584 } 585