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 android.app.Activity; 19 import android.app.AlertDialog; 20 import android.app.ProgressDialog; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.graphics.Color; 24 import android.graphics.Insets; 25 import android.graphics.PorterDuff.Mode; 26 import android.graphics.drawable.Drawable; 27 import android.net.Uri; 28 import android.os.AsyncTask; 29 import android.os.Build.VERSION; 30 import android.os.Build.VERSION_CODES; 31 import android.os.Bundle; 32 import android.provider.Settings; 33 import android.util.Log; 34 import android.view.View; 35 import android.view.View.OnClickListener; 36 import android.view.WindowInsets; 37 import android.widget.Button; 38 import android.widget.FrameLayout; 39 import android.widget.ImageView; 40 import android.widget.LinearLayout; 41 import android.widget.TextView; 42 43 import androidx.annotation.NonNull; 44 import androidx.annotation.Nullable; 45 import androidx.appcompat.widget.Toolbar; 46 import androidx.fragment.app.Fragment; 47 import androidx.fragment.app.FragmentManager; 48 49 import com.android.wallpaper.R; 50 import com.android.wallpaper.asset.Asset; 51 import com.android.wallpaper.compat.BuildCompat; 52 import com.android.wallpaper.compat.ButtonDrawableSetterCompat; 53 import com.android.wallpaper.config.Flags; 54 import com.android.wallpaper.model.Category; 55 import com.android.wallpaper.model.ImageWallpaperInfo; 56 import com.android.wallpaper.model.WallpaperInfo; 57 import com.android.wallpaper.module.CurrentWallpaperInfoFactory; 58 import com.android.wallpaper.module.CurrentWallpaperInfoFactory.WallpaperInfoCallback; 59 import com.android.wallpaper.module.DailyLoggingAlarmScheduler; 60 import com.android.wallpaper.module.ExploreIntentChecker; 61 import com.android.wallpaper.module.FormFactorChecker; 62 import com.android.wallpaper.module.Injector; 63 import com.android.wallpaper.module.InjectorProvider; 64 import com.android.wallpaper.module.NetworkStatusNotifier; 65 import com.android.wallpaper.module.NetworkStatusNotifier.NetworkStatus; 66 import com.android.wallpaper.module.UserEventLogger; 67 import com.android.wallpaper.module.UserEventLogger.WallpaperSetFailureReason; 68 import com.android.wallpaper.module.WallpaperPersister; 69 import com.android.wallpaper.module.WallpaperPersister.Destination; 70 import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback; 71 import com.android.wallpaper.module.WallpaperPersister.WallpaperPosition; 72 import com.android.wallpaper.module.WallpaperPreferences; 73 import com.android.wallpaper.module.WallpaperPreferences.PresentationMode; 74 import com.android.wallpaper.module.WallpaperRotationRefresher; 75 import com.android.wallpaper.module.WallpaperRotationRefresher.Listener; 76 import com.android.wallpaper.picker.CategoryFragment.CategoryFragmentHost; 77 import com.android.wallpaper.picker.WallpaperDisabledFragment.WallpaperSupportLevel; 78 import com.android.wallpaper.picker.individual.IndividualPickerFragment; 79 import com.android.wallpaper.util.ScreenSizeCalculator; 80 import com.android.wallpaper.util.ThrowableAnalyzer; 81 import com.android.wallpaper.widget.BottomActionBar; 82 import com.android.wallpaper.widget.BottomActionBar.BottomActionBarHost; 83 84 import com.google.android.material.bottomsheet.BottomSheetBehavior; 85 import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback; 86 import com.google.android.material.tabs.TabLayout; 87 import com.google.android.material.tabs.TabLayout.OnTabSelectedListener; 88 import com.google.android.material.tabs.TabLayout.Tab; 89 90 import java.util.List; 91 92 /** 93 * Activity allowing users to select a category of wallpapers to choose from. 94 */ 95 public class TopLevelPickerActivity extends BaseActivity implements WallpapersUiContainer, 96 CurrentWallpaperBottomSheetPresenter, SetWallpaperErrorDialogFragment.Listener, 97 MyPhotosStarter, CategoryFragmentHost, BottomActionBarHost { 98 99 private static final String TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT = 100 "toplevel_set_wallpaper_error_dialog"; 101 102 private static final String TAG = "TopLevelPicker"; 103 private static final String KEY_SELECTED_CATEGORY_TAB = "selected_category_tab"; 104 105 private WallpaperPickerDelegate mDelegate; 106 private int mLastSelectedCategoryTabIndex; 107 private UserEventLogger mUserEventLogger; 108 private NetworkStatusNotifier mNetworkStatusNotifier; 109 private NetworkStatusNotifier.Listener mNetworkStatusListener; 110 private WallpaperPersister mWallpaperPersister; 111 private WallpaperPreferences mWallpaperPreferences; 112 private boolean mWasCustomPhotoWallpaperSet; 113 @WallpaperPosition 114 private int mCustomPhotoWallpaperPosition; 115 116 /** 117 * Progress dialogs for "refresh daily wallpaper" and "set wallpaper" operations. 118 */ 119 private ProgressDialog mRefreshWallpaperProgressDialog; 120 private ProgressDialog mSetWallpaperProgressDialog; 121 122 /** 123 * Designates a test mode of operation -- in which certain UI features are disabled to allow for 124 * UI tests to run correctly. 125 */ 126 private boolean mTestingMode; 127 128 /** 129 * UI for the "currently set wallpaper" BottomSheet. 130 */ 131 private LinearLayout mBottomSheet; 132 private ImageView mCurrentWallpaperImage; 133 private TextView mCurrentWallpaperPresentationMode; 134 private TextView mCurrentWallpaperTitle; 135 private TextView mCurrentWallpaperSubtitle; 136 private Button mCurrentWallpaperExploreButton; 137 private Button mCurrentWallpaperSkipWallpaperButton; 138 private FrameLayout mFragmentContainer; 139 private FrameLayout mLoadingIndicatorContainer; 140 private LinearLayout mWallpaperPositionOptions; 141 142 /** 143 * Staged error dialog fragments that were unable to be shown when the activity didn't allow 144 * committing fragment transactions. 145 */ 146 private SetWallpaperErrorDialogFragment mStagedSetWallpaperErrorDialogFragment; 147 148 /** 149 * A wallpaper pending set to the device--we retain a reference to this in order to facilitate 150 * retry or re-crop operations. 151 */ 152 private WallpaperInfo mPendingSetWallpaperInfo; 153 getTextColorIdForWallpaperPositionButton(boolean isSelected)154 private static int getTextColorIdForWallpaperPositionButton(boolean isSelected) { 155 return isSelected ? R.color.accent_color : R.color.material_grey500; 156 } 157 158 @Override onCreate(Bundle savedInstanceState)159 protected void onCreate(Bundle savedInstanceState) { 160 super.onCreate(savedInstanceState); 161 162 mLastSelectedCategoryTabIndex = -1; 163 164 Injector injector = InjectorProvider.getInjector(); 165 mDelegate = new WallpaperPickerDelegate(this, this, injector); 166 mUserEventLogger = injector.getUserEventLogger(this); 167 mNetworkStatusNotifier = injector.getNetworkStatusNotifier(this); 168 mWallpaperPersister = injector.getWallpaperPersister(this); 169 mWallpaperPreferences = injector.getPreferences(this); 170 mWasCustomPhotoWallpaperSet = false; 171 172 mDelegate.getCategoryProvider().resetIfNeeded(); 173 174 @WallpaperSupportLevel int wallpaperSupportLevel = mDelegate.getWallpaperSupportLevel(); 175 if (wallpaperSupportLevel != WallpaperDisabledFragment.SUPPORTED_CAN_SET) { 176 setContentView(R.layout.activity_top_level_picker); 177 178 FragmentManager fm = getSupportFragmentManager(); 179 WallpaperDisabledFragment wallpaperDisabledFragment = 180 WallpaperDisabledFragment.newInstance(wallpaperSupportLevel); 181 fm.beginTransaction() 182 .add(R.id.fragment_container, wallpaperDisabledFragment) 183 .commit(); 184 return; 185 } 186 187 if (mDelegate.getFormFactor() == FormFactorChecker.FORM_FACTOR_MOBILE) { 188 initializeMobile(true /* shouldForceRefresh */); 189 } else { // DESKTOP 190 initializeDesktop(savedInstanceState); 191 } 192 } 193 194 @Override onResume()195 protected void onResume() { 196 super.onResume(); 197 boolean provisioned = Settings.Global.getInt(getContentResolver(), 198 Settings.Global.DEVICE_PROVISIONED, 0) != 0; 199 200 mUserEventLogger.logResumed(provisioned, true); 201 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one 202 // that was unable to be shown earlier when this fragment's hosting activity didn't allow 203 // committing fragment transactions. 204 if (mStagedSetWallpaperErrorDialogFragment != null) { 205 mStagedSetWallpaperErrorDialogFragment.show( 206 getSupportFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT); 207 mStagedSetWallpaperErrorDialogFragment = null; 208 } 209 } 210 211 @Override onStop()212 protected void onStop() { 213 mUserEventLogger.logStopped(); 214 super.onStop(); 215 } 216 217 @Override onDestroy()218 protected void onDestroy() { 219 super.onDestroy(); 220 mDelegate.cleanUp(); 221 if (mNetworkStatusListener != null) { 222 mNetworkStatusNotifier.unregisterListener(mNetworkStatusListener); 223 } 224 225 if (mRefreshWallpaperProgressDialog != null) { 226 mRefreshWallpaperProgressDialog.dismiss(); 227 } 228 if (mSetWallpaperProgressDialog != null) { 229 mSetWallpaperProgressDialog.dismiss(); 230 } 231 } 232 233 @Override onBackPressed()234 public void onBackPressed() { 235 Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container); 236 if (fragment instanceof BottomActionBarFragment 237 && ((BottomActionBarFragment) fragment).onBackPressed()) { 238 return; 239 } 240 241 CategoryFragment categoryFragment = getCategoryFragment(); 242 if (categoryFragment != null && categoryFragment.popChildFragment()) { 243 return; 244 } 245 super.onBackPressed(); 246 } 247 248 @Override requestCustomPhotoPicker(PermissionChangedListener listener)249 public void requestCustomPhotoPicker(PermissionChangedListener listener) { 250 mDelegate.requestCustomPhotoPicker(listener); 251 } 252 253 @Override requestExternalStoragePermission(PermissionChangedListener listener)254 public void requestExternalStoragePermission(PermissionChangedListener listener) { 255 mDelegate.requestExternalStoragePermission(listener); 256 } 257 258 /** 259 * Returns whether READ_EXTERNAL_STORAGE has been granted for the application. 260 */ isReadExternalStoragePermissionGranted()261 public boolean isReadExternalStoragePermissionGranted() { 262 return mDelegate.isReadExternalStoragePermissionGranted(); 263 } 264 initializeMobile(boolean shouldForceRefresh)265 private void initializeMobile(boolean shouldForceRefresh) { 266 setContentView(R.layout.activity_top_level_picker); 267 getWindow().getDecorView().setSystemUiVisibility( 268 getWindow().getDecorView().getSystemUiVisibility() 269 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 270 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); 271 View fragmentContainer = findViewById(R.id.fragment_container); 272 fragmentContainer.setOnApplyWindowInsetsListener((view, windowInsets) -> { 273 view.setPadding(view.getPaddingLeft(), windowInsets.getSystemWindowInsetTop(), 274 view.getPaddingRight(), view.getPaddingBottom()); 275 // Consume only the top inset (status bar), to let other content in the Activity consume 276 // the nav bar (ie, by using "fitSystemWindows") 277 if (BuildCompat.isAtLeastQ()) { 278 WindowInsets.Builder builder = new WindowInsets.Builder(windowInsets); 279 builder.setSystemWindowInsets(Insets.of(windowInsets.getSystemWindowInsetLeft(), 280 0, windowInsets.getStableInsetRight(), 281 windowInsets.getSystemWindowInsetBottom())); 282 return builder.build(); 283 } else { 284 return windowInsets.replaceSystemWindowInsets( 285 windowInsets.getSystemWindowInsetLeft(), 286 0, windowInsets.getStableInsetRight(), 287 windowInsets.getSystemWindowInsetBottom()); 288 } 289 }); 290 291 // Set toolbar as the action bar. 292 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 293 setSupportActionBar(toolbar); 294 295 FragmentManager fm = getSupportFragmentManager(); 296 Fragment fragment = fm.findFragmentById(R.id.fragment_container); 297 298 if (fragment == null) { 299 // App launch specific logic: log the "app launched" event and set up daily logging. 300 mUserEventLogger.logAppLaunched(); 301 mWallpaperPreferences.incrementAppLaunched(); 302 DailyLoggingAlarmScheduler.setAlarm(getApplicationContext()); 303 304 CategoryFragment newFragment = CategoryFragment.newInstance( 305 getString(R.string.wallpaper_app_name)); 306 fm.beginTransaction() 307 .add(R.id.fragment_container, newFragment) 308 .commit(); 309 } 310 } 311 initializeDesktop(Bundle savedInstanceState)312 private void initializeDesktop(Bundle savedInstanceState) { 313 setContentView(R.layout.activity_top_level_desktop); 314 315 mBottomSheet = (LinearLayout) findViewById(R.id.bottom_sheet); 316 mCurrentWallpaperImage = (ImageView) mBottomSheet.findViewById(R.id.current_wallpaper_image); 317 mCurrentWallpaperImage.getLayoutParams().width = getSingleWallpaperImageWidthPx(); 318 319 mCurrentWallpaperPresentationMode = 320 (TextView) mBottomSheet.findViewById(R.id.current_wallpaper_presentation_mode); 321 mCurrentWallpaperTitle = (TextView) findViewById(R.id.current_wallpaper_title); 322 mCurrentWallpaperSubtitle = (TextView) findViewById(R.id.current_wallpaper_subtitle); 323 mCurrentWallpaperExploreButton = (Button) findViewById( 324 R.id.current_wallpaper_explore_button); 325 mCurrentWallpaperSkipWallpaperButton = (Button) findViewById( 326 R.id.current_wallpaper_skip_wallpaper_button); 327 mFragmentContainer = (FrameLayout) findViewById(R.id.fragment_container); 328 mLoadingIndicatorContainer = (FrameLayout) findViewById(R.id.loading_indicator_container); 329 mWallpaperPositionOptions = (LinearLayout) findViewById( 330 R.id.desktop_wallpaper_position_options); 331 332 final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout); 333 tabLayout.addOnTabSelectedListener(new OnTabSelectedListener() { 334 @Override 335 public void onTabSelected(Tab tab) { 336 Category category = (Category) tab.getTag(); 337 showCategoryDesktop(category.getCollectionId()); 338 mLastSelectedCategoryTabIndex = tabLayout.getSelectedTabPosition(); 339 } 340 341 @Override 342 public void onTabUnselected(Tab tab) { 343 } 344 345 @Override 346 public void onTabReselected(Tab tab) { 347 Category category = (Category) tab.getTag(); 348 // If offline, "My photos" may be the only visible category. In this case we want to allow 349 // re-selection so user can still select a photo as wallpaper while offline. 350 if (!category.isEnumerable()) { 351 onTabSelected(tab); 352 } 353 } 354 }); 355 356 FragmentManager fm = getSupportFragmentManager(); 357 Fragment fragment = fm.findFragmentById(R.id.fragment_container); 358 359 if (fragment == null) { 360 // App launch specific logic: log the "app launched" event and set up daily logging. 361 mUserEventLogger.logAppLaunched(); 362 mWallpaperPreferences.incrementAppLaunched(); 363 DailyLoggingAlarmScheduler.setAlarm(getApplicationContext()); 364 } 365 366 mNetworkStatusListener = new NetworkStatusNotifier.Listener() { 367 @Override 368 public void onNetworkChanged(@NetworkStatus int networkStatus) { 369 initializeDesktopBasedOnNetwork(networkStatus, savedInstanceState); 370 } 371 }; 372 // Upon registering a listener, the onNetworkChanged method is immediately called with the 373 // initial network status. 374 mNetworkStatusNotifier.registerListener(mNetworkStatusListener); 375 } 376 initializeDesktopBasedOnNetwork(@etworkStatus int networkStatus, Bundle savedInstanceState)377 private void initializeDesktopBasedOnNetwork(@NetworkStatus int networkStatus, 378 Bundle savedInstanceState) { 379 if (networkStatus == NetworkStatusNotifier.NETWORK_CONNECTED) { 380 initializeDesktopOnline(savedInstanceState); 381 } else { 382 initializeDesktopOffline(); 383 } 384 } 385 initializeDesktopOnline(Bundle savedInstanceState)386 private void initializeDesktopOnline(Bundle savedInstanceState) { 387 FragmentManager fm = getSupportFragmentManager(); 388 Fragment fragment = fm.findFragmentById(R.id.fragment_container); 389 390 // Require a category refresh if this is the first load of the app or if the app is now 391 // returning online after having been offline. 392 boolean forceCategoryRefresh = fragment == null || fragment instanceof OfflineDesktopFragment; 393 394 if (fragment != null) { 395 fm.beginTransaction() 396 .remove(fragment) 397 .commit(); 398 } 399 400 mLastSelectedCategoryTabIndex = savedInstanceState != null 401 ? savedInstanceState.getInt(KEY_SELECTED_CATEGORY_TAB) : -1; 402 mDelegate.populateCategories(forceCategoryRefresh); 403 404 setDesktopLoading(true); 405 setUpBottomSheet(); 406 refreshCurrentWallpapers(null /* refreshListener */); 407 } 408 initializeDesktopOffline()409 private void initializeDesktopOffline() { 410 FragmentManager fm = getSupportFragmentManager(); 411 Fragment fragment = fm.findFragmentById(R.id.fragment_container); 412 413 if (fragment != null) { 414 fm.beginTransaction() 415 .remove(fragment) 416 .commit(); 417 } 418 OfflineDesktopFragment newFragment = new OfflineDesktopFragment(); 419 fm.beginTransaction() 420 .add(R.id.fragment_container, newFragment) 421 .commit(); 422 423 // Reset the last selected category tab index to ensure the app doesn't try to reselect a 424 // tab for a category not yet repopulated. 425 mLastSelectedCategoryTabIndex = -1; 426 427 mDelegate.populateCategories(true /* forceCategoryRefresh */); 428 429 setDesktopLoading(false); 430 setCurrentWallpapersExpanded(false); 431 } 432 433 /** 434 * Sets the status of the loading indicator overlay in desktop mode. 435 * 436 * @param loading Whether an indeterminate loading indicator is displayed in place of the main 437 * fragment. 438 */ setDesktopLoading(boolean loading)439 private void setDesktopLoading(boolean loading) { 440 if (loading) { 441 mLoadingIndicatorContainer.setVisibility(View.VISIBLE); 442 mFragmentContainer.setVisibility(View.GONE); 443 } else { 444 mLoadingIndicatorContainer.setVisibility(View.GONE); 445 mFragmentContainer.setVisibility(View.VISIBLE); 446 } 447 } 448 449 /** 450 * Returns the width (in physical px) to use for the "currently set wallpaper" thumbnail. 451 */ getSingleWallpaperImageWidthPx()452 private int getSingleWallpaperImageWidthPx() { 453 final float screenAspectRatio = 454 ScreenSizeCalculator.getInstance().getScreenAspectRatio(this); 455 456 int height = getResources().getDimensionPixelSize( 457 R.dimen.current_wallpaper_bottom_sheet_thumb_height); 458 return (int) (height / screenAspectRatio); 459 } 460 461 /** 462 * Enables and populates the "Currently set" wallpaper BottomSheet. 463 */ setUpBottomSheet()464 private void setUpBottomSheet() { 465 mBottomSheet.setVisibility(View.VISIBLE); 466 467 if (Flags.skipDailyWallpaperButtonEnabled) { 468 // Add "next" icon to the Next Wallpaper button 469 Drawable nextWallpaperButtonDrawable = getResources().getDrawable( 470 R.drawable.ic_refresh_18px); 471 472 // This Drawable's state is shared across the app, so make a copy of it before applying a 473 // color tint as not to affect other clients elsewhere in the app. 474 nextWallpaperButtonDrawable = 475 nextWallpaperButtonDrawable.getConstantState().newDrawable().mutate(); 476 // Color the "compass" icon with the accent color. 477 nextWallpaperButtonDrawable.setColorFilter( 478 getResources().getColor(R.color.accent_color), Mode.SRC_IN); 479 ButtonDrawableSetterCompat.setDrawableToButtonStart( 480 mCurrentWallpaperSkipWallpaperButton, nextWallpaperButtonDrawable); 481 } 482 483 final BottomSheetBehavior<LinearLayout> bottomSheetBehavior = 484 BottomSheetBehavior.from(mBottomSheet); 485 bottomSheetBehavior.setBottomSheetCallback(new BottomSheetCallback() { 486 @Override 487 public void onStateChanged(@NonNull View view, int i) { 488 } 489 490 @Override 491 public void onSlide(@NonNull View view, float slideOffset) { 492 float alpha; 493 if (slideOffset >= 0) { 494 alpha = slideOffset; 495 } else { 496 alpha = 1f - slideOffset; 497 } 498 LinearLayout bottomSheetContents = findViewById(R.id.bottom_sheet_contents); 499 bottomSheetContents.setAlpha(alpha); 500 } 501 }); 502 } 503 504 /** 505 * Enables a test mode of operation -- in which certain UI features are disabled to allow for 506 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog 507 * constantly keeps the UI thread alive and blocks a test forever. 508 */ setTestingMode(boolean testingMode)509 void setTestingMode(boolean testingMode) { 510 mTestingMode = testingMode; 511 } 512 513 /** 514 * Obtains the {@link WallpaperInfo} object(s) representing the wallpaper(s) currently set to the 515 * device from the {@link CurrentWallpaperInfoFactory} and displays them in the BottomSheet. 516 */ 517 @Override refreshCurrentWallpapers(@ullable RefreshListener refreshListener)518 public void refreshCurrentWallpapers(@Nullable RefreshListener refreshListener) { 519 final Injector injector = InjectorProvider.getInjector(); 520 final Context appContext = getApplicationContext(); 521 522 CurrentWallpaperInfoFactory factory = injector.getCurrentWallpaperFactory(this); 523 factory.createCurrentWallpaperInfos(new WallpaperInfoCallback() { 524 @Override 525 public void onWallpaperInfoCreated( 526 final WallpaperInfo homeWallpaper, 527 @Nullable final WallpaperInfo lockWallpaper, 528 @PresentationMode final int presentationMode) { 529 530 if (isDestroyed()) { 531 return; 532 } 533 534 // Fetch the home wallpaper's thumbnail asset asynchronously to work around expensive 535 // method call to WallpaperManager#getWallpaperFile made from the CurrentWallpaperInfoVN 536 // getAsset() method. 537 AssetReceiver assetReceiver = (Asset thumbAsset) -> { 538 if (isDestroyed()) { 539 return; 540 } 541 542 homeWallpaper.getThumbAsset(appContext).loadDrawableWithTransition( 543 TopLevelPickerActivity.this, 544 mCurrentWallpaperImage, 545 200 /* transitionDurationMillis */, 546 () -> { 547 if (refreshListener != null) { 548 refreshListener.onCurrentWallpaperRefreshed(); 549 } 550 }, 551 Color.TRANSPARENT); 552 }; 553 new FetchThumbAssetTask(appContext, homeWallpaper, assetReceiver).executeOnExecutor( 554 AsyncTask.THREAD_POOL_EXECUTOR); 555 556 mCurrentWallpaperPresentationMode.setText( 557 AttributionFormatter.getHumanReadableWallpaperPresentationMode( 558 TopLevelPickerActivity.this, presentationMode)); 559 560 List<String> attributions = homeWallpaper.getAttributions(appContext); 561 if (attributions.size() > 0 && attributions.get(0) != null) { 562 mCurrentWallpaperTitle.setText(attributions.get(0)); 563 } 564 565 mCurrentWallpaperSubtitle.setText( 566 AttributionFormatter.formatWallpaperSubtitle(appContext, homeWallpaper)); 567 568 final String actionUrl = homeWallpaper.getActionUrl(appContext); 569 if (actionUrl != null && !actionUrl.isEmpty()) { 570 Uri exploreUri = Uri.parse(actionUrl); 571 572 ExploreIntentChecker intentChecker = injector.getExploreIntentChecker(appContext); 573 intentChecker.fetchValidActionViewIntent(exploreUri, (@Nullable Intent exploreIntent) -> { 574 if (exploreIntent != null && !isDestroyed()) { 575 // Set the icon for the button 576 Drawable exploreButtonDrawable = getResources().getDrawable( 577 homeWallpaper.getActionIconRes(appContext)); 578 579 // This Drawable's state is shared across the app, so make a copy of it 580 // before applying a color tint as not to affect other clients elsewhere 581 // in the app. 582 exploreButtonDrawable = exploreButtonDrawable.getConstantState() 583 .newDrawable().mutate(); 584 // Color the "compass" icon with the accent color. 585 exploreButtonDrawable.setColorFilter( 586 getResources().getColor(R.color.accent_color), Mode.SRC_IN); 587 588 ButtonDrawableSetterCompat.setDrawableToButtonStart( 589 mCurrentWallpaperExploreButton, exploreButtonDrawable); 590 mCurrentWallpaperExploreButton.setText(getString( 591 homeWallpaper.getActionLabelRes(appContext))); 592 mCurrentWallpaperExploreButton.setVisibility(View.VISIBLE); 593 mCurrentWallpaperExploreButton.setOnClickListener(new OnClickListener() { 594 @Override 595 public void onClick(View v) { 596 mUserEventLogger.logActionClicked( 597 homeWallpaper.getCollectionId(appContext), 598 homeWallpaper.getActionLabelRes(appContext)); 599 startActivity(exploreIntent); 600 } 601 }); 602 } 603 }); 604 } else { 605 mCurrentWallpaperExploreButton.setVisibility(View.GONE); 606 } 607 608 // Hide the wallpaper position options UI if the current home wallpaper is not from 609 // "my photos". 610 String homeCollectionId = homeWallpaper.getCollectionId(TopLevelPickerActivity.this); 611 if (mWallpaperPositionOptions != null 612 && homeCollectionId != null // May be null if app is being used for the first time. 613 && !homeCollectionId.equals(getString(R.string.image_wallpaper_collection_id))) { 614 mWallpaperPositionOptions.setVisibility(View.GONE); 615 } 616 617 boolean showSkipWallpaperButton = Flags.skipDailyWallpaperButtonEnabled 618 && presentationMode == WallpaperPreferences.PRESENTATION_MODE_ROTATING; 619 if (showSkipWallpaperButton) { 620 mCurrentWallpaperSkipWallpaperButton.setVisibility(View.VISIBLE); 621 mCurrentWallpaperSkipWallpaperButton.setOnClickListener( 622 v -> refreshDailyWallpaper()); 623 } else { 624 mCurrentWallpaperSkipWallpaperButton.setVisibility(View.GONE); 625 } 626 627 if (refreshListener != null) { 628 refreshListener.onCurrentWallpaperRefreshed(); 629 } 630 } 631 }, true /* forceRefresh */); 632 } 633 634 @Override onSaveInstanceState(Bundle savedInstanceState)635 public void onSaveInstanceState(Bundle savedInstanceState) { 636 FormFactorChecker formFactorChecker = InjectorProvider.getInjector().getFormFactorChecker(this); 637 if (formFactorChecker.getFormFactor() == FormFactorChecker.FORM_FACTOR_DESKTOP) { 638 TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout); 639 640 // tabLayout is only present when the main IndividualPickerFragment is present (as 641 // opposed to 642 // the WallpaperDisabledFragment), so need this null check. 643 if (tabLayout != null) { 644 savedInstanceState.putInt(KEY_SELECTED_CATEGORY_TAB, tabLayout.getSelectedTabPosition()); 645 } 646 } 647 648 super.onSaveInstanceState(savedInstanceState); 649 } 650 651 @Override 652 @Nullable getCategoryFragment()653 public CategoryFragment getCategoryFragment() { 654 if (mDelegate.getFormFactor() != FormFactorChecker.FORM_FACTOR_MOBILE) { 655 return null; 656 } 657 FragmentManager fm = getSupportFragmentManager(); 658 return (CategoryFragment) fm.findFragmentById(R.id.fragment_container); 659 } 660 661 /** 662 * Populates the category tabs on DESKTOP form factor. 663 * 664 * @param selectedTabPosition The position of the tab to show as selected, or -1 if no particular 665 * tab should be selected (in which case: the tab of the category for the currently set 666 * wallpaper will be selected if enumerable; if not, the first enumerable category's tab will 667 * be selected). 668 */ populateCategoryTabs(int selectedTabPosition)669 private void populateCategoryTabs(int selectedTabPosition) { 670 final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout); 671 tabLayout.removeAllTabs(); 672 673 String currentlySetCollectionId = mDelegate.getPreferences().getHomeWallpaperCollectionId(); 674 675 Tab tabToSelect = null; 676 Tab firstEnumerableCategoryTab = null; 677 for (int i = 0; i < mDelegate.getCategoryProvider().getSize(); i++) { 678 Category category = mDelegate.getCategoryProvider().getCategory(i); 679 680 Tab tab = tabLayout.newTab(); 681 tab.setText(category.getTitle()); 682 tab.setTag(category); 683 tabLayout.addTab(tab, false /* setSelected */); 684 685 if (firstEnumerableCategoryTab == null && category.isEnumerable()) { 686 firstEnumerableCategoryTab = tab; 687 } 688 689 boolean shouldSelectTab = (i == selectedTabPosition) 690 || (selectedTabPosition == -1 691 && tabToSelect == null 692 && category.isEnumerable() 693 && currentlySetCollectionId != null 694 && currentlySetCollectionId.equals(category.getCollectionId())); 695 696 if (shouldSelectTab) { 697 tabToSelect = tab; 698 } 699 } 700 701 // If the above loop did not identify a specific tab to select, then just select the tab for 702 // the first enumerable category. 703 if (tabToSelect == null) { 704 tabToSelect = firstEnumerableCategoryTab; 705 } 706 707 // There may be no enumerable tabs (e.g., offline case), so we need to null-check again. 708 if (tabToSelect != null) { 709 tabToSelect.select(); 710 } 711 } 712 713 /** 714 * Refreshes the current wallpaper in a daily wallpaper rotation. 715 */ refreshDailyWallpaper()716 private void refreshDailyWallpaper() { 717 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore 718 // causes Espresso to hang once the dialog is shown. 719 if (!mTestingMode) { 720 int themeResId; 721 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) { 722 themeResId = R.style.ProgressDialogThemePreL; 723 } else { 724 themeResId = R.style.LightDialogTheme; 725 } 726 mRefreshWallpaperProgressDialog = new ProgressDialog(this, themeResId); 727 mRefreshWallpaperProgressDialog.setTitle(null); 728 mRefreshWallpaperProgressDialog.setMessage( 729 getResources().getString(R.string.refreshing_daily_wallpaper_dialog_message)); 730 mRefreshWallpaperProgressDialog.setIndeterminate(true); 731 mRefreshWallpaperProgressDialog.show(); 732 } 733 734 WallpaperRotationRefresher wallpaperRotationRefresher = 735 InjectorProvider.getInjector().getWallpaperRotationRefresher(); 736 wallpaperRotationRefresher.refreshWallpaper(this, new Listener() { 737 @Override 738 public void onRefreshed() { 739 if (isDestroyed()) { 740 return; 741 } 742 743 if (mRefreshWallpaperProgressDialog != null) { 744 mRefreshWallpaperProgressDialog.dismiss(); 745 } 746 747 refreshCurrentWallpapers(null /* refreshListener */); 748 } 749 750 @Override 751 public void onError() { 752 if (mRefreshWallpaperProgressDialog != null) { 753 mRefreshWallpaperProgressDialog.dismiss(); 754 } 755 756 AlertDialog errorDialog = new AlertDialog.Builder( 757 TopLevelPickerActivity.this, R.style.LightDialogTheme) 758 .setMessage(R.string.refresh_daily_wallpaper_failed_message) 759 .setPositiveButton(android.R.string.ok, null /* onClickListener */) 760 .create(); 761 errorDialog.show(); 762 } 763 }); 764 } 765 766 @Override onActivityResult(int requestCode, int resultCode, Intent data)767 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 768 super.onActivityResult(requestCode, resultCode, data); 769 770 if (requestCode == WallpaperPickerDelegate.SHOW_CATEGORY_REQUEST_CODE 771 && resultCode == Activity.RESULT_OK) { 772 if (mDelegate.getFormFactor() == FormFactorChecker.FORM_FACTOR_DESKTOP) { 773 Uri imageUri = (data == null) ? null : data.getData(); 774 if (imageUri != null) { 775 // User selected an image from the system picker, so launch the preview for that 776 // image. 777 ImageWallpaperInfo imageWallpaper = new ImageWallpaperInfo(imageUri); 778 setCustomPhotoWallpaper(imageWallpaper); 779 return; 780 } 781 } 782 } 783 if (mDelegate.handleActivityResult(requestCode, resultCode, data)) { 784 finishActivityWithResultOk(); 785 } 786 } 787 788 /** 789 * Shows the view-only preview activity for the given wallpaper. 790 */ showViewOnlyPreview(WallpaperInfo wallpaperInfo, boolean isViewAsHome)791 public void showViewOnlyPreview(WallpaperInfo wallpaperInfo, boolean isViewAsHome) { 792 mDelegate.showViewOnlyPreview(wallpaperInfo, isViewAsHome); 793 } 794 795 @Override show(String collectionId)796 public void show(String collectionId) { 797 mDelegate.show(collectionId); 798 } 799 800 @Override isNavigationTabsContained()801 public boolean isNavigationTabsContained() { 802 return false; 803 } 804 805 @Override fetchCategories()806 public void fetchCategories() { 807 mDelegate.initialize(!mDelegate.getCategoryProvider().isCategoriesFetched()); 808 } 809 810 @Override onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)811 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 812 @NonNull int[] grantResults) { 813 mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults); 814 } 815 reselectLastTab()816 private void reselectLastTab() { 817 TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout); 818 819 // In the offline case, "My photos" could be the only category. Thus we need this check -- 820 // to ensure that we don't try to select the "previously selected" category which was -1. 821 if (mLastSelectedCategoryTabIndex > -1) { 822 Tab tabToSelect = tabLayout.getTabAt( 823 mLastSelectedCategoryTabIndex); 824 if (((Category) tabToSelect.getTag()).isEnumerable()) { 825 tabToSelect.select(); 826 } 827 } 828 } 829 showCategoryDesktop(String collectionId)830 private void showCategoryDesktop(String collectionId) { 831 Category category = mDelegate.findCategoryForCollectionId(collectionId); 832 if (category == null) { 833 return; 834 } 835 836 if (category.isEnumerable()) { 837 // Replace contained IndividualPickerFragment with a new instance for the given category. 838 final FragmentManager fm = getSupportFragmentManager(); 839 Fragment fragment = fm.findFragmentById(R.id.fragment_container); 840 if (fragment != null) { 841 fm.beginTransaction() 842 .remove(fragment) 843 .commit(); 844 } 845 Injector injector = InjectorProvider.getInjector(); 846 IndividualPickerFragment newFragment = injector.getIndividualPickerFragment( 847 collectionId); 848 fm.beginTransaction() 849 .add(R.id.fragment_container, newFragment) 850 .commit(); 851 newFragment.setCurrentWallpaperBottomSheetPresenter(this); 852 newFragment.setWallpapersUiContainer(this); 853 } else { 854 category.show(this, mDelegate.getPickerIntentFactory(), 855 WallpaperPickerDelegate.SHOW_CATEGORY_REQUEST_CODE); 856 857 // Need to select the tab here in case we are coming back from a "My photos" in which case 858 // the tab would have been set to "My photos" while viewing a regular image category. 859 reselectLastTab(); 860 } 861 } 862 finishActivityWithResultOk()863 private void finishActivityWithResultOk() { 864 overridePendingTransition(R.anim.fade_in, R.anim.fade_out); 865 setResult(Activity.RESULT_OK); 866 finish(); 867 } 868 869 @Override setCurrentWallpapersExpanded(boolean expanded)870 public void setCurrentWallpapersExpanded(boolean expanded) { 871 final BottomSheetBehavior<LinearLayout> bottomSheetBehavior = 872 BottomSheetBehavior.from(mBottomSheet); 873 bottomSheetBehavior.setState( 874 expanded ? BottomSheetBehavior.STATE_EXPANDED 875 : BottomSheetBehavior.STATE_COLLAPSED); 876 } 877 878 @Override doneFetchingCategories()879 public void doneFetchingCategories() { 880 populateCategoryTabs(mLastSelectedCategoryTabIndex); 881 } 882 883 @Override onWallpapersReady()884 public void onWallpapersReady() { 885 setDesktopLoading(false); 886 setCurrentWallpapersExpanded(true); 887 } 888 889 @Override getMyPhotosStarter()890 public MyPhotosStarter getMyPhotosStarter() { 891 return this; 892 } 893 894 @Override onClickTryAgain(@estination int unused)895 public void onClickTryAgain(@Destination int unused) { 896 // Retry the set wallpaper operation with the default center-crop setting. 897 if (mPendingSetWallpaperInfo != null) { 898 setCustomPhotoWallpaper(mPendingSetWallpaperInfo); 899 } 900 } 901 902 /** 903 * Sets the provides wallpaper to the device with center-cropped and scaled to fit the device's 904 * default display. 905 */ setCustomPhotoWallpaper(final WallpaperInfo wallpaper)906 private void setCustomPhotoWallpaper(final WallpaperInfo wallpaper) { 907 // Save this WallpaperInfo so we can retry this operation later if it fails. 908 mPendingSetWallpaperInfo = wallpaper; 909 910 showSettingWallpaperProgressDialog(); 911 912 mWallpaperPersister.setIndividualWallpaperWithPosition(this, wallpaper, 913 WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP, new SetWallpaperCallback() { 914 @Override 915 public void onSuccess(WallpaperInfo wallpaperInfo) { 916 dismissSettingWallpaperProgressDialog(); 917 refreshCurrentWallpapers(null /* refreshListener */); 918 919 mDelegate.getPreferences().setPendingWallpaperSetStatus( 920 WallpaperPreferences.WALLPAPER_SET_NOT_PENDING); 921 mUserEventLogger.logWallpaperSet( 922 wallpaper.getCollectionId(getApplicationContext()), 923 wallpaper.getWallpaperId()); 924 mUserEventLogger.logWallpaperSetResult(UserEventLogger.WALLPAPER_SET_RESULT_SUCCESS); 925 926 // The user may have closed the activity before the set wallpaper operation completed. 927 if (isDestroyed()) { 928 return; 929 } 930 931 // Show the wallpaper crop option selector and bind click event handlers. 932 mWallpaperPositionOptions.setVisibility(View.VISIBLE); 933 934 mWasCustomPhotoWallpaperSet = true; 935 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP; 936 937 initializeWallpaperPositionOptionClickHandlers(wallpaper); 938 } 939 940 @Override 941 public void onError(Throwable throwable) { 942 dismissSettingWallpaperProgressDialog(); 943 showSetWallpaperErrorDialog(); 944 945 mDelegate.getPreferences().setPendingWallpaperSetStatus( 946 WallpaperPreferences.WALLPAPER_SET_NOT_PENDING); 947 mUserEventLogger.logWallpaperSetResult( 948 UserEventLogger.WALLPAPER_SET_RESULT_FAILURE); 949 @WallpaperSetFailureReason int failureReason = ThrowableAnalyzer.isOOM(throwable) 950 ? UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OOM 951 : UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OTHER; 952 mUserEventLogger.logWallpaperSetFailureReason(failureReason); 953 Log.e(TAG, "Unable to set wallpaper from 'my photos'."); 954 } 955 }); 956 } 957 958 /** 959 * Initializes the wallpaper position button click handlers to change the way the provided 960 * wallpaper is set to the device. 961 */ initializeWallpaperPositionOptionClickHandlers(final WallpaperInfo wallpaperInfo)962 private void initializeWallpaperPositionOptionClickHandlers(final WallpaperInfo wallpaperInfo) { 963 Button centerCropOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_center_crop); 964 Button stretchOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_stretched); 965 Button centerOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_center); 966 967 // The "center crop" wallpaper position button is selected by default. 968 setCenterCropWallpaperPositionButtonSelected(centerCropOptionBtn, true /* isSelected */); 969 centerCropOptionBtn.setOnClickListener(new OnClickListener() { 970 @Override 971 public void onClick(View view) { 972 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this, 973 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP, 974 new SetWallpaperCallback() { 975 @Override 976 public void onSuccess(WallpaperInfo wallpaperInfo) { 977 // The user may have closed the activity before the set wallpaper operation 978 // completed. 979 if (isDestroyed()) { 980 return; 981 } 982 983 refreshCurrentWallpapers(null /* refreshListener */); 984 985 setCenterCropWallpaperPositionButtonSelected( 986 centerCropOptionBtn, true /* isSelected */); 987 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */); 988 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */); 989 990 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP; 991 } 992 993 @Override 994 public void onError(@Nullable Throwable throwable) { 995 // no-op 996 } 997 }); 998 } 999 }); 1000 1001 // "Stretch" is not selected by default. 1002 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */); 1003 stretchOptionBtn.setOnClickListener(new OnClickListener() { 1004 @Override 1005 public void onClick(View view) { 1006 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this, 1007 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_STRETCH, 1008 new SetWallpaperCallback() { 1009 @Override 1010 public void onSuccess(WallpaperInfo wallpaperInfo) { 1011 // The user may have closed the activity before the set wallpaper operation 1012 // completed. 1013 if (isDestroyed()) { 1014 return; 1015 } 1016 1017 refreshCurrentWallpapers(null /* refreshListener */); 1018 1019 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, true /* isSelected */); 1020 setCenterCropWallpaperPositionButtonSelected( 1021 centerCropOptionBtn, false /* isSelected */); 1022 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */); 1023 1024 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_STRETCH; 1025 } 1026 1027 @Override 1028 public void onError(@Nullable Throwable throwable) { 1029 // no-op 1030 } 1031 }); 1032 } 1033 }); 1034 1035 // "Center" is not selected by default. 1036 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */); 1037 centerOptionBtn.setOnClickListener(new OnClickListener() { 1038 @Override 1039 public void onClick(View view) { 1040 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this, 1041 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_CENTER, 1042 new SetWallpaperCallback() { 1043 @Override 1044 public void onSuccess(WallpaperInfo wallpaperInfo) { 1045 // The user may have closed the activity before the set wallpaper operation 1046 // completed. 1047 if (isDestroyed()) { 1048 return; 1049 } 1050 1051 refreshCurrentWallpapers(null /* refreshListener */); 1052 1053 setCenterWallpaperPositionButtonSelected(centerOptionBtn, true /* isSelected */); 1054 setCenterCropWallpaperPositionButtonSelected( 1055 centerCropOptionBtn, false /* isSelected */); 1056 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */); 1057 1058 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER; 1059 } 1060 1061 @Override 1062 public void onError(@Nullable Throwable throwable) { 1063 // no-op 1064 } 1065 }); 1066 } 1067 }); 1068 } 1069 setCenterWallpaperPositionButtonSelected(Button button, boolean isSelected)1070 private void setCenterWallpaperPositionButtonSelected(Button button, boolean isSelected) { 1071 int drawableId = isSelected ? R.drawable.center_blue : R.drawable.center_grey; 1072 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId)); 1073 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected))); 1074 } 1075 setCenterCropWallpaperPositionButtonSelected(Button button, boolean isSelected)1076 private void setCenterCropWallpaperPositionButtonSelected(Button button, boolean isSelected) { 1077 int drawableId = isSelected ? R.drawable.center_crop_blue : R.drawable.center_crop_grey; 1078 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId)); 1079 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected))); 1080 } 1081 setStretchWallpaperPositionButtonSelected(Button button, boolean isSelected)1082 private void setStretchWallpaperPositionButtonSelected(Button button, boolean isSelected) { 1083 int drawableId = isSelected ? R.drawable.stretch_blue : R.drawable.stretch_grey; 1084 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId)); 1085 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected))); 1086 } 1087 showSettingWallpaperProgressDialog()1088 private void showSettingWallpaperProgressDialog() { 1089 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which 1090 // therefore causes Espresso to hang once the dialog is shown. 1091 if (!mTestingMode) { 1092 int themeResId; 1093 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) { 1094 themeResId = R.style.ProgressDialogThemePreL; 1095 } else { 1096 themeResId = R.style.LightDialogTheme; 1097 } 1098 mSetWallpaperProgressDialog = new ProgressDialog(this, themeResId); 1099 mSetWallpaperProgressDialog.setTitle(null); 1100 mSetWallpaperProgressDialog.setMessage( 1101 getResources().getString(R.string.set_wallpaper_progress_message)); 1102 mSetWallpaperProgressDialog.setIndeterminate(true); 1103 mSetWallpaperProgressDialog.show(); 1104 } 1105 } 1106 dismissSettingWallpaperProgressDialog()1107 private void dismissSettingWallpaperProgressDialog() { 1108 if (mSetWallpaperProgressDialog != null) { 1109 mSetWallpaperProgressDialog.dismiss(); 1110 } 1111 } 1112 showSetWallpaperErrorDialog()1113 private void showSetWallpaperErrorDialog() { 1114 SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance( 1115 R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH); 1116 1117 if (isSafeToCommitFragmentTransaction()) { 1118 dialogFragment.show(getSupportFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT); 1119 } else { 1120 mStagedSetWallpaperErrorDialogFragment = dialogFragment; 1121 } 1122 } 1123 1124 @Override getBottomActionBar()1125 public BottomActionBar getBottomActionBar() { 1126 return findViewById(R.id.bottom_actionbar); 1127 } 1128 1129 private interface AssetReceiver { onAssetReceived(Asset asset)1130 void onAssetReceived(Asset asset); 1131 } 1132 1133 /** 1134 * An AsyncTask for asynchronously fetching the thumbnail asset for a given WallpaperInfo. 1135 * Used to work around expensive method call to WallpaperManager#getWallpaperFile made from the 1136 * CurrentWallpaperInfoVN getAsset() method. 1137 */ 1138 private static class FetchThumbAssetTask extends AsyncTask<Void, Void, Asset> { 1139 private Context mAppContext; 1140 private WallpaperInfo mWallpaperInfo; 1141 private AssetReceiver mReceiver; 1142 FetchThumbAssetTask(Context appContext, WallpaperInfo wallpaperInfo, AssetReceiver receiver)1143 public FetchThumbAssetTask(Context appContext, WallpaperInfo wallpaperInfo, 1144 AssetReceiver receiver) { 1145 mAppContext = appContext; 1146 mWallpaperInfo = wallpaperInfo; 1147 mReceiver = receiver; 1148 } 1149 1150 @Override doInBackground(Void... params)1151 protected Asset doInBackground(Void... params) { 1152 return mWallpaperInfo.getThumbAsset(mAppContext); 1153 } 1154 1155 @Override onPostExecute(Asset thumbAsset)1156 protected void onPostExecute(Asset thumbAsset) { 1157 mReceiver.onAssetReceived(thumbAsset); 1158 } 1159 } 1160 } 1161