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