Initial AOSP WallpaperPicker2 commit.
Change-Id: If8770266dd3ff0d7dc3ee97820e815e39312a7ff
diff --git a/src/com/android/wallpaper/picker/TopLevelPickerActivity.java b/src/com/android/wallpaper/picker/TopLevelPickerActivity.java
new file mode 100755
index 0000000..4e536a9
--- /dev/null
+++ b/src/com/android/wallpaper/picker/TopLevelPickerActivity.java
@@ -0,0 +1,1241 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wallpaper.picker;
+
+import android.Manifest.permission;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.design.widget.BottomSheetBehavior;
+import android.support.design.widget.BottomSheetBehavior.BottomSheetCallback;
+import android.support.design.widget.TabLayout;
+import android.support.design.widget.TabLayout.OnTabSelectedListener;
+import android.support.design.widget.TabLayout.Tab;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.widget.Toolbar;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.wallpaper.R;
+import com.android.wallpaper.asset.Asset;
+import com.android.wallpaper.compat.ButtonDrawableSetterCompat;
+import com.android.wallpaper.compat.WallpaperManagerCompat;
+import com.android.wallpaper.config.Flags;
+import com.android.wallpaper.model.Category;
+import com.android.wallpaper.model.CategoryProvider;
+import com.android.wallpaper.model.CategoryReceiver;
+import com.android.wallpaper.model.ImageWallpaperInfo;
+import com.android.wallpaper.model.InlinePreviewIntentFactory;
+import com.android.wallpaper.model.WallpaperInfo;
+import com.android.wallpaper.module.CurrentWallpaperInfoFactory;
+import com.android.wallpaper.module.CurrentWallpaperInfoFactory.WallpaperInfoCallback;
+import com.android.wallpaper.module.DailyLoggingAlarmScheduler;
+import com.android.wallpaper.module.ExploreIntentChecker;
+import com.android.wallpaper.module.FormFactorChecker;
+import com.android.wallpaper.module.FormFactorChecker.FormFactor;
+import com.android.wallpaper.module.Injector;
+import com.android.wallpaper.module.InjectorProvider;
+import com.android.wallpaper.module.NetworkStatusNotifier;
+import com.android.wallpaper.module.NetworkStatusNotifier.NetworkStatus;
+import com.android.wallpaper.module.UserEventLogger;
+import com.android.wallpaper.module.UserEventLogger.WallpaperSetFailureReason;
+import com.android.wallpaper.module.WallpaperPersister;
+import com.android.wallpaper.module.WallpaperPersister.Destination;
+import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback;
+import com.android.wallpaper.module.WallpaperPersister.WallpaperPosition;
+import com.android.wallpaper.module.WallpaperPreferences;
+import com.android.wallpaper.module.WallpaperPreferences.PresentationMode;
+import com.android.wallpaper.module.WallpaperRotationRefresher;
+import com.android.wallpaper.module.WallpaperRotationRefresher.Listener;
+import com.android.wallpaper.picker.PreviewActivity.PreviewActivityIntentFactory;
+import com.android.wallpaper.picker.ViewOnlyPreviewActivity.ViewOnlyPreviewActivityIntentFactory;
+import com.android.wallpaper.picker.WallpaperDisabledFragment.WallpaperSupportLevel;
+import com.android.wallpaper.picker.individual.IndividualPickerActivity.IndividualPickerActivityIntentFactory;
+import com.android.wallpaper.picker.individual.IndividualPickerFragment;
+import com.android.wallpaper.util.ScreenSizeCalculator;
+import com.android.wallpaper.util.ThrowableAnalyzer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Activity allowing users to select a category of wallpapers to choose from.
+ */
+public class TopLevelPickerActivity extends BaseActivity implements WallpapersUiContainer,
+ CurrentWallpaperBottomSheetPresenter, SetWallpaperErrorDialogFragment.Listener,
+ MyPhotosLauncher {
+ private static final int SHOW_CATEGORY_REQUEST_CODE = 0;
+ private static final int PREVIEW_WALLPAPER_REQUEST_CODE = 1;
+ private static final int VIEW_ONLY_PREVIEW_WALLPAPER_REQUEST_CODE = 2;
+ private static final int READ_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE = 3;
+
+ private static final String TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT =
+ "toplevel_set_wallpaper_error_dialog";
+
+ private static final String TAG = "TopLevelPicker";
+ private static final String KEY_SELECTED_CATEGORY_TAB = "selected_category_tab";
+
+ private IndividualPickerActivityIntentFactory mPickerIntentFactory;
+ private InlinePreviewIntentFactory mPreviewIntentFactory;
+ private InlinePreviewIntentFactory mViewOnlyPreviewIntentFactory;
+ private ArrayList<Category> mCategories;
+ private int mLastSelectedCategoryTabIndex;
+ @FormFactor
+ private int mFormFactor;
+ private WallpaperPreferences mPreferences;
+ private UserEventLogger mUserEventLogger;
+ private NetworkStatusNotifier mNetworkStatusNotifier;
+ private NetworkStatusNotifier.Listener mNetworkStatusListener;
+ private WallpaperPersister mWallpaperPersister;
+ private boolean mWasCustomPhotoWallpaperSet;
+ @WallpaperPosition
+ private int mCustomPhotoWallpaperPosition;
+
+ /**
+ * Progress dialogs for "refresh daily wallpaper" and "set wallpaper" operations.
+ */
+ private ProgressDialog mRefreshWallpaperProgressDialog;
+ private ProgressDialog mSetWallpaperProgressDialog;
+
+ /**
+ * Designates a test mode of operation -- in which certain UI features are disabled to allow for
+ * UI tests to run correctly.
+ */
+ private boolean mTestingMode;
+
+ /**
+ * UI for the "currently set wallpaper" BottomSheet.
+ */
+ private LinearLayout mBottomSheet;
+ private ImageView mCurrentWallpaperImage;
+ private TextView mCurrentWallpaperPresentationMode;
+ private TextView mCurrentWallpaperTitle;
+ private TextView mCurrentWallpaperSubtitle;
+ private Button mCurrentWallpaperExploreButton;
+ private Button mCurrentWallpaperSkipWallpaperButton;
+ private FrameLayout mFragmentContainer;
+ private FrameLayout mLoadingIndicatorContainer;
+ private LinearLayout mWallpaperPositionOptions;
+
+ private List<PermissionChangedListener> mPermissionChangedListeners;
+
+ /**
+ * Staged error dialog fragments that were unable to be shown when the activity didn't allow
+ * committing fragment transactions.
+ */
+ private SetWallpaperErrorDialogFragment mStagedSetWallpaperErrorDialogFragment;
+
+ /**
+ * A wallpaper pending set to the device--we retain a reference to this in order to facilitate
+ * retry or re-crop operations.
+ */
+ private WallpaperInfo mPendingSetWallpaperInfo;
+
+ private static int getTextColorIdForWallpaperPositionButton(boolean isSelected) {
+ return isSelected ? R.color.accent_color : R.color.material_grey500;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mPickerIntentFactory = new IndividualPickerActivityIntentFactory();
+ mPreviewIntentFactory = new PreviewActivityIntentFactory();
+ mViewOnlyPreviewIntentFactory = new ViewOnlyPreviewActivityIntentFactory();
+ mCategories = new ArrayList<>();
+ mLastSelectedCategoryTabIndex = -1;
+
+ Injector injector = InjectorProvider.getInjector();
+ mPreferences = injector.getPreferences(this);
+ mUserEventLogger = injector.getUserEventLogger(this);
+ mNetworkStatusNotifier = injector.getNetworkStatusNotifier(this);
+ final FormFactorChecker formFactorChecker = injector.getFormFactorChecker(this);
+ mFormFactor = formFactorChecker.getFormFactor();
+ mWallpaperPersister = injector.getWallpaperPersister(this);
+ mWasCustomPhotoWallpaperSet = false;
+
+ mPermissionChangedListeners = new ArrayList<>();
+
+ @WallpaperSupportLevel int wallpaperSupportLevel = getWallpaperSupportLevel();
+ if (wallpaperSupportLevel != WallpaperDisabledFragment.SUPPORTED_CAN_SET) {
+ setContentView(R.layout.activity_single_fragment);
+
+ FragmentManager fm = getSupportFragmentManager();
+ WallpaperDisabledFragment wallpaperDisabledFragment =
+ WallpaperDisabledFragment.newInstance(wallpaperSupportLevel);
+ fm.beginTransaction()
+ .add(R.id.fragment_container, wallpaperDisabledFragment)
+ .commit();
+ return;
+ }
+
+ if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
+ initializeMobile();
+ } else { // DESKTOP
+ initializeDesktop(savedInstanceState);
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one
+ // that was unable to be shown earlier when this fragment's hosting activity didn't allow
+ // committing fragment transactions.
+ if (mStagedSetWallpaperErrorDialogFragment != null) {
+ mStagedSetWallpaperErrorDialogFragment.show(
+ getSupportFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
+ mStagedSetWallpaperErrorDialogFragment = null;
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ if (mNetworkStatusListener != null) {
+ mNetworkStatusNotifier.unregisterListener(mNetworkStatusListener);
+ }
+
+ if (mRefreshWallpaperProgressDialog != null) {
+ mRefreshWallpaperProgressDialog.dismiss();
+ }
+ if (mSetWallpaperProgressDialog != null) {
+ mSetWallpaperProgressDialog.dismiss();
+ }
+
+ if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP && mWasCustomPhotoWallpaperSet) {
+ mUserEventLogger.logWallpaperPosition(mCustomPhotoWallpaperPosition);
+ }
+ }
+
+ @Override
+ public void requestCustomPhotoPicker(PermissionChangedListener listener) {
+ if (!isReadExternalStoragePermissionGranted()) {
+ PermissionChangedListener wrappedListener = new PermissionChangedListener() {
+ @Override
+ public void onPermissionsGranted() {
+ listener.onPermissionsGranted();
+ showCustomPhotoPicker();
+ }
+
+ @Override
+ public void onPermissionsDenied(boolean dontAskAgain) {
+ listener.onPermissionsDenied(dontAskAgain);
+ }
+ };
+ requestExternalStoragePermission(wrappedListener);
+
+ return;
+ }
+
+ showCustomPhotoPicker();
+ }
+
+ void requestExternalStoragePermission(PermissionChangedListener listener) {
+ mPermissionChangedListeners.add(listener);
+ requestPermissions(
+ new String[]{permission.READ_EXTERNAL_STORAGE},
+ READ_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
+ }
+
+ /**
+ * Returns whether READ_EXTERNAL_STORAGE has been granted for the application.
+ */
+ boolean isReadExternalStoragePermissionGranted() {
+ return getPackageManager().checkPermission(permission.READ_EXTERNAL_STORAGE,
+ getPackageName()) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private void showCustomPhotoPicker() {
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.setType("image/*");
+ startActivityForResult(intent, SHOW_CATEGORY_REQUEST_CODE);
+ }
+
+ private void initializeMobile() {
+ setContentView(R.layout.activity_single_fragment_with_toolbar);
+
+ // Set toolbar as the action bar.
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ FragmentManager fm = getSupportFragmentManager();
+ Fragment fragment = fm.findFragmentById(R.id.fragment_container);
+
+ boolean forceCategoryRefresh = false;
+ if (fragment == null) {
+ // App launch specific logic: log the "app launched" event and set up daily logging.
+ mUserEventLogger.logAppLaunched();
+ DailyLoggingAlarmScheduler.setAlarm(getApplicationContext());
+
+ CategoryPickerFragment newFragment = new CategoryPickerFragment();
+ fm.beginTransaction()
+ .add(R.id.fragment_container, newFragment)
+ .commit();
+
+ forceCategoryRefresh = true;
+ }
+
+ populateCategories(-1, forceCategoryRefresh);
+ }
+
+ private void initializeDesktop(Bundle savedInstanceState) {
+ setContentView(R.layout.activity_top_level_desktop);
+
+ mBottomSheet = (LinearLayout) findViewById(R.id.bottom_sheet);
+ mCurrentWallpaperImage = (ImageView) mBottomSheet.findViewById(R.id.current_wallpaper_image);
+ mCurrentWallpaperImage.getLayoutParams().width = getSingleWallpaperImageWidthPx();
+
+ mCurrentWallpaperPresentationMode =
+ (TextView) mBottomSheet.findViewById(R.id.current_wallpaper_presentation_mode);
+ mCurrentWallpaperTitle = (TextView) findViewById(R.id.current_wallpaper_title);
+ mCurrentWallpaperSubtitle = (TextView) findViewById(R.id.current_wallpaper_subtitle);
+ mCurrentWallpaperExploreButton = (Button) findViewById(
+ R.id.current_wallpaper_explore_button);
+ mCurrentWallpaperSkipWallpaperButton = (Button) findViewById(
+ R.id.current_wallpaper_skip_wallpaper_button);
+ mFragmentContainer = (FrameLayout) findViewById(R.id.fragment_container);
+ mLoadingIndicatorContainer = (FrameLayout) findViewById(R.id.loading_indicator_container);
+ mWallpaperPositionOptions = (LinearLayout) findViewById(
+ R.id.desktop_wallpaper_position_options);
+
+ final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
+ tabLayout.addOnTabSelectedListener(new OnTabSelectedListener() {
+ @Override
+ public void onTabSelected(Tab tab) {
+ Category category = (Category) tab.getTag();
+ show(category.getCollectionId());
+ mLastSelectedCategoryTabIndex = tabLayout.getSelectedTabPosition();
+ }
+
+ @Override
+ public void onTabUnselected(Tab tab) {
+ }
+
+ @Override
+ public void onTabReselected(Tab tab) {
+ Category category = (Category) tab.getTag();
+ // If offline, "My photos" may be the only visible category. In this case we want to allow
+ // re-selection so user can still select a photo as wallpaper while offline.
+ if (!category.isEnumerable()) {
+ onTabSelected(tab);
+ }
+ }
+ });
+
+ FragmentManager fm = getSupportFragmentManager();
+ Fragment fragment = fm.findFragmentById(R.id.fragment_container);
+
+ if (fragment == null) {
+ // App launch specific logic: log the "app launched" event and set up daily logging.
+ mUserEventLogger.logAppLaunched();
+ DailyLoggingAlarmScheduler.setAlarm(getApplicationContext());
+ }
+
+ mNetworkStatusListener = new NetworkStatusNotifier.Listener() {
+ @Override
+ public void onNetworkChanged(@NetworkStatus int networkStatus) {
+ initializeDesktopBasedOnNetwork(networkStatus, savedInstanceState);
+ }
+ };
+ // Upon registering a listener, the onNetworkChanged method is immediately called with the
+ // initial network status.
+ mNetworkStatusNotifier.registerListener(mNetworkStatusListener);
+ }
+
+ private void initializeDesktopBasedOnNetwork(@NetworkStatus int networkStatus,
+ Bundle savedInstanceState) {
+ if (networkStatus == NetworkStatusNotifier.NETWORK_CONNECTED) {
+ initializeDesktopOnline(savedInstanceState);
+ } else {
+ initializeDesktopOffline();
+ }
+ }
+
+ private void initializeDesktopOnline(Bundle savedInstanceState) {
+ FragmentManager fm = getSupportFragmentManager();
+ Fragment fragment = fm.findFragmentById(R.id.fragment_container);
+
+ // Require a category refresh if this is the first load of the app or if the app is now
+ // returning online after having been offline.
+ boolean forceCategoryRefresh = fragment == null || fragment instanceof OfflineDesktopFragment;
+
+ if (fragment != null) {
+ fm.beginTransaction()
+ .remove(fragment)
+ .commit();
+ }
+
+ int selectedTabPosition = savedInstanceState != null
+ ? savedInstanceState.getInt(KEY_SELECTED_CATEGORY_TAB) : -1;
+ populateCategories(selectedTabPosition, forceCategoryRefresh);
+
+ setDesktopLoading(true);
+ setUpBottomSheet();
+ refreshCurrentWallpapers(null /* refreshListener */);
+ }
+
+ private void initializeDesktopOffline() {
+ FragmentManager fm = getSupportFragmentManager();
+ Fragment fragment = fm.findFragmentById(R.id.fragment_container);
+
+ if (fragment != null) {
+ fm.beginTransaction()
+ .remove(fragment)
+ .commit();
+ }
+ OfflineDesktopFragment newFragment = new OfflineDesktopFragment();
+ fm.beginTransaction()
+ .add(R.id.fragment_container, newFragment)
+ .commit();
+
+ // Reset the last selected category tab index to ensure the app doesn't try to reselect a tab
+ // for a category not yet repopulated.
+ mLastSelectedCategoryTabIndex = -1;
+
+ populateCategories(-1 /* selectedTabPosition */, true /* forceCategoryRefresh */);
+
+ setDesktopLoading(false);
+ setCurrentWallpapersExpanded(false);
+ }
+
+ /**
+ * Sets the status of the loading indicator overlay in desktop mode.
+ *
+ * @param loading Whether an indeterminate loading indicator is displayed in place of the main
+ * fragment.
+ */
+ private void setDesktopLoading(boolean loading) {
+ if (loading) {
+ mLoadingIndicatorContainer.setVisibility(View.VISIBLE);
+ mFragmentContainer.setVisibility(View.GONE);
+ } else {
+ mLoadingIndicatorContainer.setVisibility(View.GONE);
+ mFragmentContainer.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Returns the width (in physical px) to use for the "currently set wallpaper" thumbnail.
+ */
+ private int getSingleWallpaperImageWidthPx() {
+ Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(
+ getWindowManager().getDefaultDisplay());
+
+ int height = getResources().getDimensionPixelSize(
+ R.dimen.current_wallpaper_bottom_sheet_thumb_height);
+ return height * screenSize.x / screenSize.y;
+ }
+
+ /**
+ * Enables and populates the "Currently set" wallpaper BottomSheet.
+ */
+ private void setUpBottomSheet() {
+ mBottomSheet.setVisibility(View.VISIBLE);
+
+ // Add "compass" icon to the Explore button
+ Drawable exploreButtonDrawable = getResources().getDrawable(
+ R.drawable.material_ic_explore_black_18);
+
+ // This Drawable's state is shared across the app, so make a copy of it before applying a
+ // color tint as not to affect other clients elsewhere in the app.
+ exploreButtonDrawable = exploreButtonDrawable.getConstantState().newDrawable().mutate();
+ // Color the "compass" icon with the accent color.
+ exploreButtonDrawable.setColorFilter(
+ getResources().getColor(R.color.accent_color), Mode.SRC_IN);
+ ButtonDrawableSetterCompat.setDrawableToButtonStart(
+ mCurrentWallpaperExploreButton, exploreButtonDrawable);
+
+ if (Flags.skipDailyWallpaperButtonEnabled) {
+ // Add "next" icon to the Next Wallpaper button
+ Drawable nextWallpaperButtonDrawable = getResources().getDrawable(
+ R.drawable.material_ic_refresh_black_18);
+
+ // This Drawable's state is shared across the app, so make a copy of it before applying a
+ // color tint as not to affect other clients elsewhere in the app.
+ nextWallpaperButtonDrawable =
+ nextWallpaperButtonDrawable.getConstantState().newDrawable().mutate();
+ // Color the "compass" icon with the accent color.
+ nextWallpaperButtonDrawable.setColorFilter(
+ getResources().getColor(R.color.accent_color), Mode.SRC_IN);
+ ButtonDrawableSetterCompat.setDrawableToButtonStart(
+ mCurrentWallpaperSkipWallpaperButton, nextWallpaperButtonDrawable);
+ }
+
+ final BottomSheetBehavior<LinearLayout> bottomSheetBehavior =
+ BottomSheetBehavior.from(mBottomSheet);
+ bottomSheetBehavior.setBottomSheetCallback(new BottomSheetCallback() {
+ @Override
+ public void onStateChanged(@NonNull View view, int i) {
+ }
+
+ @Override
+ public void onSlide(@NonNull View view, float slideOffset) {
+ float alpha;
+ if (slideOffset >= 0) {
+ alpha = slideOffset;
+ } else {
+ alpha = 1f - slideOffset;
+ }
+ LinearLayout bottomSheetContents = (LinearLayout) findViewById(R.id.bottom_sheet_contents);
+ bottomSheetContents.setAlpha(alpha);
+ }
+ });
+ }
+
+ /**
+ * Enables a test mode of operation -- in which certain UI features are disabled to allow for
+ * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog
+ * constantly keeps the UI thread alive and blocks a test forever.
+ */
+ void setTestingMode(boolean testingMode) {
+ mTestingMode = testingMode;
+ }
+
+ /**
+ * Obtains the {@link WallpaperInfo} object(s) representing the wallpaper(s) currently set to the
+ * device from the {@link CurrentWallpaperInfoFactory} and displays them in the BottomSheet.
+ */
+ @Override
+ public void refreshCurrentWallpapers(@Nullable RefreshListener refreshListener) {
+ final Injector injector = InjectorProvider.getInjector();
+ final Context appContext = getApplicationContext();
+
+ CurrentWallpaperInfoFactory factory = injector.getCurrentWallpaperFactory(this);
+ factory.createCurrentWallpaperInfos(new WallpaperInfoCallback() {
+ @Override
+ public void onWallpaperInfoCreated(
+ final WallpaperInfo homeWallpaper,
+ @Nullable final WallpaperInfo lockWallpaper,
+ @PresentationMode final int presentationMode) {
+
+ if (isDestroyed()) {
+ return;
+ }
+
+ // Fetch the home wallpaper's thumbnail asset asynchronously to work around expensive
+ // method call to WallpaperManager#getWallpaperFile made from the CurrentWallpaperInfoVN
+ // getAsset() method.
+ AssetReceiver assetReceiver = (Asset thumbAsset) -> {
+ if (isDestroyed()) {
+ return;
+ }
+
+ homeWallpaper.getThumbAsset(appContext).loadDrawableWithTransition(
+ TopLevelPickerActivity.this,
+ mCurrentWallpaperImage,
+ 200 /* transitionDurationMillis */,
+ () -> {
+ if (refreshListener != null) {
+ refreshListener.onCurrentWallpaperRefreshed();
+ }
+ },
+ Color.TRANSPARENT);
+ };
+ new FetchThumbAssetTask(appContext, homeWallpaper, assetReceiver).executeOnExecutor(
+ AsyncTask.THREAD_POOL_EXECUTOR);
+
+ mCurrentWallpaperPresentationMode.setText(
+ AttributionFormatter.getHumanReadableWallpaperPresentationMode(
+ TopLevelPickerActivity.this, presentationMode));
+
+ List<String> attributions = homeWallpaper.getAttributions(appContext);
+ if (attributions.size() > 0 && attributions.get(0) != null) {
+ mCurrentWallpaperTitle.setText(attributions.get(0));
+ }
+
+ mCurrentWallpaperSubtitle.setText(
+ AttributionFormatter.formatWallpaperSubtitle(appContext, homeWallpaper));
+
+ final String actionUrl = homeWallpaper.getActionUrl(appContext);
+ if (actionUrl != null && !actionUrl.isEmpty()) {
+ Uri exploreUri = Uri.parse(actionUrl);
+
+ ExploreIntentChecker intentChecker = injector.getExploreIntentChecker(appContext);
+ intentChecker.fetchValidActionViewIntent(exploreUri, (@Nullable Intent exploreIntent) -> {
+ if (exploreIntent != null && !isDestroyed()) {
+ mCurrentWallpaperExploreButton.setVisibility(View.VISIBLE);
+ mCurrentWallpaperExploreButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mUserEventLogger.logExploreClicked(homeWallpaper.getCollectionId(appContext));
+ startActivity(exploreIntent);
+ }
+ });
+ }
+ });
+ } else {
+ mCurrentWallpaperExploreButton.setVisibility(View.GONE);
+ }
+
+ // Hide the wallpaper position options UI if the current home wallpaper is not from
+ // "my photos".
+ String homeCollectionId = homeWallpaper.getCollectionId(TopLevelPickerActivity.this);
+ if (mWallpaperPositionOptions != null
+ && homeCollectionId != null // May be null if app is being used for the first time.
+ && !homeCollectionId.equals(getString(R.string.image_wallpaper_collection_id))) {
+ mWallpaperPositionOptions.setVisibility(View.GONE);
+ }
+
+ boolean showSkipWallpaperButton = Flags.skipDailyWallpaperButtonEnabled
+ && presentationMode == WallpaperPreferences.PRESENTATION_MODE_ROTATING;
+ if (showSkipWallpaperButton) {
+ mCurrentWallpaperSkipWallpaperButton.setVisibility(View.VISIBLE);
+ mCurrentWallpaperSkipWallpaperButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ refreshDailyWallpaper();
+ }
+ });
+ } else {
+ mCurrentWallpaperSkipWallpaperButton.setVisibility(View.GONE);
+ }
+
+ if (refreshListener != null) {
+ refreshListener.onCurrentWallpaperRefreshed();
+ }
+ }
+ }, true /* forceRefresh */);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ FormFactorChecker formFactorChecker = InjectorProvider.getInjector().getFormFactorChecker(this);
+ if (formFactorChecker.getFormFactor() == FormFactorChecker.FORM_FACTOR_DESKTOP) {
+ TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
+
+ // tabLayout is only present when the main IndividualPickerFragment is present (as opposed to
+ // the WallpaperDisabledFragment), so need this null check.
+ if (tabLayout != null) {
+ savedInstanceState.putInt(KEY_SELECTED_CATEGORY_TAB, tabLayout.getSelectedTabPosition());
+ }
+ }
+
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ /**
+ * Populates the categories appropriately depending on the device form factor.
+ *
+ * @param selectedTabPosition The position of the tab to show as selected, or -1 if no tab
+ * should be selected (i.e. because there is no tab layout present, as on MOBILE form factor).
+ * @param forceRefresh Whether to force a refresh of categories from the CategoryProvider. True if
+ * on first launch.
+ */
+ private void populateCategories(final int selectedTabPosition, boolean forceRefresh) {
+ mCategories.clear();
+
+ Injector injector = InjectorProvider.getInjector();
+ CategoryProvider categoryProvider = injector.getCategoryProvider(this);
+ categoryProvider.fetchCategories(new CategoryReceiver() {
+ @Override
+ public void onCategoryReceived(Category category) {
+ int priority = category.getPriority();
+
+ int index = 0;
+ while (index < mCategories.size() && priority >= mCategories.get(index).getPriority()) {
+ index++;
+ }
+ mCategories.add(index, category);
+
+ if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
+ final FragmentManager fm = getSupportFragmentManager();
+ CategoryPickerFragment categoryPickerFragment =
+ (CategoryPickerFragment) fm.findFragmentById(R.id.fragment_container);
+ if (categoryPickerFragment != null) {
+ categoryPickerFragment.addCategory(category);
+ }
+ }
+ }
+
+ @Override
+ public void doneFetchingCategories() {
+ if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
+ final FragmentManager fm = getSupportFragmentManager();
+ CategoryPickerFragment categoryPickerFragment =
+ (CategoryPickerFragment) fm.findFragmentById(R.id.fragment_container);
+ if (categoryPickerFragment != null) {
+ categoryPickerFragment.doneFetchingCategories();
+ }
+ } else { // DESKTOP
+ populateCategoryTabs(selectedTabPosition);
+ }
+ }
+ }, forceRefresh);
+ }
+
+ /**
+ * Populates the category tabs on DESKTOP form factor.
+ *
+ * @param selectedTabPosition The position of the tab to show as selected, or -1 if no particular
+ * tab should be selected (in which case: the tab of the category for the currently set
+ * wallpaper will be selected if enumerable; if not, the first enumerable category's tab will
+ * be selected).
+ */
+ private void populateCategoryTabs(int selectedTabPosition) {
+ final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
+ tabLayout.removeAllTabs();
+
+ String currentlySetCollectionId = mPreferences.getHomeWallpaperCollectionId();
+
+ Tab tabToSelect = null;
+ Tab firstEnumerableCategoryTab = null;
+ for (int i = 0; i < mCategories.size(); i++) {
+ Category category = mCategories.get(i);
+
+ Tab tab = tabLayout.newTab();
+ tab.setText(category.getTitle());
+ tab.setTag(category);
+ tabLayout.addTab(tab, false /* setSelected */);
+
+ if (firstEnumerableCategoryTab == null && category.isEnumerable()) {
+ firstEnumerableCategoryTab = tab;
+ }
+
+ boolean shouldSelectTab = (i == selectedTabPosition)
+ || (selectedTabPosition == -1
+ && tabToSelect == null
+ && category.isEnumerable()
+ && currentlySetCollectionId != null
+ && currentlySetCollectionId.equals(category.getCollectionId()));
+
+ if (shouldSelectTab) {
+ tabToSelect = tab;
+ }
+ }
+
+ // If the above loop did not identify a specific tab to select, then just select the tab for
+ // the first enumerable category.
+ if (tabToSelect == null) {
+ tabToSelect = firstEnumerableCategoryTab;
+ }
+
+ // There may be no enumerable tabs (e.g., offline case), so we need to null-check again.
+ if (tabToSelect != null) {
+ tabToSelect.select();
+ }
+ }
+
+ /**
+ * Refreshes the current wallpaper in a daily wallpaper rotation.
+ */
+ private void refreshDailyWallpaper() {
+ // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
+ // causes Espresso to hang once the dialog is shown.
+ if (!mTestingMode) {
+ int themeResId;
+ if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
+ themeResId = R.style.ProgressDialogThemePreL;
+ } else {
+ themeResId = R.style.LightDialogTheme;
+ }
+ mRefreshWallpaperProgressDialog = new ProgressDialog(this, themeResId);
+ mRefreshWallpaperProgressDialog.setTitle(null);
+ mRefreshWallpaperProgressDialog.setMessage(
+ getResources().getString(R.string.refreshing_daily_wallpaper_dialog_message));
+ mRefreshWallpaperProgressDialog.setIndeterminate(true);
+ mRefreshWallpaperProgressDialog.show();
+ }
+
+ WallpaperRotationRefresher wallpaperRotationRefresher =
+ InjectorProvider.getInjector().getWallpaperRotationRefresher();
+ wallpaperRotationRefresher.refreshWallpaper(this, new Listener() {
+ @Override
+ public void onRefreshed() {
+ if (isDestroyed()) {
+ return;
+ }
+
+ if (mRefreshWallpaperProgressDialog != null) {
+ mRefreshWallpaperProgressDialog.dismiss();
+ }
+
+ refreshCurrentWallpapers(null /* refreshListener */);
+ }
+
+ @Override
+ public void onError() {
+ if (mRefreshWallpaperProgressDialog != null) {
+ mRefreshWallpaperProgressDialog.dismiss();
+ }
+
+ AlertDialog errorDialog = new AlertDialog.Builder(
+ TopLevelPickerActivity.this, R.style.LightDialogTheme)
+ .setMessage(R.string.refresh_daily_wallpaper_failed_message)
+ .setPositiveButton(android.R.string.ok, null /* onClickListener */)
+ .create();
+ errorDialog.show();
+ }
+ });
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ if (requestCode == SHOW_CATEGORY_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
+ Uri imageUri = (data == null) ? null : data.getData();
+ if (imageUri != null) {
+ // User selected an image from the system picker, so launch the preview for that image.
+ ImageWallpaperInfo imageWallpaper = new ImageWallpaperInfo(imageUri);
+ if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
+ setCustomPhotoWallpaper(imageWallpaper);
+ return;
+ }
+
+ imageWallpaper.showPreview(this, mPreviewIntentFactory, PREVIEW_WALLPAPER_REQUEST_CODE);
+ } else {
+ // User finished viewing a category without any data, which implies that the user previewed
+ // and selected a wallpaper in-app, so finish this activity.
+ finishActivityWithResultOk();
+ }
+ } else if (requestCode == PREVIEW_WALLPAPER_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
+ // User previewed and selected a wallpaper, so finish this activity.
+ finishActivityWithResultOk();
+ }
+ }
+
+ /**
+ * Shows the view-only preview activity for the given wallpaper.
+ */
+ public void showViewOnlyPreview(WallpaperInfo wallpaperInfo) {
+ wallpaperInfo.showPreview(
+ this, mViewOnlyPreviewIntentFactory, VIEW_ONLY_PREVIEW_WALLPAPER_REQUEST_CODE);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ if (requestCode == READ_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE
+ && permissions.length > 0
+ && permissions[0].equals(permission.READ_EXTERNAL_STORAGE)
+ && grantResults.length > 0) {
+ if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ for (PermissionChangedListener listener : mPermissionChangedListeners) {
+ listener.onPermissionsGranted();
+ }
+ } else if (!shouldShowRequestPermissionRationale(permission.READ_EXTERNAL_STORAGE)) {
+ for (PermissionChangedListener listener : mPermissionChangedListeners) {
+ listener.onPermissionsDenied(true /* dontAskAgain */);
+ }
+ } else {
+ for (PermissionChangedListener listener : mPermissionChangedListeners) {
+ listener.onPermissionsDenied(false /* dontAskAgain */);
+ }
+ }
+ }
+ mPermissionChangedListeners.clear();
+ }
+
+ /**
+ * Shows the picker activity for the given category.
+ */
+ public void show(String collectionId) {
+ Category category = findCategoryForCollectionId(collectionId);
+ if (category == null) {
+ return;
+ }
+
+ if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
+ category.show(this, mPickerIntentFactory, SHOW_CATEGORY_REQUEST_CODE);
+ } else { // DESKTOP
+ showCategoryDesktop(collectionId);
+ }
+ }
+
+ private void reselectLastTab() {
+ TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
+
+ // In the offline case, "My photos" could be the only category. Thus we need this check --
+ // to ensure that we don't try to select the "previously selected" category which was -1.
+ if (mLastSelectedCategoryTabIndex > -1) {
+ Tab tabToSelect = tabLayout.getTabAt(mLastSelectedCategoryTabIndex);
+ if (((Category) tabToSelect.getTag()).isEnumerable()) {
+ tabToSelect.select();
+ }
+ }
+ }
+
+ @Nullable
+ private Category findCategoryForCollectionId(String collectionId) {
+ for (Category category : mCategories) {
+ if (category.getCollectionId().equals(collectionId)) {
+ return category;
+ }
+ }
+ return null;
+ }
+
+ private void showCategoryDesktop(String collectionId) {
+ Category category = findCategoryForCollectionId(collectionId);
+ if (category == null) {
+ return;
+ }
+
+ if (category.isEnumerable()) {
+ // Replace contained IndividualPickerFragment with a new instance for the given category.
+ final FragmentManager fm = getSupportFragmentManager();
+ Fragment fragment = fm.findFragmentById(R.id.fragment_container);
+ if (fragment != null) {
+ fm.beginTransaction()
+ .remove(fragment)
+ .commit();
+ }
+ IndividualPickerFragment newFragment = IndividualPickerFragment.newInstance(collectionId);
+ fm.beginTransaction()
+ .add(R.id.fragment_container, newFragment)
+ .commit();
+ newFragment.setCurrentWallpaperBottomSheetPresenter(this);
+ newFragment.setWallpapersUiContainer(this);
+ } else {
+ category.show(this, mPickerIntentFactory, SHOW_CATEGORY_REQUEST_CODE);
+
+ // Need to select the tab here in case we are coming back from a "My photos" in which case
+ // the tab would have been set to "My photos" while viewing a regular image category.
+ reselectLastTab();
+ }
+ }
+
+ private void finishActivityWithResultOk() {
+ overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
+ setResult(Activity.RESULT_OK);
+ finish();
+ }
+
+ @WallpaperSupportLevel
+ private int getWallpaperSupportLevel() {
+ WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
+
+ if (VERSION.SDK_INT >= VERSION_CODES.N) {
+ if (wallpaperManager.isWallpaperSupported()) {
+ return wallpaperManager.isSetWallpaperAllowed()
+ ? WallpaperDisabledFragment.SUPPORTED_CAN_SET
+ : WallpaperDisabledFragment.NOT_SUPPORTED_BLOCKED_BY_ADMIN;
+ }
+ return WallpaperDisabledFragment.NOT_SUPPORTED_BY_DEVICE;
+ } else if (VERSION.SDK_INT >= VERSION_CODES.M) {
+ return wallpaperManager.isWallpaperSupported() ? WallpaperDisabledFragment.SUPPORTED_CAN_SET
+ : WallpaperDisabledFragment.NOT_SUPPORTED_BY_DEVICE;
+ } else {
+ WallpaperManagerCompat wallpaperManagerCompat =
+ InjectorProvider.getInjector().getWallpaperManagerCompat(this);
+ boolean isSupported = wallpaperManagerCompat.getDrawable() != null;
+ wallpaperManager.forgetLoadedWallpaper();
+ return isSupported ? WallpaperDisabledFragment.SUPPORTED_CAN_SET
+ : WallpaperDisabledFragment.NOT_SUPPORTED_BY_DEVICE;
+ }
+ }
+
+ @Override
+ public void setCurrentWallpapersExpanded(boolean expanded) {
+ final BottomSheetBehavior<LinearLayout> bottomSheetBehavior =
+ BottomSheetBehavior.from(mBottomSheet);
+ bottomSheetBehavior.setState(
+ expanded ? BottomSheetBehavior.STATE_EXPANDED : BottomSheetBehavior.STATE_COLLAPSED);
+ }
+
+ @Override
+ public void onWallpapersReady() {
+ setDesktopLoading(false);
+ setCurrentWallpapersExpanded(true);
+ }
+
+ @Override
+ public void onClickTryAgain(@Destination int unused) {
+ // Retry the set wallpaper operation with the default center-crop setting.
+ if (mPendingSetWallpaperInfo != null) {
+ setCustomPhotoWallpaper(mPendingSetWallpaperInfo);
+ }
+ }
+
+ /**
+ * Sets the provides wallpaper to the device with center-cropped and scaled to fit the device's
+ * default display.
+ */
+ private void setCustomPhotoWallpaper(final WallpaperInfo wallpaper) {
+ // Save this WallpaperInfo so we can retry this operation later if it fails.
+ mPendingSetWallpaperInfo = wallpaper;
+
+ showSettingWallpaperProgressDialog();
+
+ mWallpaperPersister.setIndividualWallpaperWithPosition(this, wallpaper,
+ WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP, new SetWallpaperCallback() {
+ @Override
+ public void onSuccess() {
+ dismissSettingWallpaperProgressDialog();
+ refreshCurrentWallpapers(null /* refreshListener */);
+
+ mPreferences.setPendingWallpaperSetStatus(
+ WallpaperPreferences.WALLPAPER_SET_NOT_PENDING);
+ mUserEventLogger.logWallpaperSet(
+ wallpaper.getCollectionId(getApplicationContext()),
+ wallpaper.getWallpaperId());
+ mUserEventLogger.logWallpaperSetResult(UserEventLogger.WALLPAPER_SET_RESULT_SUCCESS);
+
+ // The user may have closed the activity before the set wallpaper operation completed.
+ if (isDestroyed()) {
+ return;
+ }
+
+ // Show the wallpaper crop option selector and bind click event handlers.
+ mWallpaperPositionOptions.setVisibility(View.VISIBLE);
+
+ mWasCustomPhotoWallpaperSet = true;
+ mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP;
+
+ initializeWallpaperPositionOptionClickHandlers(wallpaper);
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+ dismissSettingWallpaperProgressDialog();
+ showSetWallpaperErrorDialog();
+
+ mPreferences.setPendingWallpaperSetStatus(
+ WallpaperPreferences.WALLPAPER_SET_NOT_PENDING);
+ mUserEventLogger.logWallpaperSetResult(
+ UserEventLogger.WALLPAPER_SET_RESULT_FAILURE);
+ @WallpaperSetFailureReason int failureReason = ThrowableAnalyzer.isOOM(throwable)
+ ? UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OOM
+ : UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OTHER;
+ mUserEventLogger.logWallpaperSetFailureReason(failureReason);
+ Log.e(TAG, "Unable to set wallpaper from 'my photos'.");
+ }
+ });
+ }
+
+ /**
+ * Initializes the wallpaper position button click handlers to change the way the provided
+ * wallpaper is set to the device.
+ */
+ private void initializeWallpaperPositionOptionClickHandlers(final WallpaperInfo wallpaperInfo) {
+ Button centerCropOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_center_crop);
+ Button stretchOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_stretched);
+ Button centerOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_center);
+
+ // The "center crop" wallpaper position button is selected by default.
+ setCenterCropWallpaperPositionButtonSelected(centerCropOptionBtn, true /* isSelected */);
+ centerCropOptionBtn.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
+ wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP,
+ new SetWallpaperCallback() {
+ @Override
+ public void onSuccess() {
+ // The user may have closed the activity before the set wallpaper operation
+ // completed.
+ if (isDestroyed()) {
+ return;
+ }
+
+ refreshCurrentWallpapers(null /* refreshListener */);
+
+ setCenterCropWallpaperPositionButtonSelected(
+ centerCropOptionBtn, true /* isSelected */);
+ setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
+ setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
+
+ mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP;
+ }
+
+ @Override
+ public void onError(@Nullable Throwable throwable) {
+ // no-op
+ }
+ });
+ }
+ });
+
+ // "Stretch" is not selected by default.
+ setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
+ stretchOptionBtn.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
+ wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_STRETCH,
+ new SetWallpaperCallback() {
+ @Override
+ public void onSuccess() {
+ // The user may have closed the activity before the set wallpaper operation
+ // completed.
+ if (isDestroyed()) {
+ return;
+ }
+
+ refreshCurrentWallpapers(null /* refreshListener */);
+
+ setStretchWallpaperPositionButtonSelected(stretchOptionBtn, true /* isSelected */);
+ setCenterCropWallpaperPositionButtonSelected(
+ centerCropOptionBtn, false /* isSelected */);
+ setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
+
+ mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_STRETCH;
+ }
+
+ @Override
+ public void onError(@Nullable Throwable throwable) {
+ // no-op
+ }
+ });
+ }
+ });
+
+ // "Center" is not selected by default.
+ setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
+ centerOptionBtn.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
+ wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_CENTER,
+ new SetWallpaperCallback() {
+ @Override
+ public void onSuccess() {
+ // The user may have closed the activity before the set wallpaper operation
+ // completed.
+ if (isDestroyed()) {
+ return;
+ }
+
+ refreshCurrentWallpapers(null /* refreshListener */);
+
+ setCenterWallpaperPositionButtonSelected(centerOptionBtn, true /* isSelected */);
+ setCenterCropWallpaperPositionButtonSelected(
+ centerCropOptionBtn, false /* isSelected */);
+ setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
+
+ mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER;
+ }
+
+ @Override
+ public void onError(@Nullable Throwable throwable) {
+ // no-op
+ }
+ });
+ }
+ });
+ }
+
+ private void setCenterWallpaperPositionButtonSelected(Button button, boolean isSelected) {
+ int drawableId = isSelected ? R.drawable.center_blue : R.drawable.center_grey;
+ ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
+ button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
+ }
+
+ private void setCenterCropWallpaperPositionButtonSelected(Button button, boolean isSelected) {
+ int drawableId = isSelected ? R.drawable.center_crop_blue : R.drawable.center_crop_grey;
+ ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
+ button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
+ }
+
+ private void setStretchWallpaperPositionButtonSelected(Button button, boolean isSelected) {
+ int drawableId = isSelected ? R.drawable.stretch_blue : R.drawable.stretch_grey;
+ ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
+ button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
+ }
+
+ private void showSettingWallpaperProgressDialog() {
+ // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
+ // causes Espresso to hang once the dialog is shown.
+ if (!mTestingMode) {
+ int themeResId;
+ if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
+ themeResId = R.style.ProgressDialogThemePreL;
+ } else {
+ themeResId = R.style.LightDialogTheme;
+ }
+ mSetWallpaperProgressDialog = new ProgressDialog(this, themeResId);
+ mSetWallpaperProgressDialog.setTitle(null);
+ mSetWallpaperProgressDialog.setMessage(
+ getResources().getString(R.string.set_wallpaper_progress_message));
+ mSetWallpaperProgressDialog.setIndeterminate(true);
+ mSetWallpaperProgressDialog.show();
+ }
+ }
+
+ private void dismissSettingWallpaperProgressDialog() {
+ if (mSetWallpaperProgressDialog != null) {
+ mSetWallpaperProgressDialog.dismiss();
+ }
+ }
+
+ private void showSetWallpaperErrorDialog() {
+ SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance(
+ R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH);
+
+ if (isSafeToCommitFragmentTransaction()) {
+ dialogFragment.show(getSupportFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
+ } else {
+ mStagedSetWallpaperErrorDialogFragment = dialogFragment;
+ }
+ }
+
+ private interface AssetReceiver {
+ void onAssetReceived(Asset asset);
+ }
+
+ /**
+ * An AsyncTask for asynchronously fetching the thumbnail asset for a given WallpaperInfo.
+ * Used to work around expensive method call to WallpaperManager#getWallpaperFile made from the
+ * CurrentWallpaperInfoVN getAsset() method.
+ */
+ private static class FetchThumbAssetTask extends AsyncTask<Void, Void, Asset> {
+ private Context mAppContext;
+ private WallpaperInfo mWallpaperInfo;
+ private AssetReceiver mReceiver;
+
+ public FetchThumbAssetTask(Context appContext, WallpaperInfo wallpaperInfo,
+ AssetReceiver receiver) {
+ mAppContext = appContext;
+ mWallpaperInfo = wallpaperInfo;
+ mReceiver = receiver;
+ }
+
+ @Override
+ protected Asset doInBackground(Void... params) {
+ return mWallpaperInfo.getThumbAsset(mAppContext);
+ }
+
+ @Override
+ protected void onPostExecute(Asset thumbAsset) {
+ mReceiver.onAssetReceived(thumbAsset);
+ }
+ }
+}