blob: d87049c73a65c5b068bdeac121f9d70daa3db9f2 [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 Liao7dc21572020-05-14 18:37:36 +080018import static com.android.wallpaper.picker.WallpaperPickerDelegate.PREVIEW_WALLPAPER_REQUEST_CODE;
Chuck Liao69630f12020-03-05 19:01:25 +080019import static com.android.wallpaper.widget.BottomActionBar.BottomAction.APPLY;
Chuck Liao7dc21572020-05-14 18:37:36 +080020import static com.android.wallpaper.widget.BottomActionBar.BottomAction.EDIT;
chihhangchuang22aa0cc2020-03-25 19:12:42 +080021import static com.android.wallpaper.widget.BottomActionBar.BottomAction.INFORMATION;
Chuck Liao8ec38e02020-02-26 20:59:32 +080022import static com.android.wallpaper.widget.BottomActionBar.BottomAction.ROTATION;
23
Jon Miranda16ea1b12017-12-12 14:52:48 -080024import android.app.Activity;
25import android.app.ProgressDialog;
“Chuck7ef99722020-03-22 04:34:03 +080026import android.app.WallpaperManager;
Jon Miranda16ea1b12017-12-12 14:52:48 -080027import android.content.Context;
Chihhang Chuang85f099a2020-06-16 18:04:39 +080028import android.content.DialogInterface;
chihhangchuangc687d912020-05-04 14:33:05 +080029import android.content.Intent;
Santiago Etchebehereb1854472019-06-06 17:44:54 -070030import android.content.res.Configuration;
Jon Miranda16ea1b12017-12-12 14:52:48 -080031import android.content.res.Resources.NotFoundException;
32import android.graphics.Point;
Chuck Liaoba401232020-03-13 20:11:04 +080033import android.graphics.Rect;
Jon Miranda16ea1b12017-12-12 14:52:48 -080034import android.os.Build.VERSION;
35import android.os.Build.VERSION_CODES;
36import android.os.Bundle;
37import android.os.Handler;
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -070038import android.service.wallpaper.WallpaperService;
Jon Miranda16ea1b12017-12-12 14:52:48 -080039import android.util.Log;
40import android.view.LayoutInflater;
41import android.view.View;
42import android.view.ViewGroup;
Jon Miranda16ea1b12017-12-12 14:52:48 -080043import 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 Liaof6b4b192020-08-07 02:31:32 +080047import androidx.core.widget.ContentLoadingProgressBar;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080048import androidx.fragment.app.DialogFragment;
Chuck Liao7e333722021-02-27 02:21:20 +080049import androidx.fragment.app.Fragment;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080050import androidx.recyclerview.widget.GridLayoutManager;
51import androidx.recyclerview.widget.RecyclerView;
52import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
53import androidx.recyclerview.widget.RecyclerView.ViewHolder;
54
Jon Miranda16ea1b12017-12-12 14:52:48 -080055import com.android.wallpaper.R;
56import com.android.wallpaper.asset.Asset;
57import com.android.wallpaper.asset.Asset.DrawableLoadedListener;
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;
Jon Miranda16ea1b12017-12-12 14:52:48 -080068import com.android.wallpaper.module.FormFactorChecker;
69import com.android.wallpaper.module.FormFactorChecker.FormFactor;
70import com.android.wallpaper.module.Injector;
71import com.android.wallpaper.module.InjectorProvider;
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -070072import com.android.wallpaper.module.PackageStatusNotifier;
chihhangchuangc687d912020-05-04 14:33:05 +080073import com.android.wallpaper.module.UserEventLogger;
Jon Miranda16ea1b12017-12-12 14:52:48 -080074import com.android.wallpaper.module.WallpaperChangedNotifier;
75import com.android.wallpaper.module.WallpaperPersister;
76import com.android.wallpaper.module.WallpaperPersister.Destination;
77import com.android.wallpaper.module.WallpaperPreferences;
Chuck Liao69630f12020-03-05 19:01:25 +080078import com.android.wallpaper.module.WallpaperSetter;
Chuck Liao58aca1c2021-03-17 01:20:55 +080079import com.android.wallpaper.picker.AppbarFragment;
Jon Miranda16ea1b12017-12-12 14:52:48 -080080import com.android.wallpaper.picker.BaseActivity;
81import com.android.wallpaper.picker.CurrentWallpaperBottomSheetPresenter;
Chuck Liaob17d1502020-09-07 21:55:30 +080082import com.android.wallpaper.picker.FragmentTransactionChecker;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080083import com.android.wallpaper.picker.MyPhotosStarter.MyPhotosStarterProvider;
Chuck Liao7dc21572020-05-14 18:37:36 +080084import com.android.wallpaper.picker.PreviewActivity;
Jon Miranda16ea1b12017-12-12 14:52:48 -080085import com.android.wallpaper.picker.RotationStarter;
Chuck Liao69630f12020-03-05 19:01:25 +080086import com.android.wallpaper.picker.SetWallpaperDialogFragment;
Jon Miranda16ea1b12017-12-12 14:52:48 -080087import com.android.wallpaper.picker.SetWallpaperErrorDialogFragment;
88import com.android.wallpaper.picker.StartRotationDialogFragment;
89import com.android.wallpaper.picker.StartRotationErrorDialogFragment;
chihhangchuangc687d912020-05-04 14:33:05 +080090import com.android.wallpaper.picker.WallpaperInfoHelper;
Jon Miranda16ea1b12017-12-12 14:52:48 -080091import com.android.wallpaper.picker.WallpapersUiContainer;
92import com.android.wallpaper.picker.individual.SetIndividualHolder.OnSetListener;
93import com.android.wallpaper.util.DiskBasedLogger;
Santiago Etchebehere53c63432020-05-07 18:55:35 -070094import com.android.wallpaper.util.SizeCalculator;
Chuck Liao8ec38e02020-02-26 20:59:32 +080095import com.android.wallpaper.widget.BottomActionBar;
chihhangchuang1a29e752020-04-28 18:22:53 +080096import com.android.wallpaper.widget.WallpaperInfoView;
Wesley.CW Wangdc68fde2020-06-15 19:12:33 +080097import com.android.wallpaper.widget.WallpaperPickerRecyclerViewAccessibilityDelegate;
98import com.android.wallpaper.widget.WallpaperPickerRecyclerViewAccessibilityDelegate.BottomSheetHost;
Sunny Goyal8600a3f2018-08-15 12:48:01 -070099
Jon Miranda16ea1b12017-12-12 14:52:48 -0800100import com.bumptech.glide.Glide;
101import com.bumptech.glide.MemoryCategory;
102
103import java.util.ArrayList;
104import java.util.Date;
105import java.util.List;
Chuck Liao11f4a762020-04-08 13:24:43 +0800106import java.util.Optional;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800107import java.util.Random;
108
109/**
110 * Displays the Main UI for picking an individual wallpaper image.
111 */
Chuck Liao58aca1c2021-03-17 01:20:55 +0800112public class IndividualPickerFragment extends AppbarFragment
Jon Miranda16ea1b12017-12-12 14:52:48 -0800113 implements RotationStarter, StartRotationErrorDialogFragment.Listener,
114 CurrentWallpaperBottomSheetPresenter.RefreshListener,
Chihhang Chuang85f099a2020-06-16 18:04:39 +0800115 SetWallpaperErrorDialogFragment.Listener, SetWallpaperDialogFragment.Listener,
116 StartRotationDialogFragment.Listener {
Chuck Liao46644b92020-06-08 14:20:50 +0800117
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800118 /**
119 * Position of a special tile that doesn't belong to an individual wallpaper of the category,
120 * such as "my photos" or "daily rotation".
121 */
122 static final int SPECIAL_FIXED_TILE_ADAPTER_POSITION = 0;
123 static final String ARG_CATEGORY_COLLECTION_ID = "category_collection_id";
124
Jon Miranda16ea1b12017-12-12 14:52:48 -0800125 private static final String TAG = "IndividualPickerFrgmnt";
Jon Miranda16ea1b12017-12-12 14:52:48 -0800126 private static final int UNUSED_REQUEST_CODE = 1;
127 private static final String TAG_START_ROTATION_DIALOG = "start_rotation_dialog";
128 private static final String TAG_START_ROTATION_ERROR_DIALOG = "start_rotation_error_dialog";
129 private static final String PROGRESS_DIALOG_NO_TITLE = null;
130 private static final boolean PROGRESS_DIALOG_INDETERMINATE = true;
131 private static final String TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT =
132 "individual_set_wallpaper_error_dialog";
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700133 private static final String KEY_NIGHT_MODE = "IndividualPickerFragment.NIGHT_MODE";
Jon Miranda16ea1b12017-12-12 14:52:48 -0800134
Chuck Liao8ec38e02020-02-26 20:59:32 +0800135 /**
Chuck Liaof40063f2020-03-03 18:35:24 +0800136 * An interface for updating the thumbnail with the specific wallpaper.
137 */
138 public interface ThumbnailUpdater {
139 /**
140 * Updates the thumbnail with the specific wallpaper.
141 */
142 void updateThumbnail(WallpaperInfo wallpaperInfo);
143
144 /**
145 * Restores to the thumbnails of the wallpapers which were applied.
146 */
147 void restoreThumbnails();
148 }
149
“Chuck7ef99722020-03-22 04:34:03 +0800150 /**
151 * An interface for receiving the destination of the new applied wallpaper.
152 */
153 public interface WallpaperDestinationCallback {
154 /**
155 * Called when the destination of the wallpaper is set.
156 *
157 * @param destination the destination which a wallpaper may be set.
158 * See {@link Destination} for more details.
159 */
160 void onDestinationSet(@Destination int destination);
161 }
162
Chuck Liaob3829fb2020-04-01 00:47:50 +0800163 /**
164 * The listener which will be notified when the wallpaper is selected.
165 */
166 public interface WallpaperSelectedListener {
167 /**
168 * Called when the wallpaper is selected.
169 *
170 * @param position the position of the selected wallpaper
171 */
172 void onWallpaperSelected(int position);
173 }
174
Chuck Liaof6b4b192020-08-07 02:31:32 +0800175 /**
Chuck Liao7e333722021-02-27 02:21:20 +0800176 * Interface to be implemented by a Fragment(or an Activity) hosting
177 * a {@link IndividualPickerFragment}.
Chuck Liaof6b4b192020-08-07 02:31:32 +0800178 */
179 public interface IndividualPickerFragmentHost {
180 /**
Chuck Liao58aca1c2021-03-17 01:20:55 +0800181 * Indicates if the host has toolbar to show the title. If it does, we should set the title
182 * there.
183 */
184 boolean isHostToolbarShown();
185
186 /**
187 * Sets the title in the host's toolbar.
Chuck Liaof6b4b192020-08-07 02:31:32 +0800188 */
189 void setToolbarTitle(CharSequence title);
190
191 /**
192 * Moves to the previous fragment.
193 */
194 void moveToPreviousFragment();
195 }
196
Ching-Sung Lied6560f2020-05-04 19:25:09 +0800197 WallpaperPersister mWallpaperPersister;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800198 WallpaperPreferences mWallpaperPreferences;
199 WallpaperChangedNotifier mWallpaperChangedNotifier;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800200 RecyclerView mImageGrid;
201 IndividualAdapter mAdapter;
202 WallpaperCategory mCategory;
203 WallpaperRotationInitializer mWallpaperRotationInitializer;
204 List<WallpaperInfo> mWallpapers;
205 Point mTileSizePx;
206 WallpapersUiContainer mWallpapersUiContainer;
207 @FormFactor
208 int mFormFactor;
209 PackageStatusNotifier mPackageStatusNotifier;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800210
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800211 Handler mHandler;
212 Random mRandom;
Chuck Liaof6b4b192020-08-07 02:31:32 +0800213 boolean mIsWallpapersReceived;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800214
215 WallpaperChangedNotifier.Listener mWallpaperChangedListener =
216 new WallpaperChangedNotifier.Listener() {
217 @Override
218 public void onWallpaperChanged() {
219 if (mFormFactor != FormFactorChecker.FORM_FACTOR_DESKTOP) {
220 return;
221 }
222
223 ViewHolder selectedViewHolder = mImageGrid.findViewHolderForAdapterPosition(
224 mAdapter.mSelectedAdapterPosition);
225
226 // Null remote ID => My Photos wallpaper, so deselect whatever was previously selected.
227 if (mWallpaperPreferences.getHomeWallpaperRemoteId() == null) {
228 if (selectedViewHolder instanceof SelectableHolder) {
229 ((SelectableHolder) selectedViewHolder).setSelectionState(
230 SelectableHolder.SELECTION_STATE_DESELECTED);
231 }
232 } else {
233 mAdapter.updateSelectedTile(mAdapter.mPendingSelectedAdapterPosition);
234 }
235 }
236 };
237 PackageStatusNotifier.Listener mAppStatusListener;
Ching-Sung Li073812b2020-04-07 21:19:21 +0800238 BottomActionBar mBottomActionBar;
chihhangchuang1a29e752020-04-28 18:22:53 +0800239 WallpaperInfoView mWallpaperInfoView;
Ching-Sung Li073812b2020-04-07 21:19:21 +0800240 @Nullable WallpaperInfo mSelectedWallpaperInfo;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800241
chihhangchuangc687d912020-05-04 14:33:05 +0800242 private UserEventLogger mUserEventLogger;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800243 private ProgressDialog mProgressDialog;
244 private boolean mTestingMode;
245 private CurrentWallpaperBottomSheetPresenter mCurrentWallpaperBottomSheetPresenter;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800246 private SetIndividualHolder mPendingSetIndividualHolder;
Chuck Liaof6b4b192020-08-07 02:31:32 +0800247 private ContentLoadingProgressBar mLoading;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800248
249 /**
250 * Staged error dialog fragments that were unable to be shown when the activity didn't allow
251 * committing fragment transactions.
252 */
253 private SetWallpaperErrorDialogFragment mStagedSetWallpaperErrorDialogFragment;
254 private StartRotationErrorDialogFragment mStagedStartRotationErrorDialogFragment;
255
Jon Miranda16ea1b12017-12-12 14:52:48 -0800256 private Runnable mCurrentWallpaperBottomSheetExpandedRunnable;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800257
258 /**
259 * Whether {@code mUpdateDailyWallpaperThumbRunnable} has been run at least once in this
260 * invocation of the fragment.
261 */
262 private boolean mWasUpdateRunnableRun;
263
264 /**
265 * A Runnable which regularly updates the thumbnail for the "Daily wallpapers" tile in desktop
266 * mode.
267 */
268 private Runnable mUpdateDailyWallpaperThumbRunnable = new Runnable() {
269 @Override
270 public void run() {
271 ViewHolder viewHolder = mImageGrid.findViewHolderForAdapterPosition(
272 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
273 if (viewHolder instanceof DesktopRotationHolder) {
274 updateDesktopDailyRotationThumbnail((DesktopRotationHolder) viewHolder);
275 } else { // viewHolder is null
276 // If the rotation tile is unavailable (because user has scrolled down, causing the
277 // ViewHolder to be recycled), schedule the update for some time later. Once user scrolls up
278 // again, the ViewHolder will be re-bound and its thumbnail will be updated.
279 mHandler.postDelayed(mUpdateDailyWallpaperThumbRunnable,
280 DesktopRotationHolder.CROSSFADE_DURATION_MILLIS
281 + DesktopRotationHolder.CROSSFADE_DURATION_PAUSE_MILLIS);
282 }
283 }
284 };
285
Chuck Liao69630f12020-03-05 19:01:25 +0800286 private WallpaperSetter mWallpaperSetter;
“Chuckffd832c2020-03-22 02:15:58 +0800287 private WallpaperInfo mAppliedWallpaperInfo;
“Chuck7ef99722020-03-22 04:34:03 +0800288 private WallpaperManager mWallpaperManager;
289 private int mWallpaperDestination;
Chuck Liaob3829fb2020-04-01 00:47:50 +0800290 private WallpaperSelectedListener mWallpaperSelectedListener;
Chuck Liao8ec38e02020-02-26 20:59:32 +0800291
Jon Miranda16ea1b12017-12-12 14:52:48 -0800292 public static IndividualPickerFragment newInstance(String collectionId) {
293 Bundle args = new Bundle();
294 args.putString(ARG_CATEGORY_COLLECTION_ID, collectionId);
295
296 IndividualPickerFragment fragment = new IndividualPickerFragment();
297 fragment.setArguments(args);
298 return fragment;
299 }
300
“Chuck7ef99722020-03-22 04:34:03 +0800301 /**
302 * Highlights the applied wallpaper (if it exists) according to the destination a wallpaper
303 * would be set.
304 *
305 * @param wallpaperDestination the destination a wallpaper would be set.
306 * It will be either {@link Destination#DEST_HOME_SCREEN}
307 * or {@link Destination#DEST_LOCK_SCREEN}.
308 */
309 public void highlightAppliedWallpaper(@Destination int wallpaperDestination) {
310 mWallpaperDestination = wallpaperDestination;
Chuck Liao11f4a762020-04-08 13:24:43 +0800311 if (mWallpapers != null) {
312 refreshAppliedWallpaper();
“Chuck7ef99722020-03-22 04:34:03 +0800313 }
314 }
315
Jon Miranda16ea1b12017-12-12 14:52:48 -0800316 private void updateDesktopDailyRotationThumbnail(DesktopRotationHolder holder) {
317 int wallpapersIndex = mRandom.nextInt(mWallpapers.size());
318 Asset newThumbnailAsset = mWallpapers.get(wallpapersIndex).getThumbAsset(
319 getActivity());
320 holder.updateThumbnail(newThumbnailAsset, new DrawableLoadedListener() {
321 @Override
322 public void onDrawableLoaded() {
323 if (getActivity() == null) {
324 return;
325 }
326
327 // Schedule the next update of the thumbnail.
328 int delayMillis = DesktopRotationHolder.CROSSFADE_DURATION_MILLIS
329 + DesktopRotationHolder.CROSSFADE_DURATION_PAUSE_MILLIS;
330 mHandler.postDelayed(mUpdateDailyWallpaperThumbRunnable, delayMillis);
331 }
332 });
333 }
334
335 @Override
336 public void onCreate(Bundle savedInstanceState) {
337 super.onCreate(savedInstanceState);
338
339 Injector injector = InjectorProvider.getInjector();
340 Context appContext = getContext().getApplicationContext();
341 mWallpaperPreferences = injector.getPreferences(appContext);
342
343 mWallpaperChangedNotifier = WallpaperChangedNotifier.getInstance();
344 mWallpaperChangedNotifier.registerListener(mWallpaperChangedListener);
345
“Chuck7ef99722020-03-22 04:34:03 +0800346 mWallpaperManager = WallpaperManager.getInstance(appContext);
347
Jon Miranda16ea1b12017-12-12 14:52:48 -0800348 mFormFactor = injector.getFormFactorChecker(appContext).getFormFactor();
349
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700350 mPackageStatusNotifier = injector.getPackageStatusNotifier(appContext);
351
chihhangchuangc687d912020-05-04 14:33:05 +0800352 mUserEventLogger = injector.getUserEventLogger(appContext);
353
“Chuckffd832c2020-03-22 02:15:58 +0800354 mWallpaperPersister = injector.getWallpaperPersister(appContext);
Chuck Liao69630f12020-03-05 19:01:25 +0800355 mWallpaperSetter = new WallpaperSetter(
“Chuckffd832c2020-03-22 02:15:58 +0800356 mWallpaperPersister,
Chuck Liao69630f12020-03-05 19:01:25 +0800357 injector.getPreferences(appContext),
358 injector.getUserEventLogger(appContext),
359 false);
360
Jon Miranda16ea1b12017-12-12 14:52:48 -0800361 mWallpapers = new ArrayList<>();
362 mRandom = new Random();
363 mHandler = new Handler();
364
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700365 // Clear Glide's cache if night-mode changed to ensure thumbnails are reloaded
366 if (savedInstanceState != null && (savedInstanceState.getInt(KEY_NIGHT_MODE)
367 != (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK))) {
368 Glide.get(getContext()).clearMemory();
369 }
370
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700371 CategoryProvider categoryProvider = injector.getCategoryProvider(appContext);
372 categoryProvider.fetchCategories(new CategoryReceiver() {
373 @Override
374 public void onCategoryReceived(Category category) {
375 // Do nothing.
376 }
377
378 @Override
379 public void doneFetchingCategories() {
Chuck Liao7e36d172020-09-18 01:09:17 +0800380 Category category = categoryProvider.getCategory(
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700381 getArguments().getString(ARG_CATEGORY_COLLECTION_ID));
Chuck Liaof44433e2020-09-21 22:58:26 +0800382 if (category != null && !(category instanceof WallpaperCategory)) {
Chuck Liao7e36d172020-09-18 01:09:17 +0800383 return;
384 }
385 mCategory = (WallpaperCategory) category;
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700386 if (mCategory == null) {
387 DiskBasedLogger.e(TAG, "Failed to find the category.", getContext());
388
389 // The absence of this category in the CategoryProvider indicates a broken
390 // state, see b/38030129. Hence, finish the activity and return.
Chuck Liaof6b4b192020-08-07 02:31:32 +0800391 getIndividualPickerFragmentHost().moveToPreviousFragment();
392 Toast.makeText(getContext(), R.string.collection_not_exist_msg,
393 Toast.LENGTH_SHORT).show();
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700394 return;
395 }
396 onCategoryLoaded();
397 }
398 }, false);
399 }
400
Chuck Liaof6b4b192020-08-07 02:31:32 +0800401
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700402 protected void onCategoryLoaded() {
Chuck Liao7e36d172020-09-18 01:09:17 +0800403 if (getIndividualPickerFragmentHost() == null) {
404 return;
405 }
Chuck Liao58aca1c2021-03-17 01:20:55 +0800406 if (getIndividualPickerFragmentHost().isHostToolbarShown()) {
407 getIndividualPickerFragmentHost().setToolbarTitle(mCategory.getTitle());
408 } else {
409 setTitle(mCategory.getTitle());
410 }
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700411 mWallpaperRotationInitializer = mCategory.getWallpaperRotationInitializer();
Chuck Liao58e4a1c2020-05-22 11:35:35 +0800412 // Avoids the "rotation" action is not shown correctly
413 // in a rare case : onCategoryLoaded() is called after onBottomActionBarReady().
414 if (isRotationEnabled() && mBottomActionBar != null
415 && !mBottomActionBar.areActionsShown(ROTATION)) {
416 mBottomActionBar.showActions(ROTATION);
417 }
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700418 fetchWallpapers(false);
419
420 if (mCategory.supportsThirdParty()) {
421 mAppStatusListener = (packageName, status) -> {
422 if (status != PackageStatusNotifier.PackageStatus.REMOVED ||
423 mCategory.containsThirdParty(packageName)) {
424 fetchWallpapers(true);
425 }
426 };
427 mPackageStatusNotifier.addListener(mAppStatusListener,
428 WallpaperService.SERVICE_INTERFACE);
429 }
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700430
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700431 maybeSetUpImageGrid();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700432 }
433
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800434 void fetchWallpapers(boolean forceReload) {
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700435 mWallpapers.clear();
Chuck Liaof6b4b192020-08-07 02:31:32 +0800436 mIsWallpapersReceived = false;
437 updateLoading();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800438 mCategory.fetchWallpapers(getActivity().getApplicationContext(), new WallpaperReceiver() {
439 @Override
440 public void onWallpapersReceived(List<WallpaperInfo> wallpapers) {
Chuck Liaof6b4b192020-08-07 02:31:32 +0800441 mIsWallpapersReceived = true;
442 updateLoading();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800443 for (WallpaperInfo wallpaper : wallpapers) {
444 mWallpapers.add(wallpaper);
445 }
446
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700447 // Wallpapers may load after the adapter is initialized, in which case we have
448 // to explicitly notify that the data set has changed.
Jon Miranda16ea1b12017-12-12 14:52:48 -0800449 if (mAdapter != null) {
450 mAdapter.notifyDataSetChanged();
451 }
452
453 if (mWallpapersUiContainer != null) {
454 mWallpapersUiContainer.onWallpapersReady();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700455 } else {
456 if (wallpapers.isEmpty()) {
457 // If there are no more wallpapers and we're on phone, just finish the
458 // Activity.
459 Activity activity = getActivity();
460 if (activity != null
461 && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
462 activity.finish();
463 }
464 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800465 }
466 }
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700467 }, forceReload);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800468 }
469
Chuck Liaof6b4b192020-08-07 02:31:32 +0800470 void updateLoading() {
471 if (mLoading == null) {
472 return;
473 }
474
475 if (mIsWallpapersReceived) {
476 mLoading.hide();
477 } else {
478 mLoading.show();
479 }
480 }
481
Jon Miranda16ea1b12017-12-12 14:52:48 -0800482 @Override
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700483 public void onSaveInstanceState(@NonNull Bundle outState) {
484 super.onSaveInstanceState(outState);
Santiago Etchebehere0ec065c2019-06-13 11:30:21 -0700485 outState.putInt(KEY_NIGHT_MODE,
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700486 getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK);
487 }
488
489 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800490 public View onCreateView(LayoutInflater inflater, ViewGroup container,
491 Bundle savedInstanceState) {
492 View view = inflater.inflate(R.layout.fragment_individual_picker, container, false);
Chuck Liao58aca1c2021-03-17 01:20:55 +0800493 if (getIndividualPickerFragmentHost().isHostToolbarShown()) {
494 view.findViewById(R.id.header_bar).setVisibility(View.GONE);
495 } else {
496 setUpToolbar(view);
497 if (mCategory != null) {
498 setTitle(mCategory.getTitle());
499 }
500 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800501
Santiago Etchebehere53c63432020-05-07 18:55:35 -0700502 mTileSizePx = SizeCalculator.getIndividualTileSize(getActivity());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800503
504 mImageGrid = (RecyclerView) view.findViewById(R.id.wallpaper_grid);
505 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
506 int gridPaddingPx = getResources().getDimensionPixelSize(R.dimen.grid_padding_desktop);
507 updateImageGridPadding(false /* addExtraBottomSpace */);
508 mImageGrid.setScrollBarSize(gridPaddingPx);
509 }
Chuck Liaoba401232020-03-13 20:11:04 +0800510 mImageGrid.addItemDecoration(new GridPaddingDecoration(
511 getResources().getDimensionPixelSize(R.dimen.grid_padding)));
Wesley.CW Wangdc68fde2020-06-15 19:12:33 +0800512 mImageGrid.setAccessibilityDelegateCompat(
513 new WallpaperPickerRecyclerViewAccessibilityDelegate(
514 mImageGrid, (BottomSheetHost) getParentFragment(), getNumColumns()));
Chuck Liaof6b4b192020-08-07 02:31:32 +0800515 mLoading = view.findViewById(R.id.loading_indicator);
516 updateLoading();
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700517 maybeSetUpImageGrid();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800518 setUpBottomSheet();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800519 return view;
520 }
521
522 @Override
523 public void onClickTryAgain(@Destination int unused) {
524 if (mPendingSetIndividualHolder != null) {
525 mPendingSetIndividualHolder.setWallpaper();
526 }
527 }
528
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800529 void updateImageGridPadding(boolean addExtraBottomSpace) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800530 int gridPaddingPx = getResources().getDimensionPixelSize(R.dimen.grid_padding_desktop);
531 int bottomSheetHeightPx = getResources().getDimensionPixelSize(
532 R.dimen.current_wallpaper_bottom_sheet_layout_height);
533 int paddingBottomPx = addExtraBottomSpace ? bottomSheetHeightPx : 0;
534 // Only left and top may be set in order for the GridMarginDecoration to work properly.
535 mImageGrid.setPadding(
536 gridPaddingPx, gridPaddingPx, 0, paddingBottomPx);
537 }
538
Chuck Liaof6b4b192020-08-07 02:31:32 +0800539 private IndividualPickerFragmentHost getIndividualPickerFragmentHost() {
Chuck Liao7e333722021-02-27 02:21:20 +0800540 Fragment parentFragment = getParentFragment();
541 if (parentFragment != null) {
542 return (IndividualPickerFragmentHost) parentFragment;
543 } else {
544 return (IndividualPickerFragmentHost) getActivity();
545 }
Chuck Liaof6b4b192020-08-07 02:31:32 +0800546 }
547
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700548 private void maybeSetUpImageGrid() {
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700549 // Skip if mImageGrid been initialized yet
550 if (mImageGrid == null) {
551 return;
552 }
553 // Skip if category hasn't loaded yet
554 if (mCategory == null) {
555 return;
556 }
557 // Skip if the adapter was already created
558 if (mAdapter != null) {
559 return;
560 }
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700561 setUpImageGrid();
562 }
563
564 /**
565 * Create the adapter and assign it to mImageGrid.
566 * Both mImageGrid and mCategory are guaranteed to not be null when this method is called.
567 */
568 void setUpImageGrid() {
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800569 mAdapter = new IndividualAdapter(mWallpapers);
570 mImageGrid.setAdapter(mAdapter);
571 mImageGrid.setLayoutManager(new GridLayoutManager(getActivity(), getNumColumns()));
572 }
573
Jon Miranda16ea1b12017-12-12 14:52:48 -0800574 /**
575 * Enables and populates the "Currently set" wallpaper BottomSheet.
576 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800577 void setUpBottomSheet() {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800578 mImageGrid.addOnScrollListener(new OnScrollListener() {
579 @Override
580 public void onScrolled(RecyclerView recyclerView, int dx, final int dy) {
581 if (mCurrentWallpaperBottomSheetPresenter == null) {
582 return;
583 }
584
585 if (mCurrentWallpaperBottomSheetExpandedRunnable != null) {
586 mHandler.removeCallbacks(mCurrentWallpaperBottomSheetExpandedRunnable);
587 }
588 mCurrentWallpaperBottomSheetExpandedRunnable = new Runnable() {
589 @Override
590 public void run() {
591 if (dy > 0) {
592 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(false);
593 } else {
594 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
595 }
596 }
597 };
598 mHandler.postDelayed(mCurrentWallpaperBottomSheetExpandedRunnable, 100);
599 }
600 });
601 }
602
chihhangchuang3efb6832020-04-17 02:06:25 +0800603 @Override
604 protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
Chuck Liao342f4ab2020-05-26 18:28:09 +0800605 mBottomActionBar = bottomActionBar;
606 if (isRotationEnabled()) {
607 mBottomActionBar.showActionsOnly(ROTATION);
Ching-Sung Li073812b2020-04-07 21:19:21 +0800608 }
Chuck Liao342f4ab2020-05-26 18:28:09 +0800609 mBottomActionBar.setActionClickListener(ROTATION, unused -> {
610 DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
611 startRotationDialogFragment.setTargetFragment(
612 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
613 startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
614 });
615 mBottomActionBar.setActionClickListener(APPLY, unused -> {
616 mBottomActionBar.disableActions();
617 mWallpaperSetter.requestDestination(getActivity(), getFragmentManager(), this,
618 mSelectedWallpaperInfo instanceof LiveWallpaperInfo);
619 });
620
621 mWallpaperInfoView = (WallpaperInfoView) LayoutInflater.from(getContext())
622 .inflate(R.layout.wallpaper_info_view, /* root= */ null);
623 mBottomActionBar.attachViewToBottomSheetAndBindAction(mWallpaperInfoView, INFORMATION);
624 mBottomActionBar.setActionClickListener(EDIT, unused -> {
625 mWallpaperPersister.setWallpaperInfoInPreview(mSelectedWallpaperInfo);
626 mSelectedWallpaperInfo.showPreview(getActivity(),
627 new PreviewActivity.PreviewActivityIntentFactory(),
628 PREVIEW_WALLPAPER_REQUEST_CODE);
629 });
630 mBottomActionBar.show();
Ching-Sung Li073812b2020-04-07 21:19:21 +0800631 }
632
Jon Miranda16ea1b12017-12-12 14:52:48 -0800633 @Override
634 public void onResume() {
635 super.onResume();
636
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700637 WallpaperPreferences preferences = InjectorProvider.getInjector()
638 .getPreferences(getActivity());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800639 preferences.setLastAppActiveTimestamp(new Date().getTime());
640
641 // Reset Glide memory settings to a "normal" level of usage since it may have been lowered in
642 // PreviewFragment.
643 Glide.get(getActivity()).setMemoryCategory(MemoryCategory.NORMAL);
644
645 // Show the staged 'start rotation' error dialog fragment if there is one that was unable to be
646 // shown earlier when this fragment's hosting activity didn't allow committing fragment
647 // transactions.
648 if (mStagedStartRotationErrorDialogFragment != null) {
649 mStagedStartRotationErrorDialogFragment.show(
650 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
651 mStagedStartRotationErrorDialogFragment = null;
652 }
653
654 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one
655 // that was unable to be shown earlier when this fragment's hosting activity didn't allow
656 // committing fragment transactions.
657 if (mStagedSetWallpaperErrorDialogFragment != null) {
658 mStagedSetWallpaperErrorDialogFragment.show(
659 getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
660 mStagedSetWallpaperErrorDialogFragment = null;
661 }
662
Chuck Liao5a4243b2020-05-20 23:56:39 +0800663 if (shouldShowRotationTile() && mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
664 // Must be resuming from a previously stopped state, so re-schedule the update of the
665 // daily wallpapers tile thumbnail.
666 mUpdateDailyWallpaperThumbRunnable.run();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800667 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800668 }
669
670 @Override
671 public void onStop() {
672 super.onStop();
673 mHandler.removeCallbacks(mUpdateDailyWallpaperThumbRunnable);
674 }
675
676 @Override
677 public void onDestroy() {
678 super.onDestroy();
679 if (mProgressDialog != null) {
680 mProgressDialog.dismiss();
681 }
682 mWallpaperChangedNotifier.unregisterListener(mWallpaperChangedListener);
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700683 if (mAppStatusListener != null) {
684 mPackageStatusNotifier.removeListener(mAppStatusListener);
685 }
Chuck Liao69630f12020-03-05 19:01:25 +0800686 mWallpaperSetter.cleanUp();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800687 }
688
689 @Override
Chihhang Chuang85f099a2020-06-16 18:04:39 +0800690 public void onStartRotationDialogDismiss(@NonNull DialogInterface dialog) {
chihhangchuang8f9da5f2020-06-17 00:32:18 +0800691 // TODO(b/159310028): Refactor fragment layer to make it able to restore from config change.
692 // This is to handle config change with StartRotationDialog popup, the StartRotationDialog
693 // still holds a reference to the destroyed Fragment and is calling
694 // onStartRotationDialogDismissed on that destroyed Fragment.
695 if (mBottomActionBar != null) {
696 mBottomActionBar.deselectAction(ROTATION);
697 }
Chihhang Chuang85f099a2020-06-16 18:04:39 +0800698 }
699
700 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800701 public void retryStartRotation(@NetworkPreference int networkPreference) {
702 startRotation(networkPreference);
703 }
704
chihhangchuang7feb3752020-04-24 02:48:56 +0800705 @Override
706 public boolean onBackPressed() {
707 if (mSelectedWallpaperInfo != null) {
708 onWallpaperSelected(null, 0);
709 return true;
710 }
711 return false;
712 }
713
Jon Miranda16ea1b12017-12-12 14:52:48 -0800714 public void setCurrentWallpaperBottomSheetPresenter(
715 CurrentWallpaperBottomSheetPresenter presenter) {
716 mCurrentWallpaperBottomSheetPresenter = presenter;
717 }
718
719 public void setWallpapersUiContainer(WallpapersUiContainer uiContainer) {
720 mWallpapersUiContainer = uiContainer;
721 }
722
Chuck Liaob3829fb2020-04-01 00:47:50 +0800723 public void setOnWallpaperSelectedListener(
724 WallpaperSelectedListener wallpaperSelectedListener) {
725 mWallpaperSelectedListener = wallpaperSelectedListener;
726 }
727
728 /**
729 * Resizes the layout's height.
730 */
731 public void resizeLayout(int height) {
732 mImageGrid.getLayoutParams().height = height;
733 mImageGrid.requestLayout();
734 }
735
736 /**
737 * Scrolls to the specific item.
738 *
739 * @param position the position of the item
740 */
741 public void scrollToPosition(int position) {
742 ((GridLayoutManager) mImageGrid.getLayoutManager())
743 .scrollToPositionWithOffset(position, /* offset= */ 0);
744 }
745
Jon Miranda16ea1b12017-12-12 14:52:48 -0800746 /**
747 * Enable a test mode of operation -- in which certain UI features are disabled to allow for
748 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog
749 * constantly keeps the UI thread alive and blocks a test forever.
750 *
751 * @param testingMode
752 */
753 void setTestingMode(boolean testingMode) {
754 mTestingMode = testingMode;
755 }
756
Jon Miranda16ea1b12017-12-12 14:52:48 -0800757 @Override
758 public void startRotation(@NetworkPreference final int networkPreference) {
759 if (!isRotationEnabled()) {
760 Log.e(TAG, "Rotation is not enabled for this category " + mCategory.getTitle());
761 return;
762 }
763
764 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
765 // causes Espresso to hang once the dialog is shown.
766 if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE && !mTestingMode) {
767 int themeResId;
768 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
769 themeResId = R.style.ProgressDialogThemePreL;
770 } else {
771 themeResId = R.style.LightDialogTheme;
772 }
773 mProgressDialog = new ProgressDialog(getActivity(), themeResId);
774
775 mProgressDialog.setTitle(PROGRESS_DIALOG_NO_TITLE);
776 mProgressDialog.setMessage(
777 getResources().getString(R.string.start_rotation_progress_message));
778 mProgressDialog.setIndeterminate(PROGRESS_DIALOG_INDETERMINATE);
779 mProgressDialog.show();
780 }
781
782 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
783 mAdapter.mPendingSelectedAdapterPosition = SPECIAL_FIXED_TILE_ADAPTER_POSITION;
784 }
785
786 final Context appContext = getActivity().getApplicationContext();
787
788 mWallpaperRotationInitializer.setFirstWallpaperInRotation(
789 appContext,
790 networkPreference,
791 new Listener() {
792 @Override
793 public void onFirstWallpaperInRotationSet() {
794 if (mProgressDialog != null) {
795 mProgressDialog.dismiss();
796 }
797
798 // The fragment may be detached from its containing activity if the user exits the
799 // app before the first wallpaper image in rotation finishes downloading.
800 Activity activity = getActivity();
801
Jon Miranda16ea1b12017-12-12 14:52:48 -0800802
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700803 if (mWallpaperRotationInitializer.startRotation(appContext)) {
804 if (activity != null
805 && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
806 try {
807 Toast.makeText(getActivity(),
808 R.string.wallpaper_set_successfully_message,
809 Toast.LENGTH_SHORT).show();
810 } catch (NotFoundException e) {
811 Log.e(TAG, "Could not show toast " + e);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800812 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800813
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700814 activity.setResult(Activity.RESULT_OK);
815 activity.finish();
816 } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
817 mAdapter.updateSelectedTile(SPECIAL_FIXED_TILE_ADAPTER_POSITION);
818 }
819 } else { // Failed to start rotation.
820 showStartRotationErrorDialog(networkPreference);
821
822 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
823 DesktopRotationHolder rotationViewHolder =
824 (DesktopRotationHolder)
825 mImageGrid.findViewHolderForAdapterPosition(
826 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
827 rotationViewHolder.setSelectionState(
828 SelectableHolder.SELECTION_STATE_DESELECTED);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800829 }
830 }
831 }
832
833 @Override
834 public void onError() {
835 if (mProgressDialog != null) {
836 mProgressDialog.dismiss();
837 }
838
839 showStartRotationErrorDialog(networkPreference);
840
841 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
842 DesktopRotationHolder rotationViewHolder =
843 (DesktopRotationHolder) mImageGrid.findViewHolderForAdapterPosition(
844 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
845 rotationViewHolder.setSelectionState(SelectableHolder.SELECTION_STATE_DESELECTED);
846 }
847 }
848 });
849 }
850
851 private void showStartRotationErrorDialog(@NetworkPreference int networkPreference) {
Chuck Liaob17d1502020-09-07 21:55:30 +0800852 FragmentTransactionChecker activity = (FragmentTransactionChecker) getActivity();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800853 if (activity != null) {
854 StartRotationErrorDialogFragment startRotationErrorDialogFragment =
855 StartRotationErrorDialogFragment.newInstance(networkPreference);
856 startRotationErrorDialogFragment.setTargetFragment(
857 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
858
859 if (activity.isSafeToCommitFragmentTransaction()) {
860 startRotationErrorDialogFragment.show(
861 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
862 } else {
863 mStagedStartRotationErrorDialogFragment = startRotationErrorDialogFragment;
864 }
865 }
866 }
867
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800868 int getNumColumns() {
Ching-Sung Li9df77a32019-07-10 11:45:30 +0800869 Activity activity = getActivity();
Chuck Liaoe2fe0302020-06-29 21:15:35 +0800870 return activity == null ? 1 : SizeCalculator.getNumIndividualColumns(activity);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800871 }
872
873 /**
874 * Returns whether rotation is enabled for this category.
875 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800876 boolean isRotationEnabled() {
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700877 return mWallpaperRotationInitializer != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800878 }
879
880 @Override
881 public void onCurrentWallpaperRefreshed() {
882 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
883 }
884
Chuck Liao69630f12020-03-05 19:01:25 +0800885 @Override
886 public void onSet(int destination) {
887 if (mSelectedWallpaperInfo == null) {
888 Log.e(TAG, "Unable to set wallpaper since the selected wallpaper info is null");
889 return;
890 }
891
“Chuckffd832c2020-03-22 02:15:58 +0800892 mWallpaperPersister.setWallpaperInfoInPreview(mSelectedWallpaperInfo);
Chuck Liao69630f12020-03-05 19:01:25 +0800893 if (mSelectedWallpaperInfo instanceof LiveWallpaperInfo) {
894 mWallpaperSetter.setCurrentWallpaper(getActivity(), mSelectedWallpaperInfo, null,
895 destination, 0, null, mSetWallpaperCallback);
896 } else {
897 mWallpaperSetter.setCurrentWallpaper(
898 getActivity(), mSelectedWallpaperInfo, destination, mSetWallpaperCallback);
899 }
“Chuck7ef99722020-03-22 04:34:03 +0800900 onWallpaperDestinationSet(destination);
Chuck Liao69630f12020-03-05 19:01:25 +0800901 }
902
903 private WallpaperPersister.SetWallpaperCallback mSetWallpaperCallback =
904 new WallpaperPersister.SetWallpaperCallback() {
905 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800906 public void onSuccess(WallpaperInfo wallpaperInfo) {
chihhangchuang210c9602020-06-02 12:38:14 +0800907 mWallpaperPersister.onLiveWallpaperSet();
Chuck Liao6e52fff2020-04-23 16:11:23 +0800908 Toast.makeText(getActivity(), R.string.wallpaper_set_successfully_message,
909 Toast.LENGTH_SHORT).show();
chihhangchuang210c9602020-06-02 12:38:14 +0800910 getActivity().overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
911 getActivity().finish();
Chuck Liao69630f12020-03-05 19:01:25 +0800912 }
913
914 @Override
915 public void onError(@Nullable Throwable throwable) {
916 Log.e(TAG, "Can't apply the wallpaper.");
917 mBottomActionBar.enableActions();
918 }
919 };
920
921 @Override
922 public void onDialogDismissed(boolean withItemSelected) {
923 if (!withItemSelected) {
924 mBottomActionBar.enableActions();
925 }
926 }
927
Jon Miranda16ea1b12017-12-12 14:52:48 -0800928 /**
929 * Shows a "set wallpaper" error dialog with a failure message and button to try again.
930 */
931 private void showSetWallpaperErrorDialog() {
932 SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance(
933 R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH);
934 dialogFragment.setTargetFragment(this, UNUSED_REQUEST_CODE);
935
936 if (((BaseActivity) getActivity()).isSafeToCommitFragmentTransaction()) {
937 dialogFragment.show(getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
938 } else {
939 mStagedSetWallpaperErrorDialogFragment = dialogFragment;
940 }
941 }
942
Ching-Sung Li073812b2020-04-07 21:19:21 +0800943 void updateBottomActions(boolean hasWallpaperSelected) {
chihhangchuang803ea9a2020-04-21 13:03:10 +0800944 if (hasWallpaperSelected) {
Chuck Liao7dc21572020-05-14 18:37:36 +0800945 mBottomActionBar.showActionsOnly(INFORMATION, EDIT, APPLY);
chihhangchuang803ea9a2020-04-21 13:03:10 +0800946 } else {
chihhangchuang08abb582020-04-27 17:20:31 +0800947 mBottomActionBar.showActionsOnly(ROTATION);
chihhangchuang803ea9a2020-04-21 13:03:10 +0800948 }
Chuck Liao69630f12020-03-05 19:01:25 +0800949 }
950
951 private void updateThumbnail(WallpaperInfo selectedWallpaperInfo) {
Chuck Liaof40063f2020-03-03 18:35:24 +0800952 ThumbnailUpdater thumbnailUpdater = (ThumbnailUpdater) getParentFragment();
Chuck Liao69630f12020-03-05 19:01:25 +0800953 if (thumbnailUpdater == null) {
954 return;
955 }
956
957 if (selectedWallpaperInfo != null) {
958 thumbnailUpdater.updateThumbnail(selectedWallpaperInfo);
959 } else {
960 thumbnailUpdater.restoreThumbnails();
Chuck Liaof40063f2020-03-03 18:35:24 +0800961 }
962 }
963
“Chuck7ef99722020-03-22 04:34:03 +0800964 private void onWallpaperDestinationSet(int destination) {
965 WallpaperDestinationCallback wallpaperDestinationCallback =
966 (WallpaperDestinationCallback) getParentFragment();
967 if (wallpaperDestinationCallback == null) {
968 return;
969 }
970
971 wallpaperDestinationCallback.onDestinationSet(destination);
972 }
973
Ching-Sung Li073812b2020-04-07 21:19:21 +0800974 void onWallpaperSelected(@Nullable WallpaperInfo newSelectedWallpaperInfo,
Chuck Liaob3829fb2020-04-01 00:47:50 +0800975 int position) {
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800976 if (mSelectedWallpaperInfo == newSelectedWallpaperInfo) {
“Chuckffd832c2020-03-22 02:15:58 +0800977 return;
978 }
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800979 // Update current wallpaper.
“Chuckffd832c2020-03-22 02:15:58 +0800980 updateActivatedStatus(mSelectedWallpaperInfo == null
981 ? mAppliedWallpaperInfo : mSelectedWallpaperInfo, false);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800982 // Update new selected wallpaper.
983 updateActivatedStatus(newSelectedWallpaperInfo == null
984 ? mAppliedWallpaperInfo : newSelectedWallpaperInfo, true);
985
986 mSelectedWallpaperInfo = newSelectedWallpaperInfo;
987 updateBottomActions(mSelectedWallpaperInfo != null);
988 updateThumbnail(mSelectedWallpaperInfo);
chihhangchuangde9e8722020-05-02 17:22:13 +0800989 // Populate wallpaper info into view.
chihhangchuang1a29e752020-04-28 18:22:53 +0800990 if (mSelectedWallpaperInfo != null && mWallpaperInfoView != null) {
chihhangchuangc687d912020-05-04 14:33:05 +0800991 WallpaperInfoHelper.loadExploreIntent(
992 getContext(),
993 mSelectedWallpaperInfo,
994 (actionLabel, exploreIntent) ->
995 mWallpaperInfoView.populateWallpaperInfo(
Chuck Liao9991d682021-01-20 17:45:14 +0800996 mSelectedWallpaperInfo,
997 actionLabel,
998 WallpaperInfoHelper.shouldShowExploreButton(
999 getContext(), exploreIntent),
1000 v -> onExploreClicked(exploreIntent))
1001 );
Chuck Liaob3829fb2020-04-01 00:47:50 +08001002 }
1003
1004 if (mWallpaperSelectedListener != null) {
1005 mWallpaperSelectedListener.onWallpaperSelected(position);
chihhangchuang22aa0cc2020-03-25 19:12:42 +08001006 }
Chuck Liaof40063f2020-03-03 18:35:24 +08001007 }
1008
chihhangchuangc687d912020-05-04 14:33:05 +08001009 private void onExploreClicked(Intent exploreIntent) {
1010 if (getContext() == null) {
1011 return;
1012 }
1013 Context context = getContext();
1014 mUserEventLogger.logActionClicked(mSelectedWallpaperInfo.getCollectionId(context),
1015 mSelectedWallpaperInfo.getActionLabelRes(context));
1016
1017 startActivity(exploreIntent);
1018 }
1019
Chuck Liao6a37a1c2020-03-07 03:39:43 +08001020 private void updateActivatedStatus(WallpaperInfo wallpaperInfo, boolean isActivated) {
“Chuckffd832c2020-03-22 02:15:58 +08001021 if (wallpaperInfo == null) {
1022 return;
1023 }
Chuck Liao6a37a1c2020-03-07 03:39:43 +08001024 int index = mWallpapers.indexOf(wallpaperInfo);
Chuck Liao5a4243b2020-05-20 23:56:39 +08001025 index = (shouldShowRotationTile() || mCategory.supportsCustomPhotos())
Chuck Liao6a37a1c2020-03-07 03:39:43 +08001026 ? index + 1 : index;
1027 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
1028 if (holder != null) {
Tianguang Zhangd913daf2021-03-03 20:21:26 +01001029 CircularImageView thumbnail = holder.itemView.findViewById(R.id.thumbnail);
1030 thumbnail.setClipped(isActivated);
Chuck Liao6a37a1c2020-03-07 03:39:43 +08001031 } else {
1032 // Item is not visible, make sure the item is re-bound when it becomes visible.
1033 mAdapter.notifyItemChanged(index);
1034 }
1035 }
1036
“Chuckffd832c2020-03-22 02:15:58 +08001037 private void updateAppliedStatus(WallpaperInfo wallpaperInfo, boolean isApplied) {
1038 if (wallpaperInfo == null) {
1039 return;
1040 }
1041 int index = mWallpapers.indexOf(wallpaperInfo);
Chuck Liao5a4243b2020-05-20 23:56:39 +08001042 index = (shouldShowRotationTile() || mCategory.supportsCustomPhotos())
“Chuckffd832c2020-03-22 02:15:58 +08001043 ? index + 1 : index;
1044 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
Tianguang Zhangd913daf2021-03-03 20:21:26 +01001045 if (holder == null) {
“Chuckffd832c2020-03-22 02:15:58 +08001046 // Item is not visible, make sure the item is re-bound when it becomes visible.
1047 mAdapter.notifyItemChanged(index);
1048 }
1049 }
1050
Chuck Liao11f4a762020-04-08 13:24:43 +08001051 private void refreshAppliedWallpaper() {
1052 // Clear the check mark and blue border(if it shows) of the old applied wallpaper.
1053 showCheckMarkAndBorderForAppliedWallpaper(false);
1054
1055 // Update to the new applied wallpaper.
1056 String appliedWallpaperId = getAppliedWallpaperId();
1057 Optional<WallpaperInfo> wallpaperInfoOptional = mWallpapers
1058 .stream()
1059 .filter(wallpaper -> wallpaper.getWallpaperId() != null)
1060 .filter(wallpaper -> wallpaper.getWallpaperId().equals(appliedWallpaperId))
1061 .findFirst();
1062 mAppliedWallpaperInfo = wallpaperInfoOptional.orElse(null);
1063
1064 // Set the check mark and blue border(if user doesn't select) of the new applied wallpaper.
1065 showCheckMarkAndBorderForAppliedWallpaper(true);
1066 }
1067
1068 private String getAppliedWallpaperId() {
1069 WallpaperPreferences prefs =
1070 InjectorProvider.getInjector().getPreferences(getContext());
1071 android.app.WallpaperInfo wallpaperInfo = mWallpaperManager.getWallpaperInfo();
1072 boolean isDestinationBoth =
1073 mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK) < 0;
1074
1075 if (isDestinationBoth || mWallpaperDestination == WallpaperPersister.DEST_HOME_SCREEN) {
1076 return wallpaperInfo != null
1077 ? wallpaperInfo.getServiceName() : prefs.getHomeWallpaperRemoteId();
1078 } else {
1079 return prefs.getLockWallpaperRemoteId();
1080 }
1081 }
1082
1083 private void showCheckMarkAndBorderForAppliedWallpaper(boolean show) {
1084 updateAppliedStatus(mAppliedWallpaperInfo, show);
1085 if (mSelectedWallpaperInfo == null) {
1086 updateActivatedStatus(mAppliedWallpaperInfo, show);
1087 }
1088 }
1089
Chuck Liao5a4243b2020-05-20 23:56:39 +08001090 private boolean shouldShowRotationTile() {
1091 return mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP && isRotationEnabled();
Jon Miranda16ea1b12017-12-12 14:52:48 -08001092 }
1093
Tianguang Zhangd913daf2021-03-03 20:21:26 +01001094 class EmptySelectionAnimator implements SelectionAnimator{
1095 EmptySelectionAnimator() {}
1096
1097 public boolean isSelected() {
1098 return false;
1099 }
1100
1101 /**
1102 * Sets the UI to selected immediately with no animation.
1103 */
1104 public void selectImmediately() {}
1105
1106 /**
1107 * Sets the UI to deselected immediately with no animation.
1108 */
1109 public void deselectImmediately() {}
1110
1111 /**
1112 * Sets the UI to selected with a smooth animation.
1113 */
1114 public void animateSelected() {}
1115
1116 /**
1117 * Sets the UI to deselected with a smooth animation.
1118 */
1119 public void animateDeselected() {}
1120
1121 /**
1122 * Sets the UI to show a loading indicator.
1123 */
1124 public void showLoading() {}
1125
1126 /**
1127 * Sets the UI to hide the loading indicator.
1128 */
1129 public void showNotLoading() {}
1130
1131 }
1132
Jon Miranda16ea1b12017-12-12 14:52:48 -08001133 /**
1134 * RecyclerView Adapter subclass for the wallpaper tiles in the RecyclerView.
1135 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001136 class IndividualAdapter extends RecyclerView.Adapter<ViewHolder> {
1137 static final int ITEM_VIEW_TYPE_ROTATION = 1;
1138 static final int ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER = 2;
1139 static final int ITEM_VIEW_TYPE_MY_PHOTOS = 3;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001140
1141 private final List<WallpaperInfo> mWallpapers;
1142
1143 private int mPendingSelectedAdapterPosition;
1144 private int mSelectedAdapterPosition;
1145
1146 IndividualAdapter(List<WallpaperInfo> wallpapers) {
1147 mWallpapers = wallpapers;
1148 mPendingSelectedAdapterPosition = -1;
1149 mSelectedAdapterPosition = -1;
1150 }
1151
1152 @Override
1153 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
1154 switch (viewType) {
1155 case ITEM_VIEW_TYPE_ROTATION:
1156 return createRotationHolder(parent);
1157 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1158 return createIndividualHolder(parent);
1159 case ITEM_VIEW_TYPE_MY_PHOTOS:
1160 return createMyPhotosHolder(parent);
1161 default:
1162 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1163 return null;
1164 }
1165 }
1166
1167 @Override
1168 public int getItemViewType(int position) {
Chuck Liao5a4243b2020-05-20 23:56:39 +08001169 if (shouldShowRotationTile() && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001170 return ITEM_VIEW_TYPE_ROTATION;
1171 }
1172
1173 // A category cannot have both a "start rotation" tile and a "my photos" tile.
1174 if (mCategory.supportsCustomPhotos()
1175 && !isRotationEnabled()
1176 && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
1177 return ITEM_VIEW_TYPE_MY_PHOTOS;
1178 }
1179
1180 return ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER;
1181 }
1182
1183 @Override
1184 public void onBindViewHolder(ViewHolder holder, int position) {
1185 int viewType = getItemViewType(position);
1186
1187 switch (viewType) {
1188 case ITEM_VIEW_TYPE_ROTATION:
1189 onBindRotationHolder(holder, position);
1190 break;
1191 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1192 onBindIndividualHolder(holder, position);
1193 break;
1194 case ITEM_VIEW_TYPE_MY_PHOTOS:
1195 ((MyPhotosViewHolder) holder).bind();
1196 break;
1197 default:
1198 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1199 }
1200 }
1201
1202 @Override
1203 public int getItemCount() {
Chuck Liao5a4243b2020-05-20 23:56:39 +08001204 return (shouldShowRotationTile() || mCategory.supportsCustomPhotos())
Jon Miranda16ea1b12017-12-12 14:52:48 -08001205 ? mWallpapers.size() + 1
1206 : mWallpapers.size();
1207 }
1208
1209 private ViewHolder createRotationHolder(ViewGroup parent) {
1210 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
Chuck Liao5a4243b2020-05-20 23:56:39 +08001211 View view = layoutInflater.inflate(R.layout.grid_item_rotation_desktop, parent, false);
Tianguang Zhangd913daf2021-03-03 20:21:26 +01001212 SelectionAnimator selectionAnimator = new EmptySelectionAnimator();
Chuck Liao5a4243b2020-05-20 23:56:39 +08001213 return new DesktopRotationHolder(getActivity(), mTileSizePx.y, view, selectionAnimator,
1214 IndividualPickerFragment.this);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001215 }
1216
1217 private ViewHolder createIndividualHolder(ViewGroup parent) {
1218 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1219 View view = layoutInflater.inflate(R.layout.grid_item_image, parent, false);
1220
1221 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
Tianguang Zhangd913daf2021-03-03 20:21:26 +01001222 SelectionAnimator selectionAnimator = new EmptySelectionAnimator();
Jon Miranda16ea1b12017-12-12 14:52:48 -08001223 return new SetIndividualHolder(
1224 getActivity(), mTileSizePx.y, view,
1225 selectionAnimator,
1226 new OnSetListener() {
1227 @Override
1228 public void onPendingWallpaperSet(int adapterPosition) {
1229 // Deselect and hide loading indicator for any previously pending tile.
1230 if (mPendingSelectedAdapterPosition != -1) {
1231 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1232 mPendingSelectedAdapterPosition);
1233 if (oldViewHolder instanceof SelectableHolder) {
1234 ((SelectableHolder) oldViewHolder).setSelectionState(
1235 SelectableHolder.SELECTION_STATE_DESELECTED);
1236 }
1237 }
1238
1239 if (mSelectedAdapterPosition != -1) {
1240 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1241 mSelectedAdapterPosition);
1242 if (oldViewHolder instanceof SelectableHolder) {
1243 ((SelectableHolder) oldViewHolder).setSelectionState(
1244 SelectableHolder.SELECTION_STATE_DESELECTED);
1245 }
1246 }
1247
1248 mPendingSelectedAdapterPosition = adapterPosition;
1249 }
1250
1251 @Override
1252 public void onWallpaperSet(int adapterPosition) {
1253 // No-op -- UI handles a new wallpaper being set by reacting to the
1254 // WallpaperChangedNotifier.
1255 }
1256
1257 @Override
1258 public void onWallpaperSetFailed(SetIndividualHolder holder) {
1259 showSetWallpaperErrorDialog();
1260 mPendingSetIndividualHolder = holder;
1261 }
1262 });
1263 } else { // MOBILE
Chuck Liao3d1a51c2020-02-17 18:29:34 +08001264 return new PreviewIndividualHolder(getActivity(), mTileSizePx.y, view);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001265 }
1266 }
1267
1268 private ViewHolder createMyPhotosHolder(ViewGroup parent) {
1269 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1270 View view = layoutInflater.inflate(R.layout.grid_item_my_photos, parent, false);
1271
Santiago Etchebeherefab49612019-01-15 12:22:42 -08001272 return new MyPhotosViewHolder(getActivity(),
1273 ((MyPhotosStarterProvider) getActivity()).getMyPhotosStarter(),
1274 mTileSizePx.y, view);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001275 }
1276
1277 /**
1278 * Marks the tile at the given position as selected with a visual indication. Also updates the
1279 * "currently selected" BottomSheet to reflect the newly selected tile.
1280 */
1281 private void updateSelectedTile(int newlySelectedPosition) {
1282 // Prevent multiple spinners from appearing with a user tapping several tiles in rapid
1283 // succession.
1284 if (mPendingSelectedAdapterPosition == mSelectedAdapterPosition) {
1285 return;
1286 }
1287
1288 if (mCurrentWallpaperBottomSheetPresenter != null) {
1289 mCurrentWallpaperBottomSheetPresenter.refreshCurrentWallpapers(
1290 IndividualPickerFragment.this);
1291
1292 if (mCurrentWallpaperBottomSheetExpandedRunnable != null) {
1293 mHandler.removeCallbacks(mCurrentWallpaperBottomSheetExpandedRunnable);
1294 }
1295 mCurrentWallpaperBottomSheetExpandedRunnable = new Runnable() {
1296 @Override
1297 public void run() {
1298 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
1299 }
1300 };
1301 mHandler.postDelayed(mCurrentWallpaperBottomSheetExpandedRunnable, 100);
1302 }
1303
1304 // User may have switched to another category, thus detaching this fragment, so check here.
1305 // NOTE: We do this check after updating the current wallpaper BottomSheet so that the update
1306 // still occurs in the UI after the user selects that other category.
1307 if (getActivity() == null) {
1308 return;
1309 }
1310
1311 // Update the newly selected wallpaper ViewHolder and the old one so that if
1312 // selection UI state applies (desktop UI), it is updated.
1313 if (mSelectedAdapterPosition >= 0) {
1314 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1315 mSelectedAdapterPosition);
1316 if (oldViewHolder instanceof SelectableHolder) {
1317 ((SelectableHolder) oldViewHolder).setSelectionState(
1318 SelectableHolder.SELECTION_STATE_DESELECTED);
1319 }
1320 }
1321
1322 // Animate selection of newly selected tile.
1323 ViewHolder newViewHolder = mImageGrid
1324 .findViewHolderForAdapterPosition(newlySelectedPosition);
1325 if (newViewHolder instanceof SelectableHolder) {
1326 ((SelectableHolder) newViewHolder).setSelectionState(
1327 SelectableHolder.SELECTION_STATE_SELECTED);
1328 }
1329
1330 mSelectedAdapterPosition = newlySelectedPosition;
1331
1332 // If the tile was in the last row of the grid, add space below it so the user can scroll down
1333 // and up to see the BottomSheet without it fully overlapping the newly selected tile.
1334 int spanCount = ((GridLayoutManager) mImageGrid.getLayoutManager()).getSpanCount();
1335 int numRows = (int) Math.ceil((float) getItemCount() / spanCount);
1336 int rowOfNewlySelectedTile = newlySelectedPosition / spanCount;
1337 boolean isInLastRow = rowOfNewlySelectedTile == numRows - 1;
1338
1339 updateImageGridPadding(isInLastRow /* addExtraBottomSpace */);
1340 }
1341
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001342 void onBindRotationHolder(ViewHolder holder, int position) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001343 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1344 String collectionId = mCategory.getCollectionId();
1345 ((DesktopRotationHolder) holder).bind(collectionId);
1346
1347 if (mWallpaperPreferences.getWallpaperPresentationMode()
1348 == WallpaperPreferences.PRESENTATION_MODE_ROTATING
1349 && collectionId.equals(mWallpaperPreferences.getHomeWallpaperCollectionId())) {
1350 mSelectedAdapterPosition = position;
1351 }
1352
1353 if (!mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
1354 updateDesktopDailyRotationThumbnail((DesktopRotationHolder) holder);
1355 mWasUpdateRunnableRun = true;
1356 }
1357 }
1358 }
1359
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001360 void onBindIndividualHolder(ViewHolder holder, int position) {
Chuck Liao5a4243b2020-05-20 23:56:39 +08001361 int wallpaperIndex = (shouldShowRotationTile() || mCategory.supportsCustomPhotos())
Jon Miranda16ea1b12017-12-12 14:52:48 -08001362 ? position - 1 : position;
1363 WallpaperInfo wallpaper = mWallpapers.get(wallpaperIndex);
1364 ((IndividualHolder) holder).bindWallpaper(wallpaper);
“Chuck7ef99722020-03-22 04:34:03 +08001365 String appliedWallpaperId = getAppliedWallpaperId();
“Chuckffd832c2020-03-22 02:15:58 +08001366 boolean isWallpaperApplied = wallpaper.getWallpaperId().equals(appliedWallpaperId);
1367 boolean isWallpaperSelected = wallpaper.equals(mSelectedWallpaperInfo);
1368 boolean hasUserSelectedWallpaper = mSelectedWallpaperInfo != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001369
“Chuckffd832c2020-03-22 02:15:58 +08001370 if (isWallpaperApplied) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001371 mSelectedAdapterPosition = position;
“Chuckffd832c2020-03-22 02:15:58 +08001372 mAppliedWallpaperInfo = wallpaper;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001373 }
Chuck Liaof40063f2020-03-03 18:35:24 +08001374
Tianguang Zhangd913daf2021-03-03 20:21:26 +01001375 CircularImageView thumbnail = holder.itemView.findViewById(R.id.thumbnail);
1376 thumbnail.setClipped(isWallpaperApplied);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001377 }
1378 }
Chuck Liaoba401232020-03-13 20:11:04 +08001379
1380 private class GridPaddingDecoration extends RecyclerView.ItemDecoration {
1381
1382 private int mPadding;
1383
1384 GridPaddingDecoration(int padding) {
1385 mPadding = padding;
1386 }
1387
1388 @Override
1389 public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
1390 RecyclerView.State state) {
1391 int position = parent.getChildAdapterPosition(view);
1392 if (position >= 0) {
1393 outRect.left = mPadding;
1394 outRect.right = mPadding;
1395 }
1396 }
1397 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001398}