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