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 android.view.View.MeasureSpec.EXACTLY; 19 import static android.view.View.MeasureSpec.makeMeasureSpec; 20 21 import android.app.Activity; 22 import android.app.ProgressDialog; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.pm.PackageManager; 26 import android.graphics.Point; 27 import android.graphics.PorterDuff.Mode; 28 import android.graphics.Rect; 29 import android.graphics.RectF; 30 import android.graphics.drawable.ColorDrawable; 31 import android.graphics.drawable.Drawable; 32 import android.net.Uri; 33 import android.os.Build.VERSION; 34 import android.os.Build.VERSION_CODES; 35 import android.os.Bundle; 36 import android.provider.Settings; 37 import android.service.wallpaper.WallpaperService; 38 import android.util.DisplayMetrics; 39 import android.util.Log; 40 import android.view.Display; 41 import android.view.LayoutInflater; 42 import android.view.SurfaceControlViewHost; 43 import android.view.SurfaceHolder; 44 import android.view.SurfaceView; 45 import android.view.View; 46 import android.view.View.OnClickListener; 47 import android.view.ViewGroup; 48 import android.view.animation.AnimationUtils; 49 import android.widget.Button; 50 import android.widget.FrameLayout; 51 import android.widget.ImageButton; 52 import android.widget.ImageView; 53 import android.widget.TextView; 54 55 import androidx.annotation.NonNull; 56 import androidx.annotation.Nullable; 57 import androidx.appcompat.app.AlertDialog; 58 import androidx.cardview.widget.CardView; 59 import androidx.core.content.ContextCompat; 60 import androidx.recyclerview.widget.RecyclerView; 61 import androidx.viewpager.widget.PagerAdapter; 62 import androidx.viewpager.widget.ViewPager; 63 64 import com.android.systemui.shared.system.SurfaceViewRequestUtils; 65 import com.android.wallpaper.R; 66 import com.android.wallpaper.config.Flags; 67 import com.android.wallpaper.model.Category; 68 import com.android.wallpaper.model.LiveWallpaperInfo; 69 import com.android.wallpaper.model.WallpaperInfo; 70 import com.android.wallpaper.module.CurrentWallpaperInfoFactory; 71 import com.android.wallpaper.module.CurrentWallpaperInfoFactory.WallpaperInfoCallback; 72 import com.android.wallpaper.module.ExploreIntentChecker; 73 import com.android.wallpaper.module.InjectorProvider; 74 import com.android.wallpaper.module.LockWallpaperStatusChecker; 75 import com.android.wallpaper.module.UserEventLogger; 76 import com.android.wallpaper.module.WallpaperPreferences; 77 import com.android.wallpaper.module.WallpaperPreferences.PresentationMode; 78 import com.android.wallpaper.module.WallpaperRotationRefresher; 79 import com.android.wallpaper.module.WallpaperRotationRefresher.Listener; 80 import com.android.wallpaper.picker.CategorySelectorFragment.CategorySelectorFragmentHost; 81 import com.android.wallpaper.picker.MyPhotosStarter.MyPhotosStarterProvider; 82 import com.android.wallpaper.picker.MyPhotosStarter.PermissionChangedListener; 83 import com.android.wallpaper.picker.individual.IndividualPickerFragment.ThumbnailUpdater; 84 import com.android.wallpaper.util.DisplayMetricsRetriever; 85 import com.android.wallpaper.util.PreviewUtils; 86 import com.android.wallpaper.util.ScreenSizeCalculator; 87 import com.android.wallpaper.util.TileSizeCalculator; 88 import com.android.wallpaper.util.WallpaperConnection; 89 import com.android.wallpaper.util.WallpaperConnection.WallpaperConnectionListener; 90 import com.android.wallpaper.widget.LiveTileOverlay; 91 import com.android.wallpaper.widget.PreviewPager; 92 93 import com.bumptech.glide.Glide; 94 import com.bumptech.glide.MemoryCategory; 95 import com.google.android.material.bottomsheet.BottomSheetBehavior; 96 97 import java.util.ArrayList; 98 import java.util.Date; 99 import java.util.List; 100 101 /** 102 * Displays the Main UI for picking a category of wallpapers to choose from. 103 */ 104 public class CategoryFragment extends ToolbarFragment 105 implements CategorySelectorFragmentHost, ThumbnailUpdater { 106 107 /** 108 * Interface to be implemented by an Activity hosting a {@link CategoryFragment} 109 */ 110 public interface CategoryFragmentHost extends MyPhotosStarterProvider { 111 requestExternalStoragePermission(PermissionChangedListener listener)112 void requestExternalStoragePermission(PermissionChangedListener listener); 113 isReadExternalStoragePermissionGranted()114 boolean isReadExternalStoragePermissionGranted(); 115 showViewOnlyPreview(WallpaperInfo wallpaperInfo)116 void showViewOnlyPreview(WallpaperInfo wallpaperInfo); 117 } 118 newInstance(CharSequence title)119 public static CategoryFragment newInstance(CharSequence title) { 120 CategoryFragment fragment = new CategoryFragment(); 121 fragment.setArguments(ToolbarFragment.createArguments(title)); 122 return fragment; 123 } 124 125 private static final String TAG = "CategoryFragment"; 126 private static final int MAX_ALPHA = 255; 127 128 // The number of ViewHolders that don't pertain to category tiles. 129 // Currently 2: one for the metadata section and one for the "Select wallpaper" header. 130 private static final int NUM_NON_CATEGORY_VIEW_HOLDERS = 0; 131 132 private static final int SETTINGS_APP_INFO_REQUEST_CODE = 1; 133 134 private static final String PERMISSION_READ_WALLPAPER_INTERNAL = 135 "android.permission.READ_WALLPAPER_INTERNAL"; 136 137 private ProgressDialog mRefreshWallpaperProgressDialog; 138 private boolean mTestingMode; 139 private ImageView mHomePreview; 140 private SurfaceView mWorkspaceSurface; 141 private SurfaceView mWallpaperSurface; 142 private ImageView mLockscreenPreview; 143 private PreviewPager mPreviewPager; 144 private List<View> mWallPaperPreviews; 145 private WallpaperConnection mWallpaperConnection; 146 private CategorySelectorFragment mCategorySelectorFragment; 147 private boolean mShowSelectedWallpaper; 148 private BottomSheetBehavior mBottomSheetBehavior; 149 private PreviewUtils mPreviewUtils; 150 151 // Home workspace surface is behind the app window, and so must the home image wallpaper like 152 // the live wallpaper. This view is rendered on mWallpaperSurface for home image wallpaper. 153 private ImageView mHomeImageWallpaper; 154 CategoryFragment()155 public CategoryFragment() { 156 mCategorySelectorFragment = new CategorySelectorFragment(); 157 } 158 159 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)160 public View onCreateView(LayoutInflater inflater, ViewGroup container, 161 Bundle savedInstanceState) { 162 View view = inflater.inflate( 163 ADD_SCALABLE_HEADER 164 ? R.layout.fragment_category_scalable_picker 165 : R.layout.fragment_category_picker, container, /* attachToRoot= */ false); 166 167 mWallPaperPreviews = new ArrayList<>(); 168 CardView homePreviewCard = (CardView) inflater.inflate( 169 R.layout.wallpaper_preview_card, null); 170 mHomePreview = homePreviewCard.findViewById(R.id.wallpaper_preview_image); 171 mWorkspaceSurface = homePreviewCard.findViewById(R.id.workspace_surface); 172 mWallpaperSurface = homePreviewCard.findViewById(R.id.wallpaper_surface); 173 mWallPaperPreviews.add(homePreviewCard); 174 175 if (LockWallpaperStatusChecker.isLockWallpaperSet(getContext())) { 176 CardView lockscreenPreviewCard = (CardView) inflater.inflate( 177 R.layout.wallpaper_preview_card, null); 178 mLockscreenPreview = lockscreenPreviewCard.findViewById(R.id.wallpaper_preview_image); 179 lockscreenPreviewCard.findViewById(R.id.workspace_surface).setVisibility(View.GONE); 180 lockscreenPreviewCard.findViewById(R.id.wallpaper_surface).setVisibility(View.GONE); 181 mWallPaperPreviews.add(lockscreenPreviewCard); 182 } 183 184 mPreviewPager = view.findViewById(R.id.wallpaper_preview_pager); 185 mPreviewPager.setAdapter(new PreviewPagerAdapter(mWallPaperPreviews)); 186 mPreviewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { 187 int[] mLocation = new int[2]; 188 Rect mHomePreviewRect = new Rect(); 189 @Override 190 public void onPageScrolled(int position, float positionOffset, 191 int positionOffsetPixels) { 192 if (mWallpaperConnection != null) { 193 mHomePreview.getLocationOnScreen(mLocation); 194 mHomePreviewRect.set(0, 0, mHomePreview.getMeasuredWidth(), 195 mHomePreview.getMeasuredHeight()); 196 mHomePreviewRect.offset(mLocation[0], mLocation[1]); 197 mWallpaperConnection.updatePreviewPosition(mHomePreviewRect); 198 } 199 } 200 201 @Override 202 public void onPageSelected(int i) { 203 } 204 205 @Override 206 public void onPageScrollStateChanged(int i) { 207 } 208 }); 209 setupCurrentWallpaperPreview(view); 210 211 View fragmentContainer = view.findViewById(R.id.category_fragment_container); 212 mBottomSheetBehavior = BottomSheetBehavior.from(fragmentContainer); 213 fragmentContainer.addOnLayoutChangeListener((containerView, left, top, right, bottom, 214 oldLeft, oldTop, oldRight, oldBottom) -> { 215 int minimumHeight = containerView.getHeight() - mPreviewPager.getMeasuredHeight(); 216 mBottomSheetBehavior.setPeekHeight(minimumHeight); 217 containerView.setMinimumHeight(minimumHeight); 218 ((CardView) mHomePreview.getParent()) 219 .setRadius(TileSizeCalculator.getPreviewCornerRadius( 220 getActivity(), homePreviewCard.getMeasuredWidth())); 221 }); 222 223 mPreviewUtils = new PreviewUtils(getContext(), 224 getString(R.string.grid_control_metadata_name)); 225 226 setUpToolbar(view); 227 228 getChildFragmentManager() 229 .beginTransaction() 230 .replace(R.id.category_fragment_container, mCategorySelectorFragment) 231 .commitNow(); 232 return view; 233 } 234 235 @Override onViewCreated(@onNull View view, @Nullable Bundle savedInstanceState)236 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 237 updateWallpaperSurface(); 238 updateWorkspaceSurface(); 239 } 240 241 @Override getDefaultTitle()242 public CharSequence getDefaultTitle() { 243 return getContext().getString(R.string.app_name); 244 } 245 246 @Override onResume()247 public void onResume() { 248 super.onResume(); 249 250 WallpaperPreferences preferences = InjectorProvider.getInjector().getPreferences(getActivity()); 251 preferences.setLastAppActiveTimestamp(new Date().getTime()); 252 253 // Reset Glide memory settings to a "normal" level of usage since it may have been lowered in 254 // PreviewFragment. 255 Glide.get(getActivity()).setMemoryCategory(MemoryCategory.NORMAL); 256 257 // The wallpaper may have been set while this fragment was paused, so force refresh the current 258 // wallpapers and presentation mode. 259 if (!mShowSelectedWallpaper) { 260 refreshCurrentWallpapers(/* MetadataHolder= */ null, /* forceRefresh= */ true); 261 } 262 if (mWallpaperConnection != null) { 263 mWallpaperConnection.setVisibility(true); 264 } 265 } 266 267 @Override onPause()268 public void onPause() { 269 super.onPause(); 270 if (mWallpaperConnection != null) { 271 mWallpaperConnection.setVisibility(false); 272 } 273 } 274 275 @Override onDestroyView()276 public void onDestroyView() { 277 super.onDestroyView(); 278 if (mWallpaperConnection != null) { 279 mWallpaperConnection.disconnect(); 280 mWallpaperConnection = null; 281 } 282 } 283 284 @Override onDestroy()285 public void onDestroy() { 286 super.onDestroy(); 287 if (mWallpaperConnection != null) { 288 mWallpaperConnection.disconnect(); 289 mWallpaperConnection = null; 290 } 291 if (mRefreshWallpaperProgressDialog != null) { 292 mRefreshWallpaperProgressDialog.dismiss(); 293 } 294 } 295 296 @Override onActivityResult(int requestCode, int resultCode, Intent data)297 public void onActivityResult(int requestCode, int resultCode, Intent data) { 298 if (requestCode == SETTINGS_APP_INFO_REQUEST_CODE) { 299 mCategorySelectorFragment.notifyDataSetChanged(); 300 } 301 } 302 303 @Override requestCustomPhotoPicker(PermissionChangedListener listener)304 public void requestCustomPhotoPicker(PermissionChangedListener listener) { 305 getFragmentHost().getMyPhotosStarter().requestCustomPhotoPicker(listener); 306 } 307 308 @Override show(String collectionId)309 public void show(String collectionId) { 310 getChildFragmentManager() 311 .beginTransaction() 312 .replace(R.id.category_fragment_container, 313 InjectorProvider.getInjector().getIndividualPickerFragment(collectionId)) 314 .addToBackStack(null) 315 .commit(); 316 getChildFragmentManager().executePendingTransactions(); 317 } 318 319 @Override updateThumbnail(WallpaperInfo wallpaperInfo)320 public void updateThumbnail(WallpaperInfo wallpaperInfo) { 321 new android.os.Handler().post(() -> { 322 // A config change may have destroyed the activity since the refresh started, so check 323 // for that. 324 if (getActivity() == null) { 325 return; 326 } 327 328 updateThumbnail(wallpaperInfo, mHomePreview, true); 329 updateThumbnail(wallpaperInfo, mLockscreenPreview, false); 330 mShowSelectedWallpaper = true; 331 mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); 332 }); 333 } 334 335 @Override restoreThumbnails()336 public void restoreThumbnails() { 337 refreshCurrentWallpapers(/* MetadataHolder= */ null, /* forceRefresh= */ true); 338 mShowSelectedWallpaper = false; 339 } 340 341 /** 342 * Pops the child fragment from the stack if {@link CategoryFragment} is visible to the users. 343 * 344 * @return {@code true} if the child fragment is popped, {@code false} otherwise. 345 */ popChildFragment()346 public boolean popChildFragment() { 347 return isVisible() && getChildFragmentManager().popBackStackImmediate(); 348 } 349 350 /** 351 * Inserts the given category into the categories list in priority order. 352 */ addCategory(Category category, boolean loading)353 void addCategory(Category category, boolean loading) { 354 mCategorySelectorFragment.addCategory(category, loading); 355 } 356 removeCategory(Category category)357 void removeCategory(Category category) { 358 mCategorySelectorFragment.removeCategory(category); 359 } 360 updateCategory(Category category)361 void updateCategory(Category category) { 362 mCategorySelectorFragment.updateCategory(category); 363 } 364 clearCategories()365 void clearCategories() { 366 mCategorySelectorFragment.clearCategories(); 367 } 368 369 /** 370 * Notifies the CategoryFragment that no further categories are expected so it may hide 371 * the loading indicator. 372 */ doneFetchingCategories()373 void doneFetchingCategories() { 374 mCategorySelectorFragment.doneFetchingCategories(); 375 } 376 377 /** 378 * Enable a test mode of operation -- in which certain UI features are disabled to allow for 379 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog 380 * constantly keeps the UI thread alive and blocks a test forever. 381 */ setTestingMode(boolean testingMode)382 void setTestingMode(boolean testingMode) { 383 mTestingMode = testingMode; 384 } 385 canShowCurrentWallpaper()386 private boolean canShowCurrentWallpaper() { 387 Activity activity = getActivity(); 388 CategoryFragmentHost host = getFragmentHost(); 389 PackageManager packageManager = activity.getPackageManager(); 390 String packageName = activity.getPackageName(); 391 392 boolean hasReadWallpaperInternal = packageManager.checkPermission( 393 PERMISSION_READ_WALLPAPER_INTERNAL, packageName) == PackageManager.PERMISSION_GRANTED; 394 return hasReadWallpaperInternal || host.isReadExternalStoragePermissionGranted(); 395 } 396 showCurrentWallpaper(View rootView, boolean show)397 private void showCurrentWallpaper(View rootView, boolean show) { 398 rootView.findViewById(R.id.wallpaper_preview_pager) 399 .setVisibility(show ? View.VISIBLE : View.GONE); 400 rootView.findViewById(R.id.permission_needed) 401 .setVisibility(show ? View.GONE : View.VISIBLE); 402 } 403 setupCurrentWallpaperPreview(View rootView)404 private void setupCurrentWallpaperPreview(View rootView) { 405 if (canShowCurrentWallpaper()) { 406 showCurrentWallpaper(rootView, true); 407 } else { 408 showCurrentWallpaper(rootView, false); 409 410 Button mAllowAccessButton = rootView 411 .findViewById(R.id.permission_needed_allow_access_button); 412 mAllowAccessButton.setOnClickListener(view -> 413 getFragmentHost().requestExternalStoragePermission( 414 new PermissionChangedListener() { 415 416 @Override 417 public void onPermissionsGranted() { 418 showCurrentWallpaper(rootView, true); 419 mCategorySelectorFragment.notifyDataSetChanged(); 420 } 421 422 @Override 423 public void onPermissionsDenied(boolean dontAskAgain) { 424 if (!dontAskAgain) { 425 return; 426 } 427 showPermissionNeededDialog(); 428 } 429 }) 430 ); 431 432 // Replace explanation text with text containing the Wallpapers app name which replaces 433 // the placeholder. 434 String appName = getString(R.string.app_name); 435 String explanation = getString(R.string.permission_needed_explanation, appName); 436 TextView explanationView = rootView.findViewById(R.id.permission_needed_explanation); 437 explanationView.setText(explanation); 438 } 439 } 440 showPermissionNeededDialog()441 private void showPermissionNeededDialog() { 442 String permissionNeededMessage = getString( 443 R.string.permission_needed_explanation_go_to_settings); 444 AlertDialog dialog = new AlertDialog.Builder(getActivity(), R.style.LightDialogTheme) 445 .setMessage(permissionNeededMessage) 446 .setPositiveButton(android.R.string.ok, /* onClickListener= */ null) 447 .setNegativeButton( 448 R.string.settings_button_label, 449 (dialogInterface, i) -> { 450 Intent appInfoIntent = new Intent(); 451 appInfoIntent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 452 Uri uri = Uri.fromParts("package", 453 getActivity().getPackageName(), /* fragment= */ null); 454 appInfoIntent.setData(uri); 455 startActivityForResult(appInfoIntent, SETTINGS_APP_INFO_REQUEST_CODE); 456 }) 457 .create(); 458 dialog.show(); 459 } 460 getFragmentHost()461 private CategoryFragmentHost getFragmentHost() { 462 return (CategoryFragmentHost) getActivity(); 463 } 464 getWallpaperIntent(android.app.WallpaperInfo info)465 private Intent getWallpaperIntent(android.app.WallpaperInfo info) { 466 return new Intent(WallpaperService.SERVICE_INTERFACE) 467 .setClassName(info.getPackageName(), info.getServiceName()); 468 } 469 /** 470 * Obtains the {@link WallpaperInfo} object(s) representing the wallpaper(s) currently set to the 471 * device from the {@link CurrentWallpaperInfoFactory} and binds them to the provided 472 * {@link MetadataHolder}. 473 */ refreshCurrentWallpapers(@ullable final MetadataHolder holder, boolean forceRefresh)474 private void refreshCurrentWallpapers(@Nullable final MetadataHolder holder, 475 boolean forceRefresh) { 476 CurrentWallpaperInfoFactory factory = InjectorProvider.getInjector() 477 .getCurrentWallpaperFactory(getActivity().getApplicationContext()); 478 479 factory.createCurrentWallpaperInfos(new WallpaperInfoCallback() { 480 @Override 481 public void onWallpaperInfoCreated( 482 final WallpaperInfo homeWallpaper, 483 @Nullable final WallpaperInfo lockWallpaper, 484 @PresentationMode final int presentationMode) { 485 486 // Update the metadata displayed on screen. Do this in a Handler so it is scheduled at the 487 // end of the message queue. This is necessary to ensure we do not remove or add data from 488 // the adapter while the layout is being computed. RecyclerView documentation therefore 489 // recommends performing such changes in a Handler. 490 new android.os.Handler().post(new Runnable() { 491 @Override 492 public void run() { 493 final Activity activity = getActivity(); 494 // A config change may have destroyed the activity since the refresh 495 // started, so check for that. 496 if (activity == null) { 497 return; 498 } 499 500 updateThumbnail(homeWallpaper, mHomePreview, true); 501 updateThumbnail(lockWallpaper, mLockscreenPreview, false); 502 503 // The MetadataHolder may be null if the RecyclerView has not yet created the view 504 // holder. 505 if (holder != null) { 506 holder.bindWallpapers(homeWallpaper, lockWallpaper, presentationMode); 507 } 508 } 509 }); 510 } 511 }, forceRefresh); 512 } 513 setUpLiveWallpaperPreview(WallpaperInfo homeWallpaper, ImageView previewView, Drawable thumbnail)514 private void setUpLiveWallpaperPreview(WallpaperInfo homeWallpaper, ImageView previewView, 515 Drawable thumbnail) { 516 Activity activity = getActivity(); 517 if (activity == null) { 518 return; 519 } 520 if (mWallpaperConnection != null) { 521 mWallpaperConnection.disconnect(); 522 } 523 if (thumbnail != null) { 524 thumbnail.setBounds(previewView.getLeft(), previewView.getTop(), previewView.getRight(), 525 previewView.getBottom()); 526 } 527 528 Rect previewLocalRect = new Rect(); 529 Rect previewGlobalRect = new Rect(); 530 previewView.getLocalVisibleRect(previewLocalRect); 531 previewView.getGlobalVisibleRect(previewGlobalRect); 532 mWallpaperConnection = new WallpaperConnection( 533 getWallpaperIntent(homeWallpaper.getWallpaperComponent()), activity, 534 new WallpaperConnectionListener() { 535 @Override 536 public void onEngineShown() { 537 final Drawable placeholder = previewView.getDrawable() == null 538 ? new ColorDrawable(getResources().getColor(R.color.secondary_color, 539 activity.getTheme())) 540 : previewView.getDrawable(); 541 LiveTileOverlay.INSTANCE.setForegroundDrawable(placeholder); 542 LiveTileOverlay.INSTANCE.attach(previewView.getOverlay()); 543 previewView.animate() 544 .setStartDelay(400) 545 .setDuration(400) 546 .setInterpolator(AnimationUtils.loadInterpolator(getContext(), 547 android.R.interpolator.fast_out_linear_in)) 548 .setUpdateListener(value -> placeholder.setAlpha( 549 (int) (MAX_ALPHA * (1 - value.getAnimatedFraction())))) 550 .withEndAction(() -> { 551 LiveTileOverlay.INSTANCE.setForegroundDrawable(null); 552 553 }).start(); 554 555 } 556 }, previewGlobalRect); 557 558 LiveTileOverlay.INSTANCE.update(new RectF(previewLocalRect), 559 ((CardView) previewView.getParent()).getRadius()); 560 561 mWallpaperConnection.setVisibility(true); 562 previewView.post(() -> { 563 if (!mWallpaperConnection.connect()) { 564 mWallpaperConnection = null; 565 LiveTileOverlay.INSTANCE.detach(previewView.getOverlay()); 566 } 567 }); 568 } 569 570 /** 571 * Returns the width to use for the home screen wallpaper in the "single metadata" configuration. 572 */ getSingleWallpaperImageWidth()573 private int getSingleWallpaperImageWidth() { 574 Point screenSize = ScreenSizeCalculator.getInstance() 575 .getScreenSize(getActivity().getWindowManager().getDefaultDisplay()); 576 577 int height = getResources().getDimensionPixelSize(R.dimen.single_metadata_card_layout_height); 578 return height * screenSize.x / screenSize.y; 579 } 580 581 /** 582 * Refreshes the current wallpaper in a daily wallpaper rotation. 583 */ refreshDailyWallpaper()584 private void refreshDailyWallpaper() { 585 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore 586 // causes Espresso to hang once the dialog is shown. 587 if (!mTestingMode) { 588 int themeResId; 589 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) { 590 themeResId = R.style.ProgressDialogThemePreL; 591 } else { 592 themeResId = R.style.LightDialogTheme; 593 } 594 mRefreshWallpaperProgressDialog = new ProgressDialog(getActivity(), themeResId); 595 mRefreshWallpaperProgressDialog.setTitle(null); 596 mRefreshWallpaperProgressDialog.setMessage( 597 getResources().getString(R.string.refreshing_daily_wallpaper_dialog_message)); 598 mRefreshWallpaperProgressDialog.setIndeterminate(true); 599 mRefreshWallpaperProgressDialog.setCancelable(false); 600 mRefreshWallpaperProgressDialog.show(); 601 } 602 603 WallpaperRotationRefresher wallpaperRotationRefresher = 604 InjectorProvider.getInjector().getWallpaperRotationRefresher(); 605 wallpaperRotationRefresher.refreshWallpaper(getContext(), new Listener() { 606 @Override 607 public void onRefreshed() { 608 // If the fragment is detached from the activity there's nothing to do here and the UI will 609 // update when the fragment is resumed. 610 if (getActivity() == null) { 611 return; 612 } 613 614 if (mRefreshWallpaperProgressDialog != null) { 615 mRefreshWallpaperProgressDialog.dismiss(); 616 } 617 } 618 619 @Override 620 public void onError() { 621 if (getActivity() == null) { 622 return; 623 } 624 625 if (mRefreshWallpaperProgressDialog != null) { 626 mRefreshWallpaperProgressDialog.dismiss(); 627 } 628 629 AlertDialog errorDialog = new AlertDialog.Builder(getActivity(), R.style.LightDialogTheme) 630 .setMessage(R.string.refresh_daily_wallpaper_failed_message) 631 .setPositiveButton(android.R.string.ok, null /* onClickListener */) 632 .create(); 633 errorDialog.show(); 634 } 635 }); 636 } 637 638 /** 639 * Returns the width to use for the home and lock screen wallpapers in the "both metadata" 640 * configuration. 641 */ getBothWallpaperImageWidth()642 private int getBothWallpaperImageWidth() { 643 DisplayMetrics metrics = DisplayMetricsRetriever.getInstance().getDisplayMetrics(getResources(), 644 getActivity().getWindowManager().getDefaultDisplay()); 645 646 // In the "both metadata" configuration, wallpaper images minus the gutters account for the full 647 // width of the device's screen. 648 return metrics.widthPixels - (3 * getResources().getDimensionPixelSize(R.dimen.grid_padding)); 649 } 650 updateThumbnail(WallpaperInfo wallpaperInfo, ImageView thumbnailView, boolean isHomeWallpaper)651 private void updateThumbnail(WallpaperInfo wallpaperInfo, ImageView thumbnailView, 652 boolean isHomeWallpaper) { 653 if (wallpaperInfo == null) { 654 return; 655 } 656 657 if (thumbnailView == null) { 658 return; 659 } 660 661 Activity activity = getActivity(); 662 if (activity == null) { 663 return; 664 } 665 666 UserEventLogger eventLogger = InjectorProvider.getInjector().getUserEventLogger(activity); 667 668 boolean renderInImageWallpaperSurface = 669 !(wallpaperInfo instanceof LiveWallpaperInfo) && isHomeWallpaper; 670 wallpaperInfo.getThumbAsset(activity.getApplicationContext()) 671 .loadDrawable(activity, 672 renderInImageWallpaperSurface ? mHomeImageWallpaper : thumbnailView, 673 getResources().getColor(R.color.secondary_color)); 674 if (isHomeWallpaper) { 675 LiveTileOverlay.INSTANCE.detach(thumbnailView.getOverlay()); 676 if (wallpaperInfo instanceof LiveWallpaperInfo) { 677 setUpLiveWallpaperPreview(wallpaperInfo, thumbnailView, 678 new ColorDrawable(getResources().getColor( 679 R.color.secondary_color, activity.getTheme()))); 680 } else { 681 if (mWallpaperConnection != null) { 682 mWallpaperConnection.disconnect(); 683 mWallpaperConnection = null; 684 } 685 } 686 } 687 thumbnailView.setOnClickListener(view -> { 688 getFragmentHost().showViewOnlyPreview(wallpaperInfo); 689 eventLogger.logCurrentWallpaperPreviewed(); 690 }); 691 } 692 updateWallpaperSurface()693 private void updateWallpaperSurface() { 694 mWallpaperSurface.getHolder().addCallback(mWallpaperSurfaceCallback); 695 } 696 updateWorkspaceSurface()697 private void updateWorkspaceSurface() { 698 mWorkspaceSurface.setZOrderMediaOverlay(true); 699 mWorkspaceSurface.getHolder().addCallback(mWorkspaceSurfaceCallback); 700 } 701 702 private final SurfaceHolder.Callback mWallpaperSurfaceCallback = new SurfaceHolder.Callback() { 703 704 @Override 705 public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) { 706 if (mHomeImageWallpaper == null) { 707 mHomeImageWallpaper = new ImageView(getContext()); 708 mHomeImageWallpaper.setBackgroundColor( 709 ContextCompat.getColor(getContext(), R.color.primary_color)); 710 mHomeImageWallpaper.measure(makeMeasureSpec(mHomePreview.getWidth(), EXACTLY), 711 makeMeasureSpec(mHomePreview.getHeight(), EXACTLY)); 712 mHomeImageWallpaper.layout(0, 0, mHomePreview.getWidth(), mHomePreview.getHeight()); 713 714 SurfaceControlViewHost host = new SurfaceControlViewHost(getContext(), 715 getContext().getDisplay(), mWallpaperSurface.getHostToken()); 716 host.setView(mHomeImageWallpaper, mHomeImageWallpaper.getWidth(), 717 mHomeImageWallpaper.getHeight()); 718 mWallpaperSurface.setChildSurfacePackage(host.getSurfacePackage()); 719 } 720 } 721 722 @Override 723 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 724 } 725 726 @Override 727 public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) { 728 } 729 }; 730 731 private final SurfaceHolder.Callback mWorkspaceSurfaceCallback = new SurfaceHolder.Callback() { 732 @Override 733 public void surfaceCreated(SurfaceHolder holder) { 734 Bundle bundle = SurfaceViewRequestUtils.createSurfaceBundle(mWorkspaceSurface); 735 if (mPreviewUtils.supportsPreview()) { 736 mPreviewUtils.renderPreview(bundle); 737 } 738 } 739 740 @Override 741 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } 742 743 @Override 744 public void surfaceDestroyed(SurfaceHolder holder) { } 745 }; 746 747 private interface MetadataHolder { 748 /** 749 * Binds {@link WallpaperInfo} objects representing the currently-set wallpapers to the 750 * ViewHolder layout. 751 */ bindWallpapers(WallpaperInfo homeWallpaper, WallpaperInfo lockWallpaper, @PresentationMode int presentationMode)752 void bindWallpapers(WallpaperInfo homeWallpaper, WallpaperInfo lockWallpaper, 753 @PresentationMode int presentationMode); 754 } 755 756 private static class SelectWallpaperHeaderHolder extends RecyclerView.ViewHolder { SelectWallpaperHeaderHolder(View headerView)757 public SelectWallpaperHeaderHolder(View headerView) { 758 super(headerView); 759 } 760 } 761 762 /** 763 * ViewHolder subclass for a metadata "card" at the beginning of the RecyclerView. 764 */ 765 private class SingleWallpaperMetadataHolder extends RecyclerView.ViewHolder 766 implements MetadataHolder { 767 private WallpaperInfo mWallpaperInfo; 768 private ImageView mWallpaperImage; 769 private TextView mWallpaperPresentationModeSubtitle; 770 private TextView mWallpaperTitle; 771 private TextView mWallpaperSubtitle; 772 private TextView mWallpaperSubtitle2; 773 private ImageButton mWallpaperExploreButtonNoText; 774 private ImageButton mSkipWallpaperButton; 775 SingleWallpaperMetadataHolder(View metadataView)776 public SingleWallpaperMetadataHolder(View metadataView) { 777 super(metadataView); 778 779 mWallpaperImage = metadataView.findViewById(R.id.wallpaper_image); 780 mWallpaperImage.getLayoutParams().width = getSingleWallpaperImageWidth(); 781 782 mWallpaperPresentationModeSubtitle = 783 metadataView.findViewById(R.id.wallpaper_presentation_mode_subtitle); 784 mWallpaperTitle = metadataView.findViewById(R.id.wallpaper_title); 785 mWallpaperSubtitle = metadataView.findViewById(R.id.wallpaper_subtitle); 786 mWallpaperSubtitle2 = metadataView.findViewById(R.id.wallpaper_subtitle2); 787 788 mWallpaperExploreButtonNoText = 789 metadataView.findViewById(R.id.wallpaper_explore_button_notext); 790 791 mSkipWallpaperButton = metadataView.findViewById(R.id.skip_wallpaper_button); 792 } 793 794 /** 795 * Binds home screen wallpaper to the ViewHolder layout. 796 */ 797 @Override bindWallpapers(WallpaperInfo homeWallpaper, WallpaperInfo lockWallpaper, @PresentationMode int presentationMode)798 public void bindWallpapers(WallpaperInfo homeWallpaper, WallpaperInfo lockWallpaper, 799 @PresentationMode int presentationMode) { 800 mWallpaperInfo = homeWallpaper; 801 802 bindWallpaperAsset(); 803 bindWallpaperText(presentationMode); 804 bindWallpaperActionButtons(presentationMode); 805 } 806 bindWallpaperAsset()807 private void bindWallpaperAsset() { 808 final UserEventLogger eventLogger = 809 InjectorProvider.getInjector().getUserEventLogger(getActivity()); 810 811 mWallpaperInfo.getThumbAsset(getActivity().getApplicationContext()).loadDrawable( 812 getActivity(), mWallpaperImage, getResources().getColor(R.color.secondary_color)); 813 814 mWallpaperImage.setOnClickListener(new OnClickListener() { 815 @Override 816 public void onClick(View v) { 817 getFragmentHost().showViewOnlyPreview(mWallpaperInfo); 818 eventLogger.logCurrentWallpaperPreviewed(); 819 } 820 }); 821 } 822 bindWallpaperText(@resentationMode int presentationMode)823 private void bindWallpaperText(@PresentationMode int presentationMode) { 824 Context appContext = getActivity().getApplicationContext(); 825 826 mWallpaperPresentationModeSubtitle.setText( 827 AttributionFormatter.getHumanReadableWallpaperPresentationMode( 828 appContext, presentationMode)); 829 830 List<String> attributions = mWallpaperInfo.getAttributions(appContext); 831 if (!attributions.isEmpty()) { 832 mWallpaperTitle.setText(attributions.get(0)); 833 } 834 if (attributions.size() > 1) { 835 mWallpaperSubtitle.setText(attributions.get(1)); 836 } else { 837 mWallpaperSubtitle.setVisibility(View.INVISIBLE); 838 } 839 if (attributions.size() > 2) { 840 mWallpaperSubtitle2.setText(attributions.get(2)); 841 } else { 842 mWallpaperSubtitle2.setVisibility(View.INVISIBLE); 843 } 844 } 845 bindWallpaperActionButtons(@resentationMode int presentationMode)846 private void bindWallpaperActionButtons(@PresentationMode int presentationMode) { 847 final Context appContext = getActivity().getApplicationContext(); 848 849 final String actionUrl = mWallpaperInfo.getActionUrl(appContext); 850 if (actionUrl != null && !actionUrl.isEmpty()) { 851 852 Uri exploreUri = Uri.parse(actionUrl); 853 854 ExploreIntentChecker intentChecker = 855 InjectorProvider.getInjector().getExploreIntentChecker(appContext); 856 intentChecker.fetchValidActionViewIntent(exploreUri, (@Nullable Intent exploreIntent) -> { 857 if (getActivity() == null) { 858 return; 859 } 860 861 updateExploreSectionVisibility(presentationMode, exploreIntent); 862 }); 863 } else { 864 updateExploreSectionVisibility(presentationMode, null /* exploreIntent */); 865 } 866 } 867 868 /** 869 * Shows or hides appropriate elements in the "Explore section" (containing the Explore button 870 * and the Next Wallpaper button) depending on the current wallpaper. 871 * 872 * @param presentationMode The presentation mode of the current wallpaper. 873 * @param exploreIntent An optional explore intent for the current wallpaper. 874 */ updateExploreSectionVisibility( @resentationMode int presentationMode, @Nullable Intent exploreIntent)875 private void updateExploreSectionVisibility( 876 @PresentationMode int presentationMode, @Nullable Intent exploreIntent) { 877 878 final Context appContext = getActivity().getApplicationContext(); 879 final UserEventLogger eventLogger = 880 InjectorProvider.getInjector().getUserEventLogger(appContext); 881 882 boolean showSkipWallpaperButton = Flags.skipDailyWallpaperButtonEnabled 883 && presentationMode == WallpaperPreferences.PRESENTATION_MODE_ROTATING; 884 885 if (exploreIntent != null) { 886 mWallpaperExploreButtonNoText.setImageDrawable(getContext().getDrawable( 887 mWallpaperInfo.getActionIconRes(appContext))); 888 mWallpaperExploreButtonNoText.setContentDescription( 889 getString(mWallpaperInfo.getActionLabelRes(appContext))); 890 mWallpaperExploreButtonNoText.setColorFilter( 891 getResources().getColor(R.color.currently_set_explore_button_color, 892 getContext().getTheme()), 893 Mode.SRC_IN); 894 mWallpaperExploreButtonNoText.setVisibility(View.VISIBLE); 895 mWallpaperExploreButtonNoText.setOnClickListener((View view) -> { 896 eventLogger.logActionClicked(mWallpaperInfo.getCollectionId(appContext), 897 mWallpaperInfo.getActionLabelRes(appContext)); 898 startActivity(exploreIntent); 899 }); 900 } 901 902 if (showSkipWallpaperButton) { 903 mSkipWallpaperButton.setVisibility(View.VISIBLE); 904 mSkipWallpaperButton.setOnClickListener((View view) -> refreshDailyWallpaper()); 905 } 906 } 907 } 908 909 /** 910 * ViewHolder subclass for a metadata "card" at the beginning of the RecyclerView that shows 911 * both home screen and lock screen wallpapers. 912 */ 913 private class TwoWallpapersMetadataHolder extends RecyclerView.ViewHolder 914 implements MetadataHolder { 915 private WallpaperInfo mHomeWallpaperInfo; 916 private ImageView mHomeWallpaperImage; 917 private TextView mHomeWallpaperPresentationMode; 918 private TextView mHomeWallpaperTitle; 919 private TextView mHomeWallpaperSubtitle1; 920 private TextView mHomeWallpaperSubtitle2; 921 922 private ImageButton mHomeWallpaperExploreButton; 923 private ImageButton mSkipWallpaperButton; 924 private ViewGroup mHomeWallpaperPresentationSection; 925 926 private WallpaperInfo mLockWallpaperInfo; 927 private ImageView mLockWallpaperImage; 928 private TextView mLockWallpaperTitle; 929 private TextView mLockWallpaperSubtitle1; 930 private TextView mLockWallpaperSubtitle2; 931 932 private ImageButton mLockWallpaperExploreButton; 933 TwoWallpapersMetadataHolder(View metadataView)934 public TwoWallpapersMetadataHolder(View metadataView) { 935 super(metadataView); 936 937 // Set the min width of the metadata panel to be the screen width minus space for the 938 // 2 gutters on the sides. This ensures the RecyclerView's GridLayoutManager gives it 939 // a wide-enough initial width to fill up the width of the grid prior to the view being 940 // fully populated. 941 final Display display = getActivity().getWindowManager().getDefaultDisplay(); 942 Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(display); 943 metadataView.setMinimumWidth( 944 screenSize.x - 2 * getResources().getDimensionPixelSize(R.dimen.grid_padding)); 945 946 int bothWallpaperImageWidth = getBothWallpaperImageWidth(); 947 948 FrameLayout homeWallpaperSection = metadataView.findViewById( 949 R.id.home_wallpaper_section); 950 homeWallpaperSection.setMinimumWidth(bothWallpaperImageWidth); 951 mHomeWallpaperImage = metadataView.findViewById(R.id.home_wallpaper_image); 952 953 mHomeWallpaperPresentationMode = 954 metadataView.findViewById(R.id.home_wallpaper_presentation_mode); 955 mHomeWallpaperTitle = metadataView.findViewById(R.id.home_wallpaper_title); 956 mHomeWallpaperSubtitle1 = metadataView.findViewById(R.id.home_wallpaper_subtitle1); 957 mHomeWallpaperSubtitle2 = metadataView.findViewById(R.id.home_wallpaper_subtitle2); 958 mHomeWallpaperPresentationSection = metadataView.findViewById( 959 R.id.home_wallpaper_presentation_section); 960 mHomeWallpaperExploreButton = 961 metadataView.findViewById(R.id.home_wallpaper_explore_button); 962 mSkipWallpaperButton = metadataView.findViewById(R.id.skip_home_wallpaper); 963 964 FrameLayout lockWallpaperSection = metadataView.findViewById( 965 R.id.lock_wallpaper_section); 966 lockWallpaperSection.setMinimumWidth(bothWallpaperImageWidth); 967 mLockWallpaperImage = metadataView.findViewById(R.id.lock_wallpaper_image); 968 969 mLockWallpaperTitle = metadataView.findViewById(R.id.lock_wallpaper_title); 970 mLockWallpaperSubtitle1 = metadataView.findViewById(R.id.lock_wallpaper_subtitle1); 971 mLockWallpaperSubtitle2 = metadataView.findViewById(R.id.lock_wallpaper_subtitle2); 972 mLockWallpaperExploreButton = 973 metadataView.findViewById(R.id.lock_wallpaper_explore_button); 974 } 975 976 @Override bindWallpapers(WallpaperInfo homeWallpaper, WallpaperInfo lockWallpaper, @PresentationMode int presentationMode)977 public void bindWallpapers(WallpaperInfo homeWallpaper, WallpaperInfo lockWallpaper, 978 @PresentationMode int presentationMode) { 979 bindHomeWallpaper(homeWallpaper, presentationMode); 980 bindLockWallpaper(lockWallpaper); 981 } 982 bindHomeWallpaper(WallpaperInfo homeWallpaper, @PresentationMode int presentationMode)983 private void bindHomeWallpaper(WallpaperInfo homeWallpaper, 984 @PresentationMode int presentationMode) { 985 final Context appContext = getActivity().getApplicationContext(); 986 final UserEventLogger eventLogger = 987 InjectorProvider.getInjector().getUserEventLogger(appContext); 988 989 mHomeWallpaperInfo = homeWallpaper; 990 991 homeWallpaper.getThumbAsset(appContext).loadDrawable( 992 getActivity(), mHomeWallpaperImage, 993 getResources().getColor(R.color.secondary_color, getContext().getTheme())); 994 995 mHomeWallpaperPresentationMode.setText( 996 AttributionFormatter.getHumanReadableWallpaperPresentationMode( 997 appContext, presentationMode)); 998 999 List<String> attributions = homeWallpaper.getAttributions(appContext); 1000 if (!attributions.isEmpty()) { 1001 mHomeWallpaperTitle.setText(attributions.get(0)); 1002 } 1003 if (attributions.size() > 1) { 1004 mHomeWallpaperSubtitle1.setText(attributions.get(1)); 1005 } 1006 if (attributions.size() > 2) { 1007 mHomeWallpaperSubtitle2.setText(attributions.get(2)); 1008 } 1009 1010 final String homeActionUrl = homeWallpaper.getActionUrl(appContext); 1011 1012 if (homeActionUrl != null && !homeActionUrl.isEmpty()) { 1013 Uri homeExploreUri = Uri.parse(homeActionUrl); 1014 1015 ExploreIntentChecker intentChecker = 1016 InjectorProvider.getInjector().getExploreIntentChecker(appContext); 1017 1018 intentChecker.fetchValidActionViewIntent( 1019 homeExploreUri, (@Nullable Intent exploreIntent) -> { 1020 if (exploreIntent == null || getActivity() == null) { 1021 return; 1022 } 1023 1024 mHomeWallpaperExploreButton.setVisibility(View.VISIBLE); 1025 mHomeWallpaperExploreButton.setImageDrawable(getContext().getDrawable( 1026 homeWallpaper.getActionIconRes(appContext))); 1027 mHomeWallpaperExploreButton.setContentDescription(getString(homeWallpaper 1028 .getActionLabelRes(appContext))); 1029 mHomeWallpaperExploreButton.setColorFilter( 1030 getResources().getColor(R.color.currently_set_explore_button_color, 1031 getContext().getTheme()), 1032 Mode.SRC_IN); 1033 mHomeWallpaperExploreButton.setOnClickListener(v -> { 1034 eventLogger.logActionClicked( 1035 mHomeWallpaperInfo.getCollectionId(appContext), 1036 mHomeWallpaperInfo.getActionLabelRes(appContext)); 1037 startActivity(exploreIntent); 1038 }); 1039 }); 1040 } else { 1041 mHomeWallpaperExploreButton.setVisibility(View.GONE); 1042 } 1043 1044 if (presentationMode == WallpaperPreferences.PRESENTATION_MODE_ROTATING) { 1045 mHomeWallpaperPresentationSection.setVisibility(View.VISIBLE); 1046 if (Flags.skipDailyWallpaperButtonEnabled) { 1047 mSkipWallpaperButton.setVisibility(View.VISIBLE); 1048 mSkipWallpaperButton.setColorFilter( 1049 getResources().getColor(R.color.currently_set_explore_button_color, 1050 getContext().getTheme()), Mode.SRC_IN); 1051 mSkipWallpaperButton.setOnClickListener(view -> refreshDailyWallpaper()); 1052 } else { 1053 mSkipWallpaperButton.setVisibility(View.GONE); 1054 } 1055 } else { 1056 mHomeWallpaperPresentationSection.setVisibility(View.GONE); 1057 } 1058 1059 mHomeWallpaperImage.setOnClickListener(v -> { 1060 eventLogger.logCurrentWallpaperPreviewed(); 1061 getFragmentHost().showViewOnlyPreview(mHomeWallpaperInfo); 1062 }); 1063 } 1064 bindLockWallpaper(WallpaperInfo lockWallpaper)1065 private void bindLockWallpaper(WallpaperInfo lockWallpaper) { 1066 if (lockWallpaper == null) { 1067 Log.e(TAG, "TwoWallpapersMetadataHolder bound without a lock screen wallpaper."); 1068 return; 1069 } 1070 1071 final Context appContext = getActivity().getApplicationContext(); 1072 final UserEventLogger eventLogger = 1073 InjectorProvider.getInjector().getUserEventLogger(getActivity()); 1074 1075 mLockWallpaperInfo = lockWallpaper; 1076 1077 lockWallpaper.getThumbAsset(appContext).loadDrawable( 1078 getActivity(), mLockWallpaperImage, getResources().getColor(R.color.secondary_color)); 1079 1080 List<String> lockAttributions = lockWallpaper.getAttributions(appContext); 1081 if (!lockAttributions.isEmpty()) { 1082 mLockWallpaperTitle.setText(lockAttributions.get(0)); 1083 } 1084 if (lockAttributions.size() > 1) { 1085 mLockWallpaperSubtitle1.setText(lockAttributions.get(1)); 1086 } 1087 if (lockAttributions.size() > 2) { 1088 mLockWallpaperSubtitle2.setText(lockAttributions.get(2)); 1089 } 1090 1091 final String lockActionUrl = lockWallpaper.getActionUrl(appContext); 1092 1093 if (lockActionUrl != null && !lockActionUrl.isEmpty()) { 1094 Uri lockExploreUri = Uri.parse(lockActionUrl); 1095 1096 ExploreIntentChecker intentChecker = 1097 InjectorProvider.getInjector().getExploreIntentChecker(appContext); 1098 intentChecker.fetchValidActionViewIntent( 1099 lockExploreUri, (@Nullable Intent exploreIntent) -> { 1100 if (exploreIntent == null || getActivity() == null) { 1101 return; 1102 } 1103 mLockWallpaperExploreButton.setImageDrawable(getContext().getDrawable( 1104 lockWallpaper.getActionIconRes(appContext))); 1105 mLockWallpaperExploreButton.setContentDescription(getString( 1106 lockWallpaper.getActionLabelRes(appContext))); 1107 mLockWallpaperExploreButton.setVisibility(View.VISIBLE); 1108 mLockWallpaperExploreButton.setColorFilter( 1109 getResources().getColor( 1110 R.color.currently_set_explore_button_color), 1111 Mode.SRC_IN); 1112 mLockWallpaperExploreButton.setOnClickListener(new OnClickListener() { 1113 @Override 1114 public void onClick(View v) { 1115 eventLogger.logActionClicked( 1116 mLockWallpaperInfo.getCollectionId(appContext), 1117 mLockWallpaperInfo.getActionLabelRes(appContext)); 1118 startActivity(exploreIntent); 1119 } 1120 }); 1121 }); 1122 } else { 1123 mLockWallpaperExploreButton.setVisibility(View.GONE); 1124 } 1125 1126 mLockWallpaperImage.setOnClickListener(new OnClickListener() { 1127 @Override 1128 public void onClick(View v) { 1129 eventLogger.logCurrentWallpaperPreviewed(); 1130 getFragmentHost().showViewOnlyPreview(mLockWallpaperInfo); 1131 } 1132 }); 1133 } 1134 } 1135 1136 private class PreviewPagerAdapter extends PagerAdapter { 1137 1138 private List<View> mPages; 1139 PreviewPagerAdapter(List<View> pages)1140 PreviewPagerAdapter(List<View> pages) { 1141 mPages = pages; 1142 } 1143 1144 @Override destroyItem(@onNull ViewGroup container, int position, @NonNull Object object)1145 public void destroyItem(@NonNull ViewGroup container, int position, 1146 @NonNull Object object) { 1147 container.removeView((View) object); 1148 } 1149 1150 @NonNull 1151 @Override instantiateItem(@onNull ViewGroup container, int position)1152 public Object instantiateItem(@NonNull ViewGroup container, int position) { 1153 View view = mPages.get(position); 1154 container.addView(view); 1155 return view; 1156 } 1157 1158 @Override getCount()1159 public int getCount() { 1160 return mPages.size(); 1161 } 1162 1163 @Override isViewFromObject(@onNull View view, @NonNull Object o)1164 public boolean isViewFromObject(@NonNull View view, @NonNull Object o) { 1165 return view == o; 1166 } 1167 } 1168 } 1169