blob: c87c4cd07543f9c0add5ccb5fec4c7d8305a892b [file] [log] [blame]
Jon Miranda16ea1b12017-12-12 14:52:48 -08001/*
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 */
16package com.android.wallpaper.picker.individual;
17
Chuck Liao69630f12020-03-05 19:01:25 +080018import static com.android.wallpaper.widget.BottomActionBar.BottomAction.APPLY;
chihhangchuang22aa0cc2020-03-25 19:12:42 +080019import static com.android.wallpaper.widget.BottomActionBar.BottomAction.INFORMATION;
Chuck Liao8ec38e02020-02-26 20:59:32 +080020import static com.android.wallpaper.widget.BottomActionBar.BottomAction.ROTATION;
21
Jon Miranda16ea1b12017-12-12 14:52:48 -080022import android.app.Activity;
23import android.app.ProgressDialog;
“Chuck7ef99722020-03-22 04:34:03 +080024import android.app.WallpaperManager;
Jon Miranda16ea1b12017-12-12 14:52:48 -080025import android.content.Context;
chihhangchuangc687d912020-05-04 14:33:05 +080026import android.content.Intent;
Santiago Etchebehereb1854472019-06-06 17:44:54 -070027import android.content.res.Configuration;
Jon Miranda16ea1b12017-12-12 14:52:48 -080028import android.content.res.Resources.NotFoundException;
29import android.graphics.Point;
30import android.graphics.PorterDuff.Mode;
Chuck Liaoba401232020-03-13 20:11:04 +080031import android.graphics.Rect;
Jon Miranda16ea1b12017-12-12 14:52:48 -080032import android.os.Build.VERSION;
33import android.os.Build.VERSION_CODES;
34import android.os.Bundle;
35import android.os.Handler;
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -070036import android.service.wallpaper.WallpaperService;
Jon Miranda16ea1b12017-12-12 14:52:48 -080037import android.util.Log;
38import android.view.LayoutInflater;
39import android.view.View;
40import android.view.ViewGroup;
Jon Miranda16ea1b12017-12-12 14:52:48 -080041import android.widget.ImageView;
42import android.widget.TextView;
43import android.widget.Toast;
44
Santiago Etchebehereb1854472019-06-06 17:44:54 -070045import androidx.annotation.NonNull;
Chuck Liao69630f12020-03-05 19:01:25 +080046import androidx.annotation.Nullable;
Chuck Liaoba401232020-03-13 20:11:04 +080047import androidx.cardview.widget.CardView;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080048import androidx.fragment.app.DialogFragment;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080049import androidx.recyclerview.widget.GridLayoutManager;
50import androidx.recyclerview.widget.RecyclerView;
51import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
52import androidx.recyclerview.widget.RecyclerView.ViewHolder;
53
Jon Miranda16ea1b12017-12-12 14:52:48 -080054import com.android.wallpaper.R;
55import com.android.wallpaper.asset.Asset;
56import com.android.wallpaper.asset.Asset.DrawableLoadedListener;
57import com.android.wallpaper.config.Flags;
Santiago Etchebehere8648bb82019-08-06 17:09:02 -070058import com.android.wallpaper.model.Category;
59import com.android.wallpaper.model.CategoryProvider;
60import com.android.wallpaper.model.CategoryReceiver;
Chuck Liao69630f12020-03-05 19:01:25 +080061import com.android.wallpaper.model.LiveWallpaperInfo;
Jon Miranda16ea1b12017-12-12 14:52:48 -080062import com.android.wallpaper.model.WallpaperCategory;
63import com.android.wallpaper.model.WallpaperInfo;
64import com.android.wallpaper.model.WallpaperReceiver;
65import com.android.wallpaper.model.WallpaperRotationInitializer;
66import com.android.wallpaper.model.WallpaperRotationInitializer.Listener;
67import com.android.wallpaper.model.WallpaperRotationInitializer.NetworkPreference;
68import com.android.wallpaper.model.WallpaperRotationInitializer.RotationInitializationState;
Jon Miranda16ea1b12017-12-12 14:52:48 -080069import com.android.wallpaper.module.FormFactorChecker;
70import com.android.wallpaper.module.FormFactorChecker.FormFactor;
71import com.android.wallpaper.module.Injector;
72import com.android.wallpaper.module.InjectorProvider;
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -070073import com.android.wallpaper.module.PackageStatusNotifier;
chihhangchuangc687d912020-05-04 14:33:05 +080074import com.android.wallpaper.module.UserEventLogger;
Jon Miranda16ea1b12017-12-12 14:52:48 -080075import com.android.wallpaper.module.WallpaperChangedNotifier;
76import com.android.wallpaper.module.WallpaperPersister;
77import com.android.wallpaper.module.WallpaperPersister.Destination;
78import com.android.wallpaper.module.WallpaperPreferences;
Chuck Liao69630f12020-03-05 19:01:25 +080079import com.android.wallpaper.module.WallpaperSetter;
Jon Miranda16ea1b12017-12-12 14:52:48 -080080import com.android.wallpaper.picker.BaseActivity;
chihhangchuang3efb6832020-04-17 02:06:25 +080081import com.android.wallpaper.picker.BottomActionBarFragment;
Jon Miranda16ea1b12017-12-12 14:52:48 -080082import com.android.wallpaper.picker.CurrentWallpaperBottomSheetPresenter;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080083import com.android.wallpaper.picker.MyPhotosStarter.MyPhotosStarterProvider;
Jon Miranda16ea1b12017-12-12 14:52:48 -080084import com.android.wallpaper.picker.RotationStarter;
Chuck Liao69630f12020-03-05 19:01:25 +080085import com.android.wallpaper.picker.SetWallpaperDialogFragment;
Jon Miranda16ea1b12017-12-12 14:52:48 -080086import com.android.wallpaper.picker.SetWallpaperErrorDialogFragment;
87import com.android.wallpaper.picker.StartRotationDialogFragment;
88import com.android.wallpaper.picker.StartRotationErrorDialogFragment;
chihhangchuangc687d912020-05-04 14:33:05 +080089import com.android.wallpaper.picker.WallpaperInfoHelper;
Jon Miranda16ea1b12017-12-12 14:52:48 -080090import com.android.wallpaper.picker.WallpapersUiContainer;
91import com.android.wallpaper.picker.individual.SetIndividualHolder.OnSetListener;
92import com.android.wallpaper.util.DiskBasedLogger;
93import com.android.wallpaper.util.TileSizeCalculator;
Chuck Liao8ec38e02020-02-26 20:59:32 +080094import com.android.wallpaper.widget.BottomActionBar;
chihhangchuang1a29e752020-04-28 18:22:53 +080095import com.android.wallpaper.widget.WallpaperInfoView;
Sunny Goyal8600a3f2018-08-15 12:48:01 -070096
Jon Miranda16ea1b12017-12-12 14:52:48 -080097import com.bumptech.glide.Glide;
98import com.bumptech.glide.MemoryCategory;
99
100import java.util.ArrayList;
101import java.util.Date;
102import java.util.List;
Chuck Liao11f4a762020-04-08 13:24:43 +0800103import java.util.Optional;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800104import java.util.Random;
105
106/**
107 * Displays the Main UI for picking an individual wallpaper image.
108 */
chihhangchuang3efb6832020-04-17 02:06:25 +0800109public class IndividualPickerFragment extends BottomActionBarFragment
Jon Miranda16ea1b12017-12-12 14:52:48 -0800110 implements RotationStarter, StartRotationErrorDialogFragment.Listener,
111 CurrentWallpaperBottomSheetPresenter.RefreshListener,
Chuck Liao69630f12020-03-05 19:01:25 +0800112 SetWallpaperErrorDialogFragment.Listener, SetWallpaperDialogFragment.Listener {
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800113 /**
114 * Position of a special tile that doesn't belong to an individual wallpaper of the category,
115 * such as "my photos" or "daily rotation".
116 */
117 static final int SPECIAL_FIXED_TILE_ADAPTER_POSITION = 0;
118 static final String ARG_CATEGORY_COLLECTION_ID = "category_collection_id";
Ching-Sung Li073812b2020-04-07 21:19:21 +0800119 /**
120 * A temporary flag to hide the bottom action bar feature.
121 */
Chuck Liao1b7de472020-04-24 14:06:38 +0800122 static final boolean TEMP_BOTTOM_ACTION_BAR_FEATURE = true;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800123
Jon Miranda16ea1b12017-12-12 14:52:48 -0800124 private static final String TAG = "IndividualPickerFrgmnt";
Jon Miranda16ea1b12017-12-12 14:52:48 -0800125 private static final int UNUSED_REQUEST_CODE = 1;
126 private static final String TAG_START_ROTATION_DIALOG = "start_rotation_dialog";
127 private static final String TAG_START_ROTATION_ERROR_DIALOG = "start_rotation_error_dialog";
128 private static final String PROGRESS_DIALOG_NO_TITLE = null;
129 private static final boolean PROGRESS_DIALOG_INDETERMINATE = true;
130 private static final String TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT =
131 "individual_set_wallpaper_error_dialog";
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700132 private static final String KEY_NIGHT_MODE = "IndividualPickerFragment.NIGHT_MODE";
Jon Miranda16ea1b12017-12-12 14:52:48 -0800133
Chuck Liao8ec38e02020-02-26 20:59:32 +0800134 /**
Chuck Liaof40063f2020-03-03 18:35:24 +0800135 * An interface for updating the thumbnail with the specific wallpaper.
136 */
137 public interface ThumbnailUpdater {
138 /**
139 * Updates the thumbnail with the specific wallpaper.
140 */
141 void updateThumbnail(WallpaperInfo wallpaperInfo);
142
143 /**
144 * Restores to the thumbnails of the wallpapers which were applied.
145 */
146 void restoreThumbnails();
147 }
148
“Chuck7ef99722020-03-22 04:34:03 +0800149 /**
150 * An interface for receiving the destination of the new applied wallpaper.
151 */
152 public interface WallpaperDestinationCallback {
153 /**
154 * Called when the destination of the wallpaper is set.
155 *
156 * @param destination the destination which a wallpaper may be set.
157 * See {@link Destination} for more details.
158 */
159 void onDestinationSet(@Destination int destination);
160 }
161
Chuck Liaob3829fb2020-04-01 00:47:50 +0800162 /**
163 * The listener which will be notified when the wallpaper is selected.
164 */
165 public interface WallpaperSelectedListener {
166 /**
167 * Called when the wallpaper is selected.
168 *
169 * @param position the position of the selected wallpaper
170 */
171 void onWallpaperSelected(int position);
172 }
173
Ching-Sung Lied6560f2020-05-04 19:25:09 +0800174 WallpaperPersister mWallpaperPersister;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800175 WallpaperPreferences mWallpaperPreferences;
176 WallpaperChangedNotifier mWallpaperChangedNotifier;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800177 RecyclerView mImageGrid;
178 IndividualAdapter mAdapter;
179 WallpaperCategory mCategory;
180 WallpaperRotationInitializer mWallpaperRotationInitializer;
181 List<WallpaperInfo> mWallpapers;
182 Point mTileSizePx;
183 WallpapersUiContainer mWallpapersUiContainer;
184 @FormFactor
185 int mFormFactor;
186 PackageStatusNotifier mPackageStatusNotifier;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800187
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800188 Handler mHandler;
189 Random mRandom;
190
191 WallpaperChangedNotifier.Listener mWallpaperChangedListener =
192 new WallpaperChangedNotifier.Listener() {
193 @Override
194 public void onWallpaperChanged() {
195 if (mFormFactor != FormFactorChecker.FORM_FACTOR_DESKTOP) {
196 return;
197 }
198
199 ViewHolder selectedViewHolder = mImageGrid.findViewHolderForAdapterPosition(
200 mAdapter.mSelectedAdapterPosition);
201
202 // Null remote ID => My Photos wallpaper, so deselect whatever was previously selected.
203 if (mWallpaperPreferences.getHomeWallpaperRemoteId() == null) {
204 if (selectedViewHolder instanceof SelectableHolder) {
205 ((SelectableHolder) selectedViewHolder).setSelectionState(
206 SelectableHolder.SELECTION_STATE_DESELECTED);
207 }
208 } else {
209 mAdapter.updateSelectedTile(mAdapter.mPendingSelectedAdapterPosition);
210 }
211 }
212 };
213 PackageStatusNotifier.Listener mAppStatusListener;
Ching-Sung Li073812b2020-04-07 21:19:21 +0800214 BottomActionBar mBottomActionBar;
chihhangchuang1a29e752020-04-28 18:22:53 +0800215 WallpaperInfoView mWallpaperInfoView;
Ching-Sung Li073812b2020-04-07 21:19:21 +0800216 @Nullable WallpaperInfo mSelectedWallpaperInfo;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800217
chihhangchuangc687d912020-05-04 14:33:05 +0800218 private UserEventLogger mUserEventLogger;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800219 private ProgressDialog mProgressDialog;
220 private boolean mTestingMode;
221 private CurrentWallpaperBottomSheetPresenter mCurrentWallpaperBottomSheetPresenter;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800222 private SetIndividualHolder mPendingSetIndividualHolder;
223
224 /**
225 * Staged error dialog fragments that were unable to be shown when the activity didn't allow
226 * committing fragment transactions.
227 */
228 private SetWallpaperErrorDialogFragment mStagedSetWallpaperErrorDialogFragment;
229 private StartRotationErrorDialogFragment mStagedStartRotationErrorDialogFragment;
230
Jon Miranda16ea1b12017-12-12 14:52:48 -0800231 private Runnable mCurrentWallpaperBottomSheetExpandedRunnable;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800232
233 /**
234 * Whether {@code mUpdateDailyWallpaperThumbRunnable} has been run at least once in this
235 * invocation of the fragment.
236 */
237 private boolean mWasUpdateRunnableRun;
238
239 /**
240 * A Runnable which regularly updates the thumbnail for the "Daily wallpapers" tile in desktop
241 * mode.
242 */
243 private Runnable mUpdateDailyWallpaperThumbRunnable = new Runnable() {
244 @Override
245 public void run() {
246 ViewHolder viewHolder = mImageGrid.findViewHolderForAdapterPosition(
247 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
248 if (viewHolder instanceof DesktopRotationHolder) {
249 updateDesktopDailyRotationThumbnail((DesktopRotationHolder) viewHolder);
250 } else { // viewHolder is null
251 // If the rotation tile is unavailable (because user has scrolled down, causing the
252 // ViewHolder to be recycled), schedule the update for some time later. Once user scrolls up
253 // again, the ViewHolder will be re-bound and its thumbnail will be updated.
254 mHandler.postDelayed(mUpdateDailyWallpaperThumbRunnable,
255 DesktopRotationHolder.CROSSFADE_DURATION_MILLIS
256 + DesktopRotationHolder.CROSSFADE_DURATION_PAUSE_MILLIS);
257 }
258 }
259 };
260
Chuck Liao69630f12020-03-05 19:01:25 +0800261 private WallpaperSetter mWallpaperSetter;
“Chuckffd832c2020-03-22 02:15:58 +0800262 private WallpaperInfo mAppliedWallpaperInfo;
“Chuck7ef99722020-03-22 04:34:03 +0800263 private WallpaperManager mWallpaperManager;
264 private int mWallpaperDestination;
Chuck Liaob3829fb2020-04-01 00:47:50 +0800265 private WallpaperSelectedListener mWallpaperSelectedListener;
Chuck Liao8ec38e02020-02-26 20:59:32 +0800266
Jon Miranda16ea1b12017-12-12 14:52:48 -0800267 public static IndividualPickerFragment newInstance(String collectionId) {
268 Bundle args = new Bundle();
269 args.putString(ARG_CATEGORY_COLLECTION_ID, collectionId);
270
271 IndividualPickerFragment fragment = new IndividualPickerFragment();
272 fragment.setArguments(args);
273 return fragment;
274 }
275
“Chuck7ef99722020-03-22 04:34:03 +0800276 /**
277 * Highlights the applied wallpaper (if it exists) according to the destination a wallpaper
278 * would be set.
279 *
280 * @param wallpaperDestination the destination a wallpaper would be set.
281 * It will be either {@link Destination#DEST_HOME_SCREEN}
282 * or {@link Destination#DEST_LOCK_SCREEN}.
283 */
284 public void highlightAppliedWallpaper(@Destination int wallpaperDestination) {
285 mWallpaperDestination = wallpaperDestination;
Chuck Liao11f4a762020-04-08 13:24:43 +0800286 if (mWallpapers != null) {
287 refreshAppliedWallpaper();
“Chuck7ef99722020-03-22 04:34:03 +0800288 }
289 }
290
Jon Miranda16ea1b12017-12-12 14:52:48 -0800291 private static int getResIdForRotationState(@RotationInitializationState int rotationState) {
292 switch (rotationState) {
293 case WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED:
294 return R.string.daily_refresh_tile_subtitle;
295 case WallpaperRotationInitializer.ROTATION_HOME_ONLY:
296 return R.string.home_screen_message;
297 case WallpaperRotationInitializer.ROTATION_HOME_AND_LOCK:
298 return R.string.home_and_lock_short_label;
299 default:
300 Log.e(TAG, "Unknown rotation intialization state: " + rotationState);
301 return R.string.home_screen_message;
302 }
303 }
304
305 private void updateDesktopDailyRotationThumbnail(DesktopRotationHolder holder) {
306 int wallpapersIndex = mRandom.nextInt(mWallpapers.size());
307 Asset newThumbnailAsset = mWallpapers.get(wallpapersIndex).getThumbAsset(
308 getActivity());
309 holder.updateThumbnail(newThumbnailAsset, new DrawableLoadedListener() {
310 @Override
311 public void onDrawableLoaded() {
312 if (getActivity() == null) {
313 return;
314 }
315
316 // Schedule the next update of the thumbnail.
317 int delayMillis = DesktopRotationHolder.CROSSFADE_DURATION_MILLIS
318 + DesktopRotationHolder.CROSSFADE_DURATION_PAUSE_MILLIS;
319 mHandler.postDelayed(mUpdateDailyWallpaperThumbRunnable, delayMillis);
320 }
321 });
322 }
323
324 @Override
325 public void onCreate(Bundle savedInstanceState) {
326 super.onCreate(savedInstanceState);
327
328 Injector injector = InjectorProvider.getInjector();
329 Context appContext = getContext().getApplicationContext();
330 mWallpaperPreferences = injector.getPreferences(appContext);
331
332 mWallpaperChangedNotifier = WallpaperChangedNotifier.getInstance();
333 mWallpaperChangedNotifier.registerListener(mWallpaperChangedListener);
334
“Chuck7ef99722020-03-22 04:34:03 +0800335 mWallpaperManager = WallpaperManager.getInstance(appContext);
336
Jon Miranda16ea1b12017-12-12 14:52:48 -0800337 mFormFactor = injector.getFormFactorChecker(appContext).getFormFactor();
338
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700339 mPackageStatusNotifier = injector.getPackageStatusNotifier(appContext);
340
chihhangchuangc687d912020-05-04 14:33:05 +0800341 mUserEventLogger = injector.getUserEventLogger(appContext);
342
“Chuckffd832c2020-03-22 02:15:58 +0800343 mWallpaperPersister = injector.getWallpaperPersister(appContext);
Chuck Liao69630f12020-03-05 19:01:25 +0800344 mWallpaperSetter = new WallpaperSetter(
“Chuckffd832c2020-03-22 02:15:58 +0800345 mWallpaperPersister,
Chuck Liao69630f12020-03-05 19:01:25 +0800346 injector.getPreferences(appContext),
347 injector.getUserEventLogger(appContext),
348 false);
349
Jon Miranda16ea1b12017-12-12 14:52:48 -0800350 mWallpapers = new ArrayList<>();
351 mRandom = new Random();
352 mHandler = new Handler();
353
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700354 // Clear Glide's cache if night-mode changed to ensure thumbnails are reloaded
355 if (savedInstanceState != null && (savedInstanceState.getInt(KEY_NIGHT_MODE)
356 != (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK))) {
357 Glide.get(getContext()).clearMemory();
358 }
359
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700360 CategoryProvider categoryProvider = injector.getCategoryProvider(appContext);
361 categoryProvider.fetchCategories(new CategoryReceiver() {
362 @Override
363 public void onCategoryReceived(Category category) {
364 // Do nothing.
365 }
366
367 @Override
368 public void doneFetchingCategories() {
369 mCategory = (WallpaperCategory) categoryProvider.getCategory(
370 getArguments().getString(ARG_CATEGORY_COLLECTION_ID));
371 if (mCategory == null) {
372 DiskBasedLogger.e(TAG, "Failed to find the category.", getContext());
373
374 // The absence of this category in the CategoryProvider indicates a broken
375 // state, see b/38030129. Hence, finish the activity and return.
376 getActivity().finish();
377 return;
378 }
379 onCategoryLoaded();
380 }
381 }, false);
382 }
383
384 protected void onCategoryLoaded() {
385 mWallpaperRotationInitializer = mCategory.getWallpaperRotationInitializer();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700386 fetchWallpapers(false);
387
388 if (mCategory.supportsThirdParty()) {
389 mAppStatusListener = (packageName, status) -> {
390 if (status != PackageStatusNotifier.PackageStatus.REMOVED ||
391 mCategory.containsThirdParty(packageName)) {
392 fetchWallpapers(true);
393 }
394 };
395 mPackageStatusNotifier.addListener(mAppStatusListener,
396 WallpaperService.SERVICE_INTERFACE);
397 }
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700398
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700399 maybeSetUpImageGrid();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700400 }
401
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800402 void fetchWallpapers(boolean forceReload) {
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700403 mWallpapers.clear();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800404 mCategory.fetchWallpapers(getActivity().getApplicationContext(), new WallpaperReceiver() {
405 @Override
406 public void onWallpapersReceived(List<WallpaperInfo> wallpapers) {
407 for (WallpaperInfo wallpaper : wallpapers) {
408 mWallpapers.add(wallpaper);
409 }
410
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700411 // Wallpapers may load after the adapter is initialized, in which case we have
412 // to explicitly notify that the data set has changed.
Jon Miranda16ea1b12017-12-12 14:52:48 -0800413 if (mAdapter != null) {
414 mAdapter.notifyDataSetChanged();
415 }
416
417 if (mWallpapersUiContainer != null) {
418 mWallpapersUiContainer.onWallpapersReady();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700419 } else {
420 if (wallpapers.isEmpty()) {
421 // If there are no more wallpapers and we're on phone, just finish the
422 // Activity.
423 Activity activity = getActivity();
424 if (activity != null
425 && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
426 activity.finish();
427 }
428 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800429 }
430 }
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700431 }, forceReload);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800432 }
433
434 @Override
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700435 public void onSaveInstanceState(@NonNull Bundle outState) {
436 super.onSaveInstanceState(outState);
Santiago Etchebehere0ec065c2019-06-13 11:30:21 -0700437 outState.putInt(KEY_NIGHT_MODE,
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700438 getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK);
439 }
440
441 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800442 public View onCreateView(LayoutInflater inflater, ViewGroup container,
443 Bundle savedInstanceState) {
444 View view = inflater.inflate(R.layout.fragment_individual_picker, container, false);
445
446 mTileSizePx = TileSizeCalculator.getIndividualTileSize(getActivity());
447
448 mImageGrid = (RecyclerView) view.findViewById(R.id.wallpaper_grid);
449 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
450 int gridPaddingPx = getResources().getDimensionPixelSize(R.dimen.grid_padding_desktop);
451 updateImageGridPadding(false /* addExtraBottomSpace */);
452 mImageGrid.setScrollBarSize(gridPaddingPx);
453 }
Chuck Liaoba401232020-03-13 20:11:04 +0800454 mImageGrid.addItemDecoration(new GridPaddingDecoration(
455 getResources().getDimensionPixelSize(R.dimen.grid_padding)));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800456
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700457 maybeSetUpImageGrid();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800458 setUpBottomSheet();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800459 return view;
460 }
461
462 @Override
Chuck Liao8ec38e02020-02-26 20:59:32 +0800463 public void onDestroyView() {
464 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
Chuck Liao69630f12020-03-05 19:01:25 +0800465 updateThumbnail(null);
Chuck Liao8ec38e02020-02-26 20:59:32 +0800466 }
467 super.onDestroyView();
468 }
469
470 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800471 public void onClickTryAgain(@Destination int unused) {
472 if (mPendingSetIndividualHolder != null) {
473 mPendingSetIndividualHolder.setWallpaper();
474 }
475 }
476
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800477 void updateImageGridPadding(boolean addExtraBottomSpace) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800478 int gridPaddingPx = getResources().getDimensionPixelSize(R.dimen.grid_padding_desktop);
479 int bottomSheetHeightPx = getResources().getDimensionPixelSize(
480 R.dimen.current_wallpaper_bottom_sheet_layout_height);
481 int paddingBottomPx = addExtraBottomSpace ? bottomSheetHeightPx : 0;
482 // Only left and top may be set in order for the GridMarginDecoration to work properly.
483 mImageGrid.setPadding(
484 gridPaddingPx, gridPaddingPx, 0, paddingBottomPx);
485 }
486
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700487 private void maybeSetUpImageGrid() {
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700488 // Skip if mImageGrid been initialized yet
489 if (mImageGrid == null) {
490 return;
491 }
492 // Skip if category hasn't loaded yet
493 if (mCategory == null) {
494 return;
495 }
496 // Skip if the adapter was already created
497 if (mAdapter != null) {
498 return;
499 }
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700500 setUpImageGrid();
501 }
502
503 /**
504 * Create the adapter and assign it to mImageGrid.
505 * Both mImageGrid and mCategory are guaranteed to not be null when this method is called.
506 */
507 void setUpImageGrid() {
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800508 mAdapter = new IndividualAdapter(mWallpapers);
509 mImageGrid.setAdapter(mAdapter);
510 mImageGrid.setLayoutManager(new GridLayoutManager(getActivity(), getNumColumns()));
511 }
512
Jon Miranda16ea1b12017-12-12 14:52:48 -0800513 /**
514 * Enables and populates the "Currently set" wallpaper BottomSheet.
515 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800516 void setUpBottomSheet() {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800517 mImageGrid.addOnScrollListener(new OnScrollListener() {
518 @Override
519 public void onScrolled(RecyclerView recyclerView, int dx, final int dy) {
520 if (mCurrentWallpaperBottomSheetPresenter == null) {
521 return;
522 }
523
524 if (mCurrentWallpaperBottomSheetExpandedRunnable != null) {
525 mHandler.removeCallbacks(mCurrentWallpaperBottomSheetExpandedRunnable);
526 }
527 mCurrentWallpaperBottomSheetExpandedRunnable = new Runnable() {
528 @Override
529 public void run() {
530 if (dy > 0) {
531 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(false);
532 } else {
533 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
534 }
535 }
536 };
537 mHandler.postDelayed(mCurrentWallpaperBottomSheetExpandedRunnable, 100);
538 }
539 });
540 }
541
chihhangchuang3efb6832020-04-17 02:06:25 +0800542 @Override
543 protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
Ching-Sung Li073812b2020-04-07 21:19:21 +0800544 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
chihhangchuang3efb6832020-04-17 02:06:25 +0800545 mBottomActionBar = bottomActionBar;
chihhangchuang803ea9a2020-04-21 13:03:10 +0800546 if (isRotationEnabled()) {
chihhangchuang08abb582020-04-27 17:20:31 +0800547 mBottomActionBar.showActionsOnly(ROTATION);
chihhangchuang803ea9a2020-04-21 13:03:10 +0800548 }
Ching-Sung Li073812b2020-04-07 21:19:21 +0800549 mBottomActionBar.setActionClickListener(ROTATION, unused -> {
550 DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
551 startRotationDialogFragment.setTargetFragment(
552 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
553 startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
554 });
555 mBottomActionBar.setActionClickListener(APPLY, unused -> {
556 mBottomActionBar.disableActions();
557 mWallpaperSetter.requestDestination(getActivity(), getFragmentManager(), this,
558 mSelectedWallpaperInfo instanceof LiveWallpaperInfo);
559 });
chihhangchuang1a29e752020-04-28 18:22:53 +0800560
561 mWallpaperInfoView =
562 (WallpaperInfoView) mBottomActionBar.inflateViewToBottomSheetAndBindAction(
563 R.layout.wallpaper_info_view, R.id.wallpaper_info, INFORMATION);
564
Ching-Sung Li073812b2020-04-07 21:19:21 +0800565 mBottomActionBar.show();
Ching-Sung Li073812b2020-04-07 21:19:21 +0800566 }
567 }
568
Jon Miranda16ea1b12017-12-12 14:52:48 -0800569 @Override
570 public void onResume() {
571 super.onResume();
572
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700573 WallpaperPreferences preferences = InjectorProvider.getInjector()
574 .getPreferences(getActivity());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800575 preferences.setLastAppActiveTimestamp(new Date().getTime());
576
577 // Reset Glide memory settings to a "normal" level of usage since it may have been lowered in
578 // PreviewFragment.
579 Glide.get(getActivity()).setMemoryCategory(MemoryCategory.NORMAL);
580
581 // Show the staged 'start rotation' error dialog fragment if there is one that was unable to be
582 // shown earlier when this fragment's hosting activity didn't allow committing fragment
583 // transactions.
584 if (mStagedStartRotationErrorDialogFragment != null) {
585 mStagedStartRotationErrorDialogFragment.show(
586 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
587 mStagedStartRotationErrorDialogFragment = null;
588 }
589
590 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one
591 // that was unable to be shown earlier when this fragment's hosting activity didn't allow
592 // committing fragment transactions.
593 if (mStagedSetWallpaperErrorDialogFragment != null) {
594 mStagedSetWallpaperErrorDialogFragment.show(
595 getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
596 mStagedSetWallpaperErrorDialogFragment = null;
597 }
598
599 if (isRotationEnabled()) {
600 if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
601 // Refresh the state of the "start rotation" in case something changed the current daily
602 // rotation while this fragment was paused.
603 RotationHolder rotationHolder = (RotationHolder) mImageGrid
604 .findViewHolderForAdapterPosition(
605 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
606 // The RotationHolder may be null if the RecyclerView has not created the view
607 // holder yet.
608 if (rotationHolder != null && Flags.dynamicStartRotationTileEnabled) {
609 refreshRotationHolder(rotationHolder);
610 }
611 } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
612 if (mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
613 // Must be resuming from a previously stopped state, so re-schedule the update of the
614 // daily wallpapers tile thumbnail.
615 mUpdateDailyWallpaperThumbRunnable.run();
616 }
617 }
618 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800619 }
620
621 @Override
622 public void onStop() {
623 super.onStop();
624 mHandler.removeCallbacks(mUpdateDailyWallpaperThumbRunnable);
625 }
626
627 @Override
628 public void onDestroy() {
629 super.onDestroy();
630 if (mProgressDialog != null) {
631 mProgressDialog.dismiss();
632 }
633 mWallpaperChangedNotifier.unregisterListener(mWallpaperChangedListener);
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700634 if (mAppStatusListener != null) {
635 mPackageStatusNotifier.removeListener(mAppStatusListener);
636 }
Chuck Liao69630f12020-03-05 19:01:25 +0800637 mWallpaperSetter.cleanUp();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800638 }
639
640 @Override
641 public void retryStartRotation(@NetworkPreference int networkPreference) {
642 startRotation(networkPreference);
643 }
644
chihhangchuang7feb3752020-04-24 02:48:56 +0800645 @Override
646 public boolean onBackPressed() {
647 if (mSelectedWallpaperInfo != null) {
648 onWallpaperSelected(null, 0);
649 return true;
650 }
651 return false;
652 }
653
Jon Miranda16ea1b12017-12-12 14:52:48 -0800654 public void setCurrentWallpaperBottomSheetPresenter(
655 CurrentWallpaperBottomSheetPresenter presenter) {
656 mCurrentWallpaperBottomSheetPresenter = presenter;
657 }
658
659 public void setWallpapersUiContainer(WallpapersUiContainer uiContainer) {
660 mWallpapersUiContainer = uiContainer;
661 }
662
Chuck Liaob3829fb2020-04-01 00:47:50 +0800663 public void setOnWallpaperSelectedListener(
664 WallpaperSelectedListener wallpaperSelectedListener) {
665 mWallpaperSelectedListener = wallpaperSelectedListener;
666 }
667
668 /**
669 * Resizes the layout's height.
670 */
671 public void resizeLayout(int height) {
672 mImageGrid.getLayoutParams().height = height;
673 mImageGrid.requestLayout();
674 }
675
676 /**
677 * Scrolls to the specific item.
678 *
679 * @param position the position of the item
680 */
681 public void scrollToPosition(int position) {
682 ((GridLayoutManager) mImageGrid.getLayoutManager())
683 .scrollToPositionWithOffset(position, /* offset= */ 0);
684 }
685
Jon Miranda16ea1b12017-12-12 14:52:48 -0800686 /**
687 * Enable a test mode of operation -- in which certain UI features are disabled to allow for
688 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog
689 * constantly keeps the UI thread alive and blocks a test forever.
690 *
691 * @param testingMode
692 */
693 void setTestingMode(boolean testingMode) {
694 mTestingMode = testingMode;
695 }
696
697 /**
698 * Asynchronously fetches the refreshed rotation initialization state that is up to date with the
699 * state of the user's device and binds the state of the current category's rotation to the "start
700 * rotation" tile.
701 */
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700702 private void refreshRotationHolder(RotationHolder rotationHolder) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800703 mWallpaperRotationInitializer.fetchRotationInitializationState(getContext(),
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700704 rotationState -> {
705 // Update the UI state of the "start rotation" tile displayed on screen.
706 // Do this in a Handler so it is scheduled at the end of the message queue.
707 // This is necessary to ensure we do not remove or add data from the adapter
708 // while the layout is still being computed. RecyclerView documentation
709 // therefore recommends performing such changes in a Handler.
710 new Handler().post(() -> {
711 // A config change may have destroyed the activity since the refresh
712 // started, so check for that to avoid an NPE.
713 if (getActivity() == null) {
714 return;
715 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800716
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700717 rotationHolder.bindRotationInitializationState(rotationState);
718 });
Jon Miranda16ea1b12017-12-12 14:52:48 -0800719 });
720 }
721
722 @Override
723 public void startRotation(@NetworkPreference final int networkPreference) {
724 if (!isRotationEnabled()) {
725 Log.e(TAG, "Rotation is not enabled for this category " + mCategory.getTitle());
726 return;
727 }
728
729 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
730 // causes Espresso to hang once the dialog is shown.
731 if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE && !mTestingMode) {
732 int themeResId;
733 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
734 themeResId = R.style.ProgressDialogThemePreL;
735 } else {
736 themeResId = R.style.LightDialogTheme;
737 }
738 mProgressDialog = new ProgressDialog(getActivity(), themeResId);
739
740 mProgressDialog.setTitle(PROGRESS_DIALOG_NO_TITLE);
741 mProgressDialog.setMessage(
742 getResources().getString(R.string.start_rotation_progress_message));
743 mProgressDialog.setIndeterminate(PROGRESS_DIALOG_INDETERMINATE);
744 mProgressDialog.show();
745 }
746
747 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
748 mAdapter.mPendingSelectedAdapterPosition = SPECIAL_FIXED_TILE_ADAPTER_POSITION;
749 }
750
751 final Context appContext = getActivity().getApplicationContext();
752
753 mWallpaperRotationInitializer.setFirstWallpaperInRotation(
754 appContext,
755 networkPreference,
756 new Listener() {
757 @Override
758 public void onFirstWallpaperInRotationSet() {
759 if (mProgressDialog != null) {
760 mProgressDialog.dismiss();
761 }
762
763 // The fragment may be detached from its containing activity if the user exits the
764 // app before the first wallpaper image in rotation finishes downloading.
765 Activity activity = getActivity();
766
Jon Miranda16ea1b12017-12-12 14:52:48 -0800767
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700768 if (mWallpaperRotationInitializer.startRotation(appContext)) {
769 if (activity != null
770 && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
771 try {
772 Toast.makeText(getActivity(),
773 R.string.wallpaper_set_successfully_message,
774 Toast.LENGTH_SHORT).show();
775 } catch (NotFoundException e) {
776 Log.e(TAG, "Could not show toast " + e);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800777 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800778
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700779 activity.setResult(Activity.RESULT_OK);
780 activity.finish();
781 } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
782 mAdapter.updateSelectedTile(SPECIAL_FIXED_TILE_ADAPTER_POSITION);
783 }
784 } else { // Failed to start rotation.
785 showStartRotationErrorDialog(networkPreference);
786
787 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
788 DesktopRotationHolder rotationViewHolder =
789 (DesktopRotationHolder)
790 mImageGrid.findViewHolderForAdapterPosition(
791 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
792 rotationViewHolder.setSelectionState(
793 SelectableHolder.SELECTION_STATE_DESELECTED);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800794 }
795 }
796 }
797
798 @Override
799 public void onError() {
800 if (mProgressDialog != null) {
801 mProgressDialog.dismiss();
802 }
803
804 showStartRotationErrorDialog(networkPreference);
805
806 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
807 DesktopRotationHolder rotationViewHolder =
808 (DesktopRotationHolder) mImageGrid.findViewHolderForAdapterPosition(
809 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
810 rotationViewHolder.setSelectionState(SelectableHolder.SELECTION_STATE_DESELECTED);
811 }
812 }
813 });
814 }
815
816 private void showStartRotationErrorDialog(@NetworkPreference int networkPreference) {
817 BaseActivity activity = (BaseActivity) getActivity();
818 if (activity != null) {
819 StartRotationErrorDialogFragment startRotationErrorDialogFragment =
820 StartRotationErrorDialogFragment.newInstance(networkPreference);
821 startRotationErrorDialogFragment.setTargetFragment(
822 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
823
824 if (activity.isSafeToCommitFragmentTransaction()) {
825 startRotationErrorDialogFragment.show(
826 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
827 } else {
828 mStagedStartRotationErrorDialogFragment = startRotationErrorDialogFragment;
829 }
830 }
831 }
832
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800833 int getNumColumns() {
Ching-Sung Li9df77a32019-07-10 11:45:30 +0800834 Activity activity = getActivity();
835 return activity == null ? 0 : TileSizeCalculator.getNumIndividualColumns(activity);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800836 }
837
838 /**
839 * Returns whether rotation is enabled for this category.
840 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800841 boolean isRotationEnabled() {
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700842 return mWallpaperRotationInitializer != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800843 }
844
845 @Override
846 public void onCurrentWallpaperRefreshed() {
847 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
848 }
849
Chuck Liao69630f12020-03-05 19:01:25 +0800850
851 @Override
852 public void onSet(int destination) {
853 if (mSelectedWallpaperInfo == null) {
854 Log.e(TAG, "Unable to set wallpaper since the selected wallpaper info is null");
855 return;
856 }
857
“Chuckffd832c2020-03-22 02:15:58 +0800858 mWallpaperPersister.setWallpaperInfoInPreview(mSelectedWallpaperInfo);
Chuck Liao69630f12020-03-05 19:01:25 +0800859 if (mSelectedWallpaperInfo instanceof LiveWallpaperInfo) {
860 mWallpaperSetter.setCurrentWallpaper(getActivity(), mSelectedWallpaperInfo, null,
861 destination, 0, null, mSetWallpaperCallback);
862 } else {
863 mWallpaperSetter.setCurrentWallpaper(
864 getActivity(), mSelectedWallpaperInfo, destination, mSetWallpaperCallback);
865 }
“Chuck7ef99722020-03-22 04:34:03 +0800866 onWallpaperDestinationSet(destination);
Chuck Liao69630f12020-03-05 19:01:25 +0800867 }
868
869 private WallpaperPersister.SetWallpaperCallback mSetWallpaperCallback =
870 new WallpaperPersister.SetWallpaperCallback() {
871 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800872 public void onSuccess(WallpaperInfo wallpaperInfo) {
Chuck Liao6e52fff2020-04-23 16:11:23 +0800873 Toast.makeText(getActivity(), R.string.wallpaper_set_successfully_message,
874 Toast.LENGTH_SHORT).show();
Chuck Liao69630f12020-03-05 19:01:25 +0800875 mBottomActionBar.enableActions();
Chuck Liao11f4a762020-04-08 13:24:43 +0800876 refreshAppliedWallpaper();
“Chuckffd832c2020-03-22 02:15:58 +0800877
878 mWallpaperPersister.onLiveWallpaperSet();
Chuck Liao69630f12020-03-05 19:01:25 +0800879 }
880
881 @Override
882 public void onError(@Nullable Throwable throwable) {
883 Log.e(TAG, "Can't apply the wallpaper.");
884 mBottomActionBar.enableActions();
885 }
886 };
887
888 @Override
889 public void onDialogDismissed(boolean withItemSelected) {
890 if (!withItemSelected) {
891 mBottomActionBar.enableActions();
892 }
893 }
894
Jon Miranda16ea1b12017-12-12 14:52:48 -0800895 /**
896 * Shows a "set wallpaper" error dialog with a failure message and button to try again.
897 */
898 private void showSetWallpaperErrorDialog() {
899 SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance(
900 R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH);
901 dialogFragment.setTargetFragment(this, UNUSED_REQUEST_CODE);
902
903 if (((BaseActivity) getActivity()).isSafeToCommitFragmentTransaction()) {
904 dialogFragment.show(getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
905 } else {
906 mStagedSetWallpaperErrorDialogFragment = dialogFragment;
907 }
908 }
909
Ching-Sung Li073812b2020-04-07 21:19:21 +0800910 void updateBottomActions(boolean hasWallpaperSelected) {
chihhangchuang803ea9a2020-04-21 13:03:10 +0800911 if (hasWallpaperSelected) {
chihhangchuang08abb582020-04-27 17:20:31 +0800912 mBottomActionBar.showActionsOnly(INFORMATION, APPLY);
chihhangchuang803ea9a2020-04-21 13:03:10 +0800913 } else {
chihhangchuang08abb582020-04-27 17:20:31 +0800914 mBottomActionBar.showActionsOnly(ROTATION);
chihhangchuang803ea9a2020-04-21 13:03:10 +0800915 }
Chuck Liao69630f12020-03-05 19:01:25 +0800916 }
917
918 private void updateThumbnail(WallpaperInfo selectedWallpaperInfo) {
Chuck Liaof40063f2020-03-03 18:35:24 +0800919 ThumbnailUpdater thumbnailUpdater = (ThumbnailUpdater) getParentFragment();
Chuck Liao69630f12020-03-05 19:01:25 +0800920 if (thumbnailUpdater == null) {
921 return;
922 }
923
924 if (selectedWallpaperInfo != null) {
925 thumbnailUpdater.updateThumbnail(selectedWallpaperInfo);
926 } else {
927 thumbnailUpdater.restoreThumbnails();
Chuck Liaof40063f2020-03-03 18:35:24 +0800928 }
929 }
930
“Chuck7ef99722020-03-22 04:34:03 +0800931 private void onWallpaperDestinationSet(int destination) {
932 WallpaperDestinationCallback wallpaperDestinationCallback =
933 (WallpaperDestinationCallback) getParentFragment();
934 if (wallpaperDestinationCallback == null) {
935 return;
936 }
937
938 wallpaperDestinationCallback.onDestinationSet(destination);
939 }
940
Ching-Sung Li073812b2020-04-07 21:19:21 +0800941 void onWallpaperSelected(@Nullable WallpaperInfo newSelectedWallpaperInfo,
Chuck Liaob3829fb2020-04-01 00:47:50 +0800942 int position) {
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800943 if (mSelectedWallpaperInfo == newSelectedWallpaperInfo) {
“Chuckffd832c2020-03-22 02:15:58 +0800944 return;
945 }
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800946 // Update current wallpaper.
“Chuckffd832c2020-03-22 02:15:58 +0800947 updateActivatedStatus(mSelectedWallpaperInfo == null
948 ? mAppliedWallpaperInfo : mSelectedWallpaperInfo, false);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800949 // Update new selected wallpaper.
950 updateActivatedStatus(newSelectedWallpaperInfo == null
951 ? mAppliedWallpaperInfo : newSelectedWallpaperInfo, true);
952
953 mSelectedWallpaperInfo = newSelectedWallpaperInfo;
954 updateBottomActions(mSelectedWallpaperInfo != null);
955 updateThumbnail(mSelectedWallpaperInfo);
chihhangchuangde9e8722020-05-02 17:22:13 +0800956 // Populate wallpaper info into view.
chihhangchuang1a29e752020-04-28 18:22:53 +0800957 if (mSelectedWallpaperInfo != null && mWallpaperInfoView != null) {
chihhangchuangc687d912020-05-04 14:33:05 +0800958 WallpaperInfoHelper.loadExploreIntent(
959 getContext(),
960 mSelectedWallpaperInfo,
961 (actionLabel, exploreIntent) ->
962 mWallpaperInfoView.populateWallpaperInfo(
963 mSelectedWallpaperInfo, actionLabel, exploreIntent,
964 v -> onExploreClicked(exploreIntent)));
Chuck Liaob3829fb2020-04-01 00:47:50 +0800965 }
966
967 if (mWallpaperSelectedListener != null) {
968 mWallpaperSelectedListener.onWallpaperSelected(position);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800969 }
Chuck Liaof40063f2020-03-03 18:35:24 +0800970 }
971
chihhangchuangc687d912020-05-04 14:33:05 +0800972 private void onExploreClicked(Intent exploreIntent) {
973 if (getContext() == null) {
974 return;
975 }
976 Context context = getContext();
977 mUserEventLogger.logActionClicked(mSelectedWallpaperInfo.getCollectionId(context),
978 mSelectedWallpaperInfo.getActionLabelRes(context));
979
980 startActivity(exploreIntent);
981 }
982
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800983 private void updateActivatedStatus(WallpaperInfo wallpaperInfo, boolean isActivated) {
“Chuckffd832c2020-03-22 02:15:58 +0800984 if (wallpaperInfo == null) {
985 return;
986 }
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800987 int index = mWallpapers.indexOf(wallpaperInfo);
988 index = (isRotationEnabled() || mCategory.supportsCustomPhotos())
989 ? index + 1 : index;
990 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
991 if (holder != null) {
992 holder.itemView.setActivated(isActivated);
993 } else {
994 // Item is not visible, make sure the item is re-bound when it becomes visible.
995 mAdapter.notifyItemChanged(index);
996 }
997 }
998
“Chuckffd832c2020-03-22 02:15:58 +0800999 private void updateAppliedStatus(WallpaperInfo wallpaperInfo, boolean isApplied) {
1000 if (wallpaperInfo == null) {
1001 return;
1002 }
1003 int index = mWallpapers.indexOf(wallpaperInfo);
1004 index = (isRotationEnabled() || mCategory.supportsCustomPhotos())
1005 ? index + 1 : index;
1006 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
1007 if (holder != null) {
1008 holder.itemView.findViewById(R.id.check_circle)
1009 .setVisibility(isApplied ? View.VISIBLE : View.GONE);
1010 } else {
1011 // Item is not visible, make sure the item is re-bound when it becomes visible.
1012 mAdapter.notifyItemChanged(index);
1013 }
1014 }
1015
Chuck Liao11f4a762020-04-08 13:24:43 +08001016 private void refreshAppliedWallpaper() {
1017 // Clear the check mark and blue border(if it shows) of the old applied wallpaper.
1018 showCheckMarkAndBorderForAppliedWallpaper(false);
1019
1020 // Update to the new applied wallpaper.
1021 String appliedWallpaperId = getAppliedWallpaperId();
1022 Optional<WallpaperInfo> wallpaperInfoOptional = mWallpapers
1023 .stream()
1024 .filter(wallpaper -> wallpaper.getWallpaperId() != null)
1025 .filter(wallpaper -> wallpaper.getWallpaperId().equals(appliedWallpaperId))
1026 .findFirst();
1027 mAppliedWallpaperInfo = wallpaperInfoOptional.orElse(null);
1028
1029 // Set the check mark and blue border(if user doesn't select) of the new applied wallpaper.
1030 showCheckMarkAndBorderForAppliedWallpaper(true);
1031 }
1032
1033 private String getAppliedWallpaperId() {
1034 WallpaperPreferences prefs =
1035 InjectorProvider.getInjector().getPreferences(getContext());
1036 android.app.WallpaperInfo wallpaperInfo = mWallpaperManager.getWallpaperInfo();
1037 boolean isDestinationBoth =
1038 mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK) < 0;
1039
1040 if (isDestinationBoth || mWallpaperDestination == WallpaperPersister.DEST_HOME_SCREEN) {
1041 return wallpaperInfo != null
1042 ? wallpaperInfo.getServiceName() : prefs.getHomeWallpaperRemoteId();
1043 } else {
1044 return prefs.getLockWallpaperRemoteId();
1045 }
1046 }
1047
1048 private void showCheckMarkAndBorderForAppliedWallpaper(boolean show) {
1049 updateAppliedStatus(mAppliedWallpaperInfo, show);
1050 if (mSelectedWallpaperInfo == null) {
1051 updateActivatedStatus(mAppliedWallpaperInfo, show);
1052 }
1053 }
1054
Jon Miranda16ea1b12017-12-12 14:52:48 -08001055 /**
1056 * ViewHolder subclass for "daily refresh" tile in the RecyclerView, only shown if rotation is
1057 * enabled for this category.
1058 */
1059 private class RotationHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
1060
Chuck Liaoba401232020-03-13 20:11:04 +08001061 private CardView mTileLayout;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001062 private TextView mRotationMessage;
1063 private TextView mRotationTitle;
1064 private ImageView mRefreshIcon;
1065
1066 RotationHolder(View itemView) {
1067 super(itemView);
1068 itemView.setOnClickListener(this);
1069
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -07001070 mTileLayout = itemView.findViewById(R.id.daily_refresh);
1071 mRotationMessage = itemView.findViewById(R.id.rotation_tile_message);
1072 mRotationTitle = itemView.findViewById(R.id.rotation_tile_title);
1073 mRefreshIcon = itemView.findViewById(R.id.rotation_tile_refresh_icon);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001074 mTileLayout.getLayoutParams().height = mTileSizePx.y;
1075
1076 // If the feature flag for "dynamic start rotation tile" is not enabled, fall back to the
1077 // static UI with a blue accent color background and "Tap to turn on" text.
1078 if (!Flags.dynamicStartRotationTileEnabled) {
1079 mTileLayout.setBackgroundColor(
1080 getResources().getColor(R.color.rotation_tile_enabled_background_color));
1081 mRotationMessage.setText(R.string.daily_refresh_tile_subtitle);
1082 mRotationTitle.setTextColor(
1083 getResources().getColor(R.color.rotation_tile_enabled_title_text_color));
1084 mRotationMessage.setTextColor(
1085 getResources().getColor(R.color.rotation_tile_enabled_subtitle_text_color));
1086 mRefreshIcon.setColorFilter(
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -07001087 getResources().getColor(R.color.rotation_tile_enabled_refresh_icon_color),
1088 Mode.SRC_IN);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001089 return;
1090 }
1091
1092 // Initialize the state of the "start rotation" tile (i.e., whether it is gray or blue to
1093 // indicate if rotation is turned on for the current category) with last-known rotation state
1094 // that could be stale. The last-known rotation state is correct in most cases and is a good
1095 // starting point but may not be accurate if the user set a wallpaper through a 3rd party app
1096 // while this app was paused.
1097 int rotationState = mWallpaperRotationInitializer.getRotationInitializationStateDirty(
1098 getContext());
1099 bindRotationInitializationState(rotationState);
1100 }
1101
1102 @Override
1103 public void onClick(View v) {
Samuel Fufa03bc6ac2019-09-19 12:01:50 -07001104 DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
Jon Miranda16ea1b12017-12-12 14:52:48 -08001105 startRotationDialogFragment.setTargetFragment(
1106 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
1107 startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
1108 }
1109
1110 /**
1111 * Binds the provided rotation initialization state to the RotationHolder and updates the tile's
1112 * UI to be in sync with the state (i.e., message and color appropriately reflect the state to
1113 * the user).
1114 */
1115 void bindRotationInitializationState(@RotationInitializationState int rotationState) {
1116 int newBackgroundColor =
1117 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1118 ? getResources().getColor(R.color.rotation_tile_not_enabled_background_color)
1119 : getResources().getColor(R.color.rotation_tile_enabled_background_color);
1120 int newTitleTextColor =
1121 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1122 ? getResources().getColor(R.color.rotation_tile_not_enabled_title_text_color)
1123 : getResources().getColor(R.color.rotation_tile_enabled_title_text_color);
1124 int newSubtitleTextColor =
1125 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1126 ? getResources().getColor(R.color.rotation_tile_not_enabled_subtitle_text_color)
1127 : getResources().getColor(R.color.rotation_tile_enabled_subtitle_text_color);
1128 int newRefreshIconColor =
1129 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1130 ? getResources().getColor(R.color.rotation_tile_not_enabled_refresh_icon_color)
1131 : getResources().getColor(R.color.rotation_tile_enabled_refresh_icon_color);
1132
Chuck Liaoba401232020-03-13 20:11:04 +08001133 mTileLayout.setCardBackgroundColor(newBackgroundColor);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001134 mRotationTitle.setTextColor(newTitleTextColor);
1135 mRotationMessage.setText(getResIdForRotationState(rotationState));
1136 mRotationMessage.setTextColor(newSubtitleTextColor);
1137 mRefreshIcon.setColorFilter(newRefreshIconColor, Mode.SRC_IN);
1138 }
1139 }
1140
1141 /**
1142 * RecyclerView Adapter subclass for the wallpaper tiles in the RecyclerView.
1143 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001144 class IndividualAdapter extends RecyclerView.Adapter<ViewHolder> {
1145 static final int ITEM_VIEW_TYPE_ROTATION = 1;
1146 static final int ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER = 2;
1147 static final int ITEM_VIEW_TYPE_MY_PHOTOS = 3;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001148
1149 private final List<WallpaperInfo> mWallpapers;
1150
1151 private int mPendingSelectedAdapterPosition;
1152 private int mSelectedAdapterPosition;
1153
1154 IndividualAdapter(List<WallpaperInfo> wallpapers) {
1155 mWallpapers = wallpapers;
1156 mPendingSelectedAdapterPosition = -1;
1157 mSelectedAdapterPosition = -1;
1158 }
1159
1160 @Override
1161 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
1162 switch (viewType) {
1163 case ITEM_VIEW_TYPE_ROTATION:
1164 return createRotationHolder(parent);
1165 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1166 return createIndividualHolder(parent);
1167 case ITEM_VIEW_TYPE_MY_PHOTOS:
1168 return createMyPhotosHolder(parent);
1169 default:
1170 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1171 return null;
1172 }
1173 }
1174
1175 @Override
1176 public int getItemViewType(int position) {
1177 if (isRotationEnabled() && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
1178 return ITEM_VIEW_TYPE_ROTATION;
1179 }
1180
1181 // A category cannot have both a "start rotation" tile and a "my photos" tile.
1182 if (mCategory.supportsCustomPhotos()
1183 && !isRotationEnabled()
1184 && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
1185 return ITEM_VIEW_TYPE_MY_PHOTOS;
1186 }
1187
1188 return ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER;
1189 }
1190
1191 @Override
1192 public void onBindViewHolder(ViewHolder holder, int position) {
1193 int viewType = getItemViewType(position);
1194
1195 switch (viewType) {
1196 case ITEM_VIEW_TYPE_ROTATION:
1197 onBindRotationHolder(holder, position);
1198 break;
1199 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1200 onBindIndividualHolder(holder, position);
1201 break;
1202 case ITEM_VIEW_TYPE_MY_PHOTOS:
1203 ((MyPhotosViewHolder) holder).bind();
1204 break;
1205 default:
1206 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1207 }
1208 }
1209
1210 @Override
1211 public int getItemCount() {
1212 return (isRotationEnabled() || mCategory.supportsCustomPhotos())
1213 ? mWallpapers.size() + 1
1214 : mWallpapers.size();
1215 }
1216
1217 private ViewHolder createRotationHolder(ViewGroup parent) {
1218 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1219 View view;
1220
1221 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1222 view = layoutInflater.inflate(R.layout.grid_item_rotation_desktop, parent, false);
1223 SelectionAnimator selectionAnimator =
1224 new CheckmarkSelectionAnimator(getActivity(), view);
1225 return new DesktopRotationHolder(
1226 getActivity(), mTileSizePx.y, view, selectionAnimator,
1227 IndividualPickerFragment.this);
1228 } else { // MOBILE
1229 view = layoutInflater.inflate(R.layout.grid_item_rotation, parent, false);
1230 return new RotationHolder(view);
1231 }
1232 }
1233
1234 private ViewHolder createIndividualHolder(ViewGroup parent) {
1235 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1236 View view = layoutInflater.inflate(R.layout.grid_item_image, parent, false);
Chuck Liao6a37a1c2020-03-07 03:39:43 +08001237 if (!TEMP_BOTTOM_ACTION_BAR_FEATURE) {
1238 view.findViewById(R.id.tile).setPadding(0, 0, 0, 0);
1239 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001240
1241 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1242 SelectionAnimator selectionAnimator =
1243 new CheckmarkSelectionAnimator(getActivity(), view);
1244 return new SetIndividualHolder(
1245 getActivity(), mTileSizePx.y, view,
1246 selectionAnimator,
1247 new OnSetListener() {
1248 @Override
1249 public void onPendingWallpaperSet(int adapterPosition) {
1250 // Deselect and hide loading indicator for any previously pending tile.
1251 if (mPendingSelectedAdapterPosition != -1) {
1252 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1253 mPendingSelectedAdapterPosition);
1254 if (oldViewHolder instanceof SelectableHolder) {
1255 ((SelectableHolder) oldViewHolder).setSelectionState(
1256 SelectableHolder.SELECTION_STATE_DESELECTED);
1257 }
1258 }
1259
1260 if (mSelectedAdapterPosition != -1) {
1261 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1262 mSelectedAdapterPosition);
1263 if (oldViewHolder instanceof SelectableHolder) {
1264 ((SelectableHolder) oldViewHolder).setSelectionState(
1265 SelectableHolder.SELECTION_STATE_DESELECTED);
1266 }
1267 }
1268
1269 mPendingSelectedAdapterPosition = adapterPosition;
1270 }
1271
1272 @Override
1273 public void onWallpaperSet(int adapterPosition) {
1274 // No-op -- UI handles a new wallpaper being set by reacting to the
1275 // WallpaperChangedNotifier.
1276 }
1277
1278 @Override
1279 public void onWallpaperSetFailed(SetIndividualHolder holder) {
1280 showSetWallpaperErrorDialog();
1281 mPendingSetIndividualHolder = holder;
1282 }
1283 });
1284 } else { // MOBILE
Chuck Liao3d1a51c2020-02-17 18:29:34 +08001285 return new PreviewIndividualHolder(getActivity(), mTileSizePx.y, view);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001286 }
1287 }
1288
1289 private ViewHolder createMyPhotosHolder(ViewGroup parent) {
1290 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1291 View view = layoutInflater.inflate(R.layout.grid_item_my_photos, parent, false);
1292
Santiago Etchebeherefab49612019-01-15 12:22:42 -08001293 return new MyPhotosViewHolder(getActivity(),
1294 ((MyPhotosStarterProvider) getActivity()).getMyPhotosStarter(),
1295 mTileSizePx.y, view);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001296 }
1297
1298 /**
1299 * Marks the tile at the given position as selected with a visual indication. Also updates the
1300 * "currently selected" BottomSheet to reflect the newly selected tile.
1301 */
1302 private void updateSelectedTile(int newlySelectedPosition) {
1303 // Prevent multiple spinners from appearing with a user tapping several tiles in rapid
1304 // succession.
1305 if (mPendingSelectedAdapterPosition == mSelectedAdapterPosition) {
1306 return;
1307 }
1308
1309 if (mCurrentWallpaperBottomSheetPresenter != null) {
1310 mCurrentWallpaperBottomSheetPresenter.refreshCurrentWallpapers(
1311 IndividualPickerFragment.this);
1312
1313 if (mCurrentWallpaperBottomSheetExpandedRunnable != null) {
1314 mHandler.removeCallbacks(mCurrentWallpaperBottomSheetExpandedRunnable);
1315 }
1316 mCurrentWallpaperBottomSheetExpandedRunnable = new Runnable() {
1317 @Override
1318 public void run() {
1319 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
1320 }
1321 };
1322 mHandler.postDelayed(mCurrentWallpaperBottomSheetExpandedRunnable, 100);
1323 }
1324
1325 // User may have switched to another category, thus detaching this fragment, so check here.
1326 // NOTE: We do this check after updating the current wallpaper BottomSheet so that the update
1327 // still occurs in the UI after the user selects that other category.
1328 if (getActivity() == null) {
1329 return;
1330 }
1331
1332 // Update the newly selected wallpaper ViewHolder and the old one so that if
1333 // selection UI state applies (desktop UI), it is updated.
1334 if (mSelectedAdapterPosition >= 0) {
1335 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1336 mSelectedAdapterPosition);
1337 if (oldViewHolder instanceof SelectableHolder) {
1338 ((SelectableHolder) oldViewHolder).setSelectionState(
1339 SelectableHolder.SELECTION_STATE_DESELECTED);
1340 }
1341 }
1342
1343 // Animate selection of newly selected tile.
1344 ViewHolder newViewHolder = mImageGrid
1345 .findViewHolderForAdapterPosition(newlySelectedPosition);
1346 if (newViewHolder instanceof SelectableHolder) {
1347 ((SelectableHolder) newViewHolder).setSelectionState(
1348 SelectableHolder.SELECTION_STATE_SELECTED);
1349 }
1350
1351 mSelectedAdapterPosition = newlySelectedPosition;
1352
1353 // If the tile was in the last row of the grid, add space below it so the user can scroll down
1354 // and up to see the BottomSheet without it fully overlapping the newly selected tile.
1355 int spanCount = ((GridLayoutManager) mImageGrid.getLayoutManager()).getSpanCount();
1356 int numRows = (int) Math.ceil((float) getItemCount() / spanCount);
1357 int rowOfNewlySelectedTile = newlySelectedPosition / spanCount;
1358 boolean isInLastRow = rowOfNewlySelectedTile == numRows - 1;
1359
1360 updateImageGridPadding(isInLastRow /* addExtraBottomSpace */);
1361 }
1362
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001363 void onBindRotationHolder(ViewHolder holder, int position) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001364 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1365 String collectionId = mCategory.getCollectionId();
1366 ((DesktopRotationHolder) holder).bind(collectionId);
1367
1368 if (mWallpaperPreferences.getWallpaperPresentationMode()
1369 == WallpaperPreferences.PRESENTATION_MODE_ROTATING
1370 && collectionId.equals(mWallpaperPreferences.getHomeWallpaperCollectionId())) {
1371 mSelectedAdapterPosition = position;
1372 }
1373
1374 if (!mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
1375 updateDesktopDailyRotationThumbnail((DesktopRotationHolder) holder);
1376 mWasUpdateRunnableRun = true;
1377 }
1378 }
1379 }
1380
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001381 void onBindIndividualHolder(ViewHolder holder, int position) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001382 int wallpaperIndex = (isRotationEnabled() || mCategory.supportsCustomPhotos())
1383 ? position - 1 : position;
1384 WallpaperInfo wallpaper = mWallpapers.get(wallpaperIndex);
1385 ((IndividualHolder) holder).bindWallpaper(wallpaper);
“Chuck7ef99722020-03-22 04:34:03 +08001386 String appliedWallpaperId = getAppliedWallpaperId();
“Chuckffd832c2020-03-22 02:15:58 +08001387 boolean isWallpaperApplied = wallpaper.getWallpaperId().equals(appliedWallpaperId);
1388 boolean isWallpaperSelected = wallpaper.equals(mSelectedWallpaperInfo);
1389 boolean hasUserSelectedWallpaper = mSelectedWallpaperInfo != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001390
“Chuckffd832c2020-03-22 02:15:58 +08001391 if (isWallpaperApplied) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001392 mSelectedAdapterPosition = position;
“Chuckffd832c2020-03-22 02:15:58 +08001393 mAppliedWallpaperInfo = wallpaper;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001394 }
Chuck Liaof40063f2020-03-03 18:35:24 +08001395
1396 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
“Chuckffd832c2020-03-22 02:15:58 +08001397 holder.itemView.setActivated(
1398 (isWallpaperApplied && !hasUserSelectedWallpaper) || isWallpaperSelected);
1399 holder.itemView.findViewById(R.id.check_circle).setVisibility(
1400 isWallpaperApplied ? View.VISIBLE : View.GONE);
Chuck Liao69630f12020-03-05 19:01:25 +08001401 holder.itemView.findViewById(R.id.tile).setOnClickListener(
Chuck Liaob3829fb2020-04-01 00:47:50 +08001402 view -> onWallpaperSelected(wallpaper, position));
Chuck Liaof40063f2020-03-03 18:35:24 +08001403 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001404 }
1405 }
Chuck Liaoba401232020-03-13 20:11:04 +08001406
1407 private class GridPaddingDecoration extends RecyclerView.ItemDecoration {
1408
1409 private int mPadding;
1410
1411 GridPaddingDecoration(int padding) {
1412 mPadding = padding;
1413 }
1414
1415 @Override
1416 public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
1417 RecyclerView.State state) {
1418 int position = parent.getChildAdapterPosition(view);
1419 if (position >= 0) {
1420 outRect.left = mPadding;
1421 outRect.right = mPadding;
1422 }
1423 }
1424 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001425}