• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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