blob: 0f042ab1ebb6176e96ef9139fdac49032b9f6d50 [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;
Santiago Etchebehereb1854472019-06-06 17:44:54 -070026import android.content.res.Configuration;
Jon Miranda16ea1b12017-12-12 14:52:48 -080027import android.content.res.Resources.NotFoundException;
28import android.graphics.Point;
29import android.graphics.PorterDuff.Mode;
Chuck Liaoba401232020-03-13 20:11:04 +080030import android.graphics.Rect;
Jon Miranda16ea1b12017-12-12 14:52:48 -080031import android.os.Build.VERSION;
32import android.os.Build.VERSION_CODES;
33import android.os.Bundle;
34import android.os.Handler;
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -070035import android.service.wallpaper.WallpaperService;
Jon Miranda16ea1b12017-12-12 14:52:48 -080036import android.util.Log;
37import android.view.LayoutInflater;
38import android.view.View;
39import android.view.ViewGroup;
Jon Miranda16ea1b12017-12-12 14:52:48 -080040import android.widget.ImageView;
41import android.widget.TextView;
42import android.widget.Toast;
43
Santiago Etchebehereb1854472019-06-06 17:44:54 -070044import androidx.annotation.NonNull;
Chuck Liao69630f12020-03-05 19:01:25 +080045import androidx.annotation.Nullable;
Chuck Liaoba401232020-03-13 20:11:04 +080046import androidx.cardview.widget.CardView;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080047import androidx.fragment.app.DialogFragment;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080048import androidx.recyclerview.widget.GridLayoutManager;
49import androidx.recyclerview.widget.RecyclerView;
50import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
51import androidx.recyclerview.widget.RecyclerView.ViewHolder;
52
Jon Miranda16ea1b12017-12-12 14:52:48 -080053import com.android.wallpaper.R;
54import com.android.wallpaper.asset.Asset;
55import com.android.wallpaper.asset.Asset.DrawableLoadedListener;
56import com.android.wallpaper.config.Flags;
Santiago Etchebehere8648bb82019-08-06 17:09:02 -070057import com.android.wallpaper.model.Category;
58import com.android.wallpaper.model.CategoryProvider;
59import com.android.wallpaper.model.CategoryReceiver;
Chuck Liao69630f12020-03-05 19:01:25 +080060import com.android.wallpaper.model.LiveWallpaperInfo;
Jon Miranda16ea1b12017-12-12 14:52:48 -080061import com.android.wallpaper.model.WallpaperCategory;
62import com.android.wallpaper.model.WallpaperInfo;
63import com.android.wallpaper.model.WallpaperReceiver;
64import com.android.wallpaper.model.WallpaperRotationInitializer;
65import com.android.wallpaper.model.WallpaperRotationInitializer.Listener;
66import com.android.wallpaper.model.WallpaperRotationInitializer.NetworkPreference;
67import com.android.wallpaper.model.WallpaperRotationInitializer.RotationInitializationState;
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;
Jon Miranda16ea1b12017-12-12 14:52:48 -080073import com.android.wallpaper.module.WallpaperChangedNotifier;
74import com.android.wallpaper.module.WallpaperPersister;
75import com.android.wallpaper.module.WallpaperPersister.Destination;
76import com.android.wallpaper.module.WallpaperPreferences;
Chuck Liao69630f12020-03-05 19:01:25 +080077import com.android.wallpaper.module.WallpaperSetter;
Jon Miranda16ea1b12017-12-12 14:52:48 -080078import com.android.wallpaper.picker.BaseActivity;
chihhangchuang3efb6832020-04-17 02:06:25 +080079import com.android.wallpaper.picker.BottomActionBarFragment;
Jon Miranda16ea1b12017-12-12 14:52:48 -080080import com.android.wallpaper.picker.CurrentWallpaperBottomSheetPresenter;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080081import com.android.wallpaper.picker.MyPhotosStarter.MyPhotosStarterProvider;
Jon Miranda16ea1b12017-12-12 14:52:48 -080082import com.android.wallpaper.picker.RotationStarter;
Chuck Liao69630f12020-03-05 19:01:25 +080083import com.android.wallpaper.picker.SetWallpaperDialogFragment;
Jon Miranda16ea1b12017-12-12 14:52:48 -080084import com.android.wallpaper.picker.SetWallpaperErrorDialogFragment;
85import com.android.wallpaper.picker.StartRotationDialogFragment;
86import com.android.wallpaper.picker.StartRotationErrorDialogFragment;
87import com.android.wallpaper.picker.WallpapersUiContainer;
88import com.android.wallpaper.picker.individual.SetIndividualHolder.OnSetListener;
89import com.android.wallpaper.util.DiskBasedLogger;
90import com.android.wallpaper.util.TileSizeCalculator;
Chuck Liao8ec38e02020-02-26 20:59:32 +080091import com.android.wallpaper.widget.BottomActionBar;
chihhangchuang1a29e752020-04-28 18:22:53 +080092import com.android.wallpaper.widget.WallpaperInfoView;
Sunny Goyal8600a3f2018-08-15 12:48:01 -070093
Jon Miranda16ea1b12017-12-12 14:52:48 -080094import com.bumptech.glide.Glide;
95import com.bumptech.glide.MemoryCategory;
96
97import java.util.ArrayList;
98import java.util.Date;
99import java.util.List;
Chuck Liao11f4a762020-04-08 13:24:43 +0800100import java.util.Optional;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800101import java.util.Random;
102
103/**
104 * Displays the Main UI for picking an individual wallpaper image.
105 */
chihhangchuang3efb6832020-04-17 02:06:25 +0800106public class IndividualPickerFragment extends BottomActionBarFragment
Jon Miranda16ea1b12017-12-12 14:52:48 -0800107 implements RotationStarter, StartRotationErrorDialogFragment.Listener,
108 CurrentWallpaperBottomSheetPresenter.RefreshListener,
Chuck Liao69630f12020-03-05 19:01:25 +0800109 SetWallpaperErrorDialogFragment.Listener, SetWallpaperDialogFragment.Listener {
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800110 /**
111 * Position of a special tile that doesn't belong to an individual wallpaper of the category,
112 * such as "my photos" or "daily rotation".
113 */
114 static final int SPECIAL_FIXED_TILE_ADAPTER_POSITION = 0;
115 static final String ARG_CATEGORY_COLLECTION_ID = "category_collection_id";
Ching-Sung Li073812b2020-04-07 21:19:21 +0800116 /**
117 * A temporary flag to hide the bottom action bar feature.
118 */
Chuck Liao1b7de472020-04-24 14:06:38 +0800119 static final boolean TEMP_BOTTOM_ACTION_BAR_FEATURE = true;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800120
Jon Miranda16ea1b12017-12-12 14:52:48 -0800121 private static final String TAG = "IndividualPickerFrgmnt";
Jon Miranda16ea1b12017-12-12 14:52:48 -0800122 private static final int UNUSED_REQUEST_CODE = 1;
123 private static final String TAG_START_ROTATION_DIALOG = "start_rotation_dialog";
124 private static final String TAG_START_ROTATION_ERROR_DIALOG = "start_rotation_error_dialog";
125 private static final String PROGRESS_DIALOG_NO_TITLE = null;
126 private static final boolean PROGRESS_DIALOG_INDETERMINATE = true;
127 private static final String TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT =
128 "individual_set_wallpaper_error_dialog";
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700129 private static final String KEY_NIGHT_MODE = "IndividualPickerFragment.NIGHT_MODE";
Jon Miranda16ea1b12017-12-12 14:52:48 -0800130
Chuck Liao8ec38e02020-02-26 20:59:32 +0800131 /**
Chuck Liaof40063f2020-03-03 18:35:24 +0800132 * An interface for updating the thumbnail with the specific wallpaper.
133 */
134 public interface ThumbnailUpdater {
135 /**
136 * Updates the thumbnail with the specific wallpaper.
137 */
138 void updateThumbnail(WallpaperInfo wallpaperInfo);
139
140 /**
141 * Restores to the thumbnails of the wallpapers which were applied.
142 */
143 void restoreThumbnails();
144 }
145
“Chuck7ef99722020-03-22 04:34:03 +0800146 /**
147 * An interface for receiving the destination of the new applied wallpaper.
148 */
149 public interface WallpaperDestinationCallback {
150 /**
151 * Called when the destination of the wallpaper is set.
152 *
153 * @param destination the destination which a wallpaper may be set.
154 * See {@link Destination} for more details.
155 */
156 void onDestinationSet(@Destination int destination);
157 }
158
Chuck Liaob3829fb2020-04-01 00:47:50 +0800159 /**
160 * The listener which will be notified when the wallpaper is selected.
161 */
162 public interface WallpaperSelectedListener {
163 /**
164 * Called when the wallpaper is selected.
165 *
166 * @param position the position of the selected wallpaper
167 */
168 void onWallpaperSelected(int position);
169 }
170
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800171 WallpaperPreferences mWallpaperPreferences;
172 WallpaperChangedNotifier mWallpaperChangedNotifier;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800173 RecyclerView mImageGrid;
174 IndividualAdapter mAdapter;
175 WallpaperCategory mCategory;
176 WallpaperRotationInitializer mWallpaperRotationInitializer;
177 List<WallpaperInfo> mWallpapers;
178 Point mTileSizePx;
179 WallpapersUiContainer mWallpapersUiContainer;
180 @FormFactor
181 int mFormFactor;
182 PackageStatusNotifier mPackageStatusNotifier;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800183
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800184 Handler mHandler;
185 Random mRandom;
186
187 WallpaperChangedNotifier.Listener mWallpaperChangedListener =
188 new WallpaperChangedNotifier.Listener() {
189 @Override
190 public void onWallpaperChanged() {
191 if (mFormFactor != FormFactorChecker.FORM_FACTOR_DESKTOP) {
192 return;
193 }
194
195 ViewHolder selectedViewHolder = mImageGrid.findViewHolderForAdapterPosition(
196 mAdapter.mSelectedAdapterPosition);
197
198 // Null remote ID => My Photos wallpaper, so deselect whatever was previously selected.
199 if (mWallpaperPreferences.getHomeWallpaperRemoteId() == null) {
200 if (selectedViewHolder instanceof SelectableHolder) {
201 ((SelectableHolder) selectedViewHolder).setSelectionState(
202 SelectableHolder.SELECTION_STATE_DESELECTED);
203 }
204 } else {
205 mAdapter.updateSelectedTile(mAdapter.mPendingSelectedAdapterPosition);
206 }
207 }
208 };
209 PackageStatusNotifier.Listener mAppStatusListener;
Ching-Sung Li073812b2020-04-07 21:19:21 +0800210 BottomActionBar mBottomActionBar;
chihhangchuang1a29e752020-04-28 18:22:53 +0800211 WallpaperInfoView mWallpaperInfoView;
Ching-Sung Li073812b2020-04-07 21:19:21 +0800212 @Nullable WallpaperInfo mSelectedWallpaperInfo;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800213
Jon Miranda16ea1b12017-12-12 14:52:48 -0800214 private ProgressDialog mProgressDialog;
215 private boolean mTestingMode;
216 private CurrentWallpaperBottomSheetPresenter mCurrentWallpaperBottomSheetPresenter;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800217 private SetIndividualHolder mPendingSetIndividualHolder;
218
219 /**
220 * Staged error dialog fragments that were unable to be shown when the activity didn't allow
221 * committing fragment transactions.
222 */
223 private SetWallpaperErrorDialogFragment mStagedSetWallpaperErrorDialogFragment;
224 private StartRotationErrorDialogFragment mStagedStartRotationErrorDialogFragment;
225
Jon Miranda16ea1b12017-12-12 14:52:48 -0800226 private Runnable mCurrentWallpaperBottomSheetExpandedRunnable;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800227
228 /**
229 * Whether {@code mUpdateDailyWallpaperThumbRunnable} has been run at least once in this
230 * invocation of the fragment.
231 */
232 private boolean mWasUpdateRunnableRun;
233
234 /**
235 * A Runnable which regularly updates the thumbnail for the "Daily wallpapers" tile in desktop
236 * mode.
237 */
238 private Runnable mUpdateDailyWallpaperThumbRunnable = new Runnable() {
239 @Override
240 public void run() {
241 ViewHolder viewHolder = mImageGrid.findViewHolderForAdapterPosition(
242 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
243 if (viewHolder instanceof DesktopRotationHolder) {
244 updateDesktopDailyRotationThumbnail((DesktopRotationHolder) viewHolder);
245 } else { // viewHolder is null
246 // If the rotation tile is unavailable (because user has scrolled down, causing the
247 // ViewHolder to be recycled), schedule the update for some time later. Once user scrolls up
248 // again, the ViewHolder will be re-bound and its thumbnail will be updated.
249 mHandler.postDelayed(mUpdateDailyWallpaperThumbRunnable,
250 DesktopRotationHolder.CROSSFADE_DURATION_MILLIS
251 + DesktopRotationHolder.CROSSFADE_DURATION_PAUSE_MILLIS);
252 }
253 }
254 };
255
Chuck Liao69630f12020-03-05 19:01:25 +0800256 private WallpaperSetter mWallpaperSetter;
“Chuckffd832c2020-03-22 02:15:58 +0800257 private WallpaperPersister mWallpaperPersister;
“Chuckffd832c2020-03-22 02:15:58 +0800258 private WallpaperInfo mAppliedWallpaperInfo;
“Chuck7ef99722020-03-22 04:34:03 +0800259 private WallpaperManager mWallpaperManager;
260 private int mWallpaperDestination;
Chuck Liaob3829fb2020-04-01 00:47:50 +0800261 private WallpaperSelectedListener mWallpaperSelectedListener;
Chuck Liao8ec38e02020-02-26 20:59:32 +0800262
Jon Miranda16ea1b12017-12-12 14:52:48 -0800263 public static IndividualPickerFragment newInstance(String collectionId) {
264 Bundle args = new Bundle();
265 args.putString(ARG_CATEGORY_COLLECTION_ID, collectionId);
266
267 IndividualPickerFragment fragment = new IndividualPickerFragment();
268 fragment.setArguments(args);
269 return fragment;
270 }
271
“Chuck7ef99722020-03-22 04:34:03 +0800272 /**
273 * Highlights the applied wallpaper (if it exists) according to the destination a wallpaper
274 * would be set.
275 *
276 * @param wallpaperDestination the destination a wallpaper would be set.
277 * It will be either {@link Destination#DEST_HOME_SCREEN}
278 * or {@link Destination#DEST_LOCK_SCREEN}.
279 */
280 public void highlightAppliedWallpaper(@Destination int wallpaperDestination) {
281 mWallpaperDestination = wallpaperDestination;
Chuck Liao11f4a762020-04-08 13:24:43 +0800282 if (mWallpapers != null) {
283 refreshAppliedWallpaper();
“Chuck7ef99722020-03-22 04:34:03 +0800284 }
285 }
286
Jon Miranda16ea1b12017-12-12 14:52:48 -0800287 private static int getResIdForRotationState(@RotationInitializationState int rotationState) {
288 switch (rotationState) {
289 case WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED:
290 return R.string.daily_refresh_tile_subtitle;
291 case WallpaperRotationInitializer.ROTATION_HOME_ONLY:
292 return R.string.home_screen_message;
293 case WallpaperRotationInitializer.ROTATION_HOME_AND_LOCK:
294 return R.string.home_and_lock_short_label;
295 default:
296 Log.e(TAG, "Unknown rotation intialization state: " + rotationState);
297 return R.string.home_screen_message;
298 }
299 }
300
301 private void updateDesktopDailyRotationThumbnail(DesktopRotationHolder holder) {
302 int wallpapersIndex = mRandom.nextInt(mWallpapers.size());
303 Asset newThumbnailAsset = mWallpapers.get(wallpapersIndex).getThumbAsset(
304 getActivity());
305 holder.updateThumbnail(newThumbnailAsset, new DrawableLoadedListener() {
306 @Override
307 public void onDrawableLoaded() {
308 if (getActivity() == null) {
309 return;
310 }
311
312 // Schedule the next update of the thumbnail.
313 int delayMillis = DesktopRotationHolder.CROSSFADE_DURATION_MILLIS
314 + DesktopRotationHolder.CROSSFADE_DURATION_PAUSE_MILLIS;
315 mHandler.postDelayed(mUpdateDailyWallpaperThumbRunnable, delayMillis);
316 }
317 });
318 }
319
320 @Override
321 public void onCreate(Bundle savedInstanceState) {
322 super.onCreate(savedInstanceState);
323
324 Injector injector = InjectorProvider.getInjector();
325 Context appContext = getContext().getApplicationContext();
326 mWallpaperPreferences = injector.getPreferences(appContext);
327
328 mWallpaperChangedNotifier = WallpaperChangedNotifier.getInstance();
329 mWallpaperChangedNotifier.registerListener(mWallpaperChangedListener);
330
“Chuck7ef99722020-03-22 04:34:03 +0800331 mWallpaperManager = WallpaperManager.getInstance(appContext);
332
Jon Miranda16ea1b12017-12-12 14:52:48 -0800333 mFormFactor = injector.getFormFactorChecker(appContext).getFormFactor();
334
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700335 mPackageStatusNotifier = injector.getPackageStatusNotifier(appContext);
336
“Chuckffd832c2020-03-22 02:15:58 +0800337 mWallpaperPersister = injector.getWallpaperPersister(appContext);
Chuck Liao69630f12020-03-05 19:01:25 +0800338 mWallpaperSetter = new WallpaperSetter(
“Chuckffd832c2020-03-22 02:15:58 +0800339 mWallpaperPersister,
Chuck Liao69630f12020-03-05 19:01:25 +0800340 injector.getPreferences(appContext),
341 injector.getUserEventLogger(appContext),
342 false);
343
Jon Miranda16ea1b12017-12-12 14:52:48 -0800344 mWallpapers = new ArrayList<>();
345 mRandom = new Random();
346 mHandler = new Handler();
347
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700348 // Clear Glide's cache if night-mode changed to ensure thumbnails are reloaded
349 if (savedInstanceState != null && (savedInstanceState.getInt(KEY_NIGHT_MODE)
350 != (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK))) {
351 Glide.get(getContext()).clearMemory();
352 }
353
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700354 CategoryProvider categoryProvider = injector.getCategoryProvider(appContext);
355 categoryProvider.fetchCategories(new CategoryReceiver() {
356 @Override
357 public void onCategoryReceived(Category category) {
358 // Do nothing.
359 }
360
361 @Override
362 public void doneFetchingCategories() {
363 mCategory = (WallpaperCategory) categoryProvider.getCategory(
364 getArguments().getString(ARG_CATEGORY_COLLECTION_ID));
365 if (mCategory == null) {
366 DiskBasedLogger.e(TAG, "Failed to find the category.", getContext());
367
368 // The absence of this category in the CategoryProvider indicates a broken
369 // state, see b/38030129. Hence, finish the activity and return.
370 getActivity().finish();
371 return;
372 }
373 onCategoryLoaded();
374 }
375 }, false);
376 }
377
378 protected void onCategoryLoaded() {
379 mWallpaperRotationInitializer = mCategory.getWallpaperRotationInitializer();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700380 fetchWallpapers(false);
381
382 if (mCategory.supportsThirdParty()) {
383 mAppStatusListener = (packageName, status) -> {
384 if (status != PackageStatusNotifier.PackageStatus.REMOVED ||
385 mCategory.containsThirdParty(packageName)) {
386 fetchWallpapers(true);
387 }
388 };
389 mPackageStatusNotifier.addListener(mAppStatusListener,
390 WallpaperService.SERVICE_INTERFACE);
391 }
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700392
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700393 maybeSetUpImageGrid();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700394 }
395
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800396 void fetchWallpapers(boolean forceReload) {
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700397 mWallpapers.clear();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800398 mCategory.fetchWallpapers(getActivity().getApplicationContext(), new WallpaperReceiver() {
399 @Override
400 public void onWallpapersReceived(List<WallpaperInfo> wallpapers) {
401 for (WallpaperInfo wallpaper : wallpapers) {
402 mWallpapers.add(wallpaper);
403 }
404
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700405 // Wallpapers may load after the adapter is initialized, in which case we have
406 // to explicitly notify that the data set has changed.
Jon Miranda16ea1b12017-12-12 14:52:48 -0800407 if (mAdapter != null) {
408 mAdapter.notifyDataSetChanged();
409 }
410
411 if (mWallpapersUiContainer != null) {
412 mWallpapersUiContainer.onWallpapersReady();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700413 } else {
414 if (wallpapers.isEmpty()) {
415 // If there are no more wallpapers and we're on phone, just finish the
416 // Activity.
417 Activity activity = getActivity();
418 if (activity != null
419 && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
420 activity.finish();
421 }
422 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800423 }
424 }
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700425 }, forceReload);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800426 }
427
428 @Override
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700429 public void onSaveInstanceState(@NonNull Bundle outState) {
430 super.onSaveInstanceState(outState);
Santiago Etchebehere0ec065c2019-06-13 11:30:21 -0700431 outState.putInt(KEY_NIGHT_MODE,
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700432 getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK);
433 }
434
435 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800436 public View onCreateView(LayoutInflater inflater, ViewGroup container,
437 Bundle savedInstanceState) {
438 View view = inflater.inflate(R.layout.fragment_individual_picker, container, false);
439
440 mTileSizePx = TileSizeCalculator.getIndividualTileSize(getActivity());
441
442 mImageGrid = (RecyclerView) view.findViewById(R.id.wallpaper_grid);
443 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
444 int gridPaddingPx = getResources().getDimensionPixelSize(R.dimen.grid_padding_desktop);
445 updateImageGridPadding(false /* addExtraBottomSpace */);
446 mImageGrid.setScrollBarSize(gridPaddingPx);
447 }
Chuck Liaoba401232020-03-13 20:11:04 +0800448 mImageGrid.addItemDecoration(new GridPaddingDecoration(
449 getResources().getDimensionPixelSize(R.dimen.grid_padding)));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800450
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700451 maybeSetUpImageGrid();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800452 setUpBottomSheet();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800453 return view;
454 }
455
456 @Override
Chuck Liao8ec38e02020-02-26 20:59:32 +0800457 public void onDestroyView() {
458 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
Chuck Liao69630f12020-03-05 19:01:25 +0800459 updateThumbnail(null);
Chuck Liao8ec38e02020-02-26 20:59:32 +0800460 }
461 super.onDestroyView();
462 }
463
464 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800465 public void onClickTryAgain(@Destination int unused) {
466 if (mPendingSetIndividualHolder != null) {
467 mPendingSetIndividualHolder.setWallpaper();
468 }
469 }
470
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800471 void updateImageGridPadding(boolean addExtraBottomSpace) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800472 int gridPaddingPx = getResources().getDimensionPixelSize(R.dimen.grid_padding_desktop);
473 int bottomSheetHeightPx = getResources().getDimensionPixelSize(
474 R.dimen.current_wallpaper_bottom_sheet_layout_height);
475 int paddingBottomPx = addExtraBottomSpace ? bottomSheetHeightPx : 0;
476 // Only left and top may be set in order for the GridMarginDecoration to work properly.
477 mImageGrid.setPadding(
478 gridPaddingPx, gridPaddingPx, 0, paddingBottomPx);
479 }
480
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700481 private void maybeSetUpImageGrid() {
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700482 // Skip if mImageGrid been initialized yet
483 if (mImageGrid == null) {
484 return;
485 }
486 // Skip if category hasn't loaded yet
487 if (mCategory == null) {
488 return;
489 }
490 // Skip if the adapter was already created
491 if (mAdapter != null) {
492 return;
493 }
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700494 setUpImageGrid();
495 }
496
497 /**
498 * Create the adapter and assign it to mImageGrid.
499 * Both mImageGrid and mCategory are guaranteed to not be null when this method is called.
500 */
501 void setUpImageGrid() {
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800502 mAdapter = new IndividualAdapter(mWallpapers);
503 mImageGrid.setAdapter(mAdapter);
504 mImageGrid.setLayoutManager(new GridLayoutManager(getActivity(), getNumColumns()));
505 }
506
Jon Miranda16ea1b12017-12-12 14:52:48 -0800507 /**
508 * Enables and populates the "Currently set" wallpaper BottomSheet.
509 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800510 void setUpBottomSheet() {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800511 mImageGrid.addOnScrollListener(new OnScrollListener() {
512 @Override
513 public void onScrolled(RecyclerView recyclerView, int dx, final int dy) {
514 if (mCurrentWallpaperBottomSheetPresenter == null) {
515 return;
516 }
517
518 if (mCurrentWallpaperBottomSheetExpandedRunnable != null) {
519 mHandler.removeCallbacks(mCurrentWallpaperBottomSheetExpandedRunnable);
520 }
521 mCurrentWallpaperBottomSheetExpandedRunnable = new Runnable() {
522 @Override
523 public void run() {
524 if (dy > 0) {
525 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(false);
526 } else {
527 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
528 }
529 }
530 };
531 mHandler.postDelayed(mCurrentWallpaperBottomSheetExpandedRunnable, 100);
532 }
533 });
534 }
535
chihhangchuang3efb6832020-04-17 02:06:25 +0800536 @Override
537 protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
Ching-Sung Li073812b2020-04-07 21:19:21 +0800538 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
chihhangchuang3efb6832020-04-17 02:06:25 +0800539 mBottomActionBar = bottomActionBar;
chihhangchuang803ea9a2020-04-21 13:03:10 +0800540 if (isRotationEnabled()) {
chihhangchuang08abb582020-04-27 17:20:31 +0800541 mBottomActionBar.showActionsOnly(ROTATION);
chihhangchuang803ea9a2020-04-21 13:03:10 +0800542 }
Ching-Sung Li073812b2020-04-07 21:19:21 +0800543 mBottomActionBar.setActionClickListener(ROTATION, unused -> {
544 DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
545 startRotationDialogFragment.setTargetFragment(
546 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
547 startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
548 });
549 mBottomActionBar.setActionClickListener(APPLY, unused -> {
550 mBottomActionBar.disableActions();
551 mWallpaperSetter.requestDestination(getActivity(), getFragmentManager(), this,
552 mSelectedWallpaperInfo instanceof LiveWallpaperInfo);
553 });
chihhangchuang1a29e752020-04-28 18:22:53 +0800554
555 mWallpaperInfoView =
556 (WallpaperInfoView) mBottomActionBar.inflateViewToBottomSheetAndBindAction(
557 R.layout.wallpaper_info_view, R.id.wallpaper_info, INFORMATION);
558
Ching-Sung Li073812b2020-04-07 21:19:21 +0800559 mBottomActionBar.show();
Ching-Sung Li073812b2020-04-07 21:19:21 +0800560 }
561 }
562
Jon Miranda16ea1b12017-12-12 14:52:48 -0800563 @Override
564 public void onResume() {
565 super.onResume();
566
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700567 WallpaperPreferences preferences = InjectorProvider.getInjector()
568 .getPreferences(getActivity());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800569 preferences.setLastAppActiveTimestamp(new Date().getTime());
570
571 // Reset Glide memory settings to a "normal" level of usage since it may have been lowered in
572 // PreviewFragment.
573 Glide.get(getActivity()).setMemoryCategory(MemoryCategory.NORMAL);
574
575 // Show the staged 'start rotation' error dialog fragment if there is one that was unable to be
576 // shown earlier when this fragment's hosting activity didn't allow committing fragment
577 // transactions.
578 if (mStagedStartRotationErrorDialogFragment != null) {
579 mStagedStartRotationErrorDialogFragment.show(
580 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
581 mStagedStartRotationErrorDialogFragment = null;
582 }
583
584 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one
585 // that was unable to be shown earlier when this fragment's hosting activity didn't allow
586 // committing fragment transactions.
587 if (mStagedSetWallpaperErrorDialogFragment != null) {
588 mStagedSetWallpaperErrorDialogFragment.show(
589 getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
590 mStagedSetWallpaperErrorDialogFragment = null;
591 }
592
593 if (isRotationEnabled()) {
594 if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
595 // Refresh the state of the "start rotation" in case something changed the current daily
596 // rotation while this fragment was paused.
597 RotationHolder rotationHolder = (RotationHolder) mImageGrid
598 .findViewHolderForAdapterPosition(
599 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
600 // The RotationHolder may be null if the RecyclerView has not created the view
601 // holder yet.
602 if (rotationHolder != null && Flags.dynamicStartRotationTileEnabled) {
603 refreshRotationHolder(rotationHolder);
604 }
605 } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
606 if (mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
607 // Must be resuming from a previously stopped state, so re-schedule the update of the
608 // daily wallpapers tile thumbnail.
609 mUpdateDailyWallpaperThumbRunnable.run();
610 }
611 }
612 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800613 }
614
615 @Override
616 public void onStop() {
617 super.onStop();
618 mHandler.removeCallbacks(mUpdateDailyWallpaperThumbRunnable);
619 }
620
621 @Override
622 public void onDestroy() {
623 super.onDestroy();
624 if (mProgressDialog != null) {
625 mProgressDialog.dismiss();
626 }
627 mWallpaperChangedNotifier.unregisterListener(mWallpaperChangedListener);
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700628 if (mAppStatusListener != null) {
629 mPackageStatusNotifier.removeListener(mAppStatusListener);
630 }
Chuck Liao69630f12020-03-05 19:01:25 +0800631 mWallpaperSetter.cleanUp();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800632 }
633
634 @Override
635 public void retryStartRotation(@NetworkPreference int networkPreference) {
636 startRotation(networkPreference);
637 }
638
chihhangchuang7feb3752020-04-24 02:48:56 +0800639 @Override
640 public boolean onBackPressed() {
641 if (mSelectedWallpaperInfo != null) {
642 onWallpaperSelected(null, 0);
643 return true;
644 }
645 return false;
646 }
647
Jon Miranda16ea1b12017-12-12 14:52:48 -0800648 public void setCurrentWallpaperBottomSheetPresenter(
649 CurrentWallpaperBottomSheetPresenter presenter) {
650 mCurrentWallpaperBottomSheetPresenter = presenter;
651 }
652
653 public void setWallpapersUiContainer(WallpapersUiContainer uiContainer) {
654 mWallpapersUiContainer = uiContainer;
655 }
656
Chuck Liaob3829fb2020-04-01 00:47:50 +0800657 public void setOnWallpaperSelectedListener(
658 WallpaperSelectedListener wallpaperSelectedListener) {
659 mWallpaperSelectedListener = wallpaperSelectedListener;
660 }
661
662 /**
663 * Resizes the layout's height.
664 */
665 public void resizeLayout(int height) {
666 mImageGrid.getLayoutParams().height = height;
667 mImageGrid.requestLayout();
668 }
669
670 /**
671 * Scrolls to the specific item.
672 *
673 * @param position the position of the item
674 */
675 public void scrollToPosition(int position) {
676 ((GridLayoutManager) mImageGrid.getLayoutManager())
677 .scrollToPositionWithOffset(position, /* offset= */ 0);
678 }
679
Jon Miranda16ea1b12017-12-12 14:52:48 -0800680 /**
681 * Enable a test mode of operation -- in which certain UI features are disabled to allow for
682 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog
683 * constantly keeps the UI thread alive and blocks a test forever.
684 *
685 * @param testingMode
686 */
687 void setTestingMode(boolean testingMode) {
688 mTestingMode = testingMode;
689 }
690
691 /**
692 * Asynchronously fetches the refreshed rotation initialization state that is up to date with the
693 * state of the user's device and binds the state of the current category's rotation to the "start
694 * rotation" tile.
695 */
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700696 private void refreshRotationHolder(RotationHolder rotationHolder) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800697 mWallpaperRotationInitializer.fetchRotationInitializationState(getContext(),
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700698 rotationState -> {
699 // Update the UI state of the "start rotation" tile displayed on screen.
700 // Do this in a Handler so it is scheduled at the end of the message queue.
701 // This is necessary to ensure we do not remove or add data from the adapter
702 // while the layout is still being computed. RecyclerView documentation
703 // therefore recommends performing such changes in a Handler.
704 new Handler().post(() -> {
705 // A config change may have destroyed the activity since the refresh
706 // started, so check for that to avoid an NPE.
707 if (getActivity() == null) {
708 return;
709 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800710
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700711 rotationHolder.bindRotationInitializationState(rotationState);
712 });
Jon Miranda16ea1b12017-12-12 14:52:48 -0800713 });
714 }
715
716 @Override
717 public void startRotation(@NetworkPreference final int networkPreference) {
718 if (!isRotationEnabled()) {
719 Log.e(TAG, "Rotation is not enabled for this category " + mCategory.getTitle());
720 return;
721 }
722
723 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
724 // causes Espresso to hang once the dialog is shown.
725 if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE && !mTestingMode) {
726 int themeResId;
727 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
728 themeResId = R.style.ProgressDialogThemePreL;
729 } else {
730 themeResId = R.style.LightDialogTheme;
731 }
732 mProgressDialog = new ProgressDialog(getActivity(), themeResId);
733
734 mProgressDialog.setTitle(PROGRESS_DIALOG_NO_TITLE);
735 mProgressDialog.setMessage(
736 getResources().getString(R.string.start_rotation_progress_message));
737 mProgressDialog.setIndeterminate(PROGRESS_DIALOG_INDETERMINATE);
738 mProgressDialog.show();
739 }
740
741 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
742 mAdapter.mPendingSelectedAdapterPosition = SPECIAL_FIXED_TILE_ADAPTER_POSITION;
743 }
744
745 final Context appContext = getActivity().getApplicationContext();
746
747 mWallpaperRotationInitializer.setFirstWallpaperInRotation(
748 appContext,
749 networkPreference,
750 new Listener() {
751 @Override
752 public void onFirstWallpaperInRotationSet() {
753 if (mProgressDialog != null) {
754 mProgressDialog.dismiss();
755 }
756
757 // The fragment may be detached from its containing activity if the user exits the
758 // app before the first wallpaper image in rotation finishes downloading.
759 Activity activity = getActivity();
760
Jon Miranda16ea1b12017-12-12 14:52:48 -0800761
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700762 if (mWallpaperRotationInitializer.startRotation(appContext)) {
763 if (activity != null
764 && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
765 try {
766 Toast.makeText(getActivity(),
767 R.string.wallpaper_set_successfully_message,
768 Toast.LENGTH_SHORT).show();
769 } catch (NotFoundException e) {
770 Log.e(TAG, "Could not show toast " + e);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800771 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800772
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700773 activity.setResult(Activity.RESULT_OK);
774 activity.finish();
775 } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
776 mAdapter.updateSelectedTile(SPECIAL_FIXED_TILE_ADAPTER_POSITION);
777 }
778 } else { // Failed to start rotation.
779 showStartRotationErrorDialog(networkPreference);
780
781 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
782 DesktopRotationHolder rotationViewHolder =
783 (DesktopRotationHolder)
784 mImageGrid.findViewHolderForAdapterPosition(
785 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
786 rotationViewHolder.setSelectionState(
787 SelectableHolder.SELECTION_STATE_DESELECTED);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800788 }
789 }
790 }
791
792 @Override
793 public void onError() {
794 if (mProgressDialog != null) {
795 mProgressDialog.dismiss();
796 }
797
798 showStartRotationErrorDialog(networkPreference);
799
800 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
801 DesktopRotationHolder rotationViewHolder =
802 (DesktopRotationHolder) mImageGrid.findViewHolderForAdapterPosition(
803 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
804 rotationViewHolder.setSelectionState(SelectableHolder.SELECTION_STATE_DESELECTED);
805 }
806 }
807 });
808 }
809
810 private void showStartRotationErrorDialog(@NetworkPreference int networkPreference) {
811 BaseActivity activity = (BaseActivity) getActivity();
812 if (activity != null) {
813 StartRotationErrorDialogFragment startRotationErrorDialogFragment =
814 StartRotationErrorDialogFragment.newInstance(networkPreference);
815 startRotationErrorDialogFragment.setTargetFragment(
816 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
817
818 if (activity.isSafeToCommitFragmentTransaction()) {
819 startRotationErrorDialogFragment.show(
820 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
821 } else {
822 mStagedStartRotationErrorDialogFragment = startRotationErrorDialogFragment;
823 }
824 }
825 }
826
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800827 int getNumColumns() {
Ching-Sung Li9df77a32019-07-10 11:45:30 +0800828 Activity activity = getActivity();
829 return activity == null ? 0 : TileSizeCalculator.getNumIndividualColumns(activity);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800830 }
831
832 /**
833 * Returns whether rotation is enabled for this category.
834 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800835 boolean isRotationEnabled() {
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700836 return mWallpaperRotationInitializer != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800837 }
838
839 @Override
840 public void onCurrentWallpaperRefreshed() {
841 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
842 }
843
Chuck Liao69630f12020-03-05 19:01:25 +0800844
845 @Override
846 public void onSet(int destination) {
847 if (mSelectedWallpaperInfo == null) {
848 Log.e(TAG, "Unable to set wallpaper since the selected wallpaper info is null");
849 return;
850 }
851
“Chuckffd832c2020-03-22 02:15:58 +0800852 mWallpaperPersister.setWallpaperInfoInPreview(mSelectedWallpaperInfo);
Chuck Liao69630f12020-03-05 19:01:25 +0800853 if (mSelectedWallpaperInfo instanceof LiveWallpaperInfo) {
854 mWallpaperSetter.setCurrentWallpaper(getActivity(), mSelectedWallpaperInfo, null,
855 destination, 0, null, mSetWallpaperCallback);
856 } else {
857 mWallpaperSetter.setCurrentWallpaper(
858 getActivity(), mSelectedWallpaperInfo, destination, mSetWallpaperCallback);
859 }
“Chuck7ef99722020-03-22 04:34:03 +0800860 onWallpaperDestinationSet(destination);
Chuck Liao69630f12020-03-05 19:01:25 +0800861 }
862
863 private WallpaperPersister.SetWallpaperCallback mSetWallpaperCallback =
864 new WallpaperPersister.SetWallpaperCallback() {
865 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800866 public void onSuccess(WallpaperInfo wallpaperInfo) {
Chuck Liao6e52fff2020-04-23 16:11:23 +0800867 Toast.makeText(getActivity(), R.string.wallpaper_set_successfully_message,
868 Toast.LENGTH_SHORT).show();
Chuck Liao69630f12020-03-05 19:01:25 +0800869 mBottomActionBar.enableActions();
Chuck Liao11f4a762020-04-08 13:24:43 +0800870 refreshAppliedWallpaper();
“Chuckffd832c2020-03-22 02:15:58 +0800871
872 mWallpaperPersister.onLiveWallpaperSet();
Chuck Liao69630f12020-03-05 19:01:25 +0800873 }
874
875 @Override
876 public void onError(@Nullable Throwable throwable) {
877 Log.e(TAG, "Can't apply the wallpaper.");
878 mBottomActionBar.enableActions();
879 }
880 };
881
882 @Override
883 public void onDialogDismissed(boolean withItemSelected) {
884 if (!withItemSelected) {
885 mBottomActionBar.enableActions();
886 }
887 }
888
Jon Miranda16ea1b12017-12-12 14:52:48 -0800889 /**
890 * Shows a "set wallpaper" error dialog with a failure message and button to try again.
891 */
892 private void showSetWallpaperErrorDialog() {
893 SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance(
894 R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH);
895 dialogFragment.setTargetFragment(this, UNUSED_REQUEST_CODE);
896
897 if (((BaseActivity) getActivity()).isSafeToCommitFragmentTransaction()) {
898 dialogFragment.show(getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
899 } else {
900 mStagedSetWallpaperErrorDialogFragment = dialogFragment;
901 }
902 }
903
Ching-Sung Li073812b2020-04-07 21:19:21 +0800904 void updateBottomActions(boolean hasWallpaperSelected) {
chihhangchuang803ea9a2020-04-21 13:03:10 +0800905 if (hasWallpaperSelected) {
chihhangchuang08abb582020-04-27 17:20:31 +0800906 mBottomActionBar.showActionsOnly(INFORMATION, APPLY);
chihhangchuang803ea9a2020-04-21 13:03:10 +0800907 } else {
chihhangchuang08abb582020-04-27 17:20:31 +0800908 mBottomActionBar.showActionsOnly(ROTATION);
chihhangchuang803ea9a2020-04-21 13:03:10 +0800909 }
Chuck Liao69630f12020-03-05 19:01:25 +0800910 }
911
912 private void updateThumbnail(WallpaperInfo selectedWallpaperInfo) {
Chuck Liaof40063f2020-03-03 18:35:24 +0800913 ThumbnailUpdater thumbnailUpdater = (ThumbnailUpdater) getParentFragment();
Chuck Liao69630f12020-03-05 19:01:25 +0800914 if (thumbnailUpdater == null) {
915 return;
916 }
917
918 if (selectedWallpaperInfo != null) {
919 thumbnailUpdater.updateThumbnail(selectedWallpaperInfo);
920 } else {
921 thumbnailUpdater.restoreThumbnails();
Chuck Liaof40063f2020-03-03 18:35:24 +0800922 }
923 }
924
“Chuck7ef99722020-03-22 04:34:03 +0800925 private void onWallpaperDestinationSet(int destination) {
926 WallpaperDestinationCallback wallpaperDestinationCallback =
927 (WallpaperDestinationCallback) getParentFragment();
928 if (wallpaperDestinationCallback == null) {
929 return;
930 }
931
932 wallpaperDestinationCallback.onDestinationSet(destination);
933 }
934
Ching-Sung Li073812b2020-04-07 21:19:21 +0800935 void onWallpaperSelected(@Nullable WallpaperInfo newSelectedWallpaperInfo,
Chuck Liaob3829fb2020-04-01 00:47:50 +0800936 int position) {
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800937 if (mSelectedWallpaperInfo == newSelectedWallpaperInfo) {
“Chuckffd832c2020-03-22 02:15:58 +0800938 return;
939 }
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800940 // Update current wallpaper.
“Chuckffd832c2020-03-22 02:15:58 +0800941 updateActivatedStatus(mSelectedWallpaperInfo == null
942 ? mAppliedWallpaperInfo : mSelectedWallpaperInfo, false);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800943 // Update new selected wallpaper.
944 updateActivatedStatus(newSelectedWallpaperInfo == null
945 ? mAppliedWallpaperInfo : newSelectedWallpaperInfo, true);
946
947 mSelectedWallpaperInfo = newSelectedWallpaperInfo;
948 updateBottomActions(mSelectedWallpaperInfo != null);
949 updateThumbnail(mSelectedWallpaperInfo);
950 // Populate wallpaper info to bottom sheet page.
chihhangchuang1a29e752020-04-28 18:22:53 +0800951 if (mSelectedWallpaperInfo != null && mWallpaperInfoView != null) {
952 mWallpaperInfoView.populateWallpaperInfo(
Chuck Liaob3829fb2020-04-01 00:47:50 +0800953 mSelectedWallpaperInfo.getAttributions(getContext()),
954 shouldShowMetadataInPreview(mSelectedWallpaperInfo));
955 }
956
957 if (mWallpaperSelectedListener != null) {
958 mWallpaperSelectedListener.onWallpaperSelected(position);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800959 }
Chuck Liaof40063f2020-03-03 18:35:24 +0800960 }
961
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800962 private void updateActivatedStatus(WallpaperInfo wallpaperInfo, boolean isActivated) {
“Chuckffd832c2020-03-22 02:15:58 +0800963 if (wallpaperInfo == null) {
964 return;
965 }
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800966 int index = mWallpapers.indexOf(wallpaperInfo);
967 index = (isRotationEnabled() || mCategory.supportsCustomPhotos())
968 ? index + 1 : index;
969 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
970 if (holder != null) {
971 holder.itemView.setActivated(isActivated);
972 } else {
973 // Item is not visible, make sure the item is re-bound when it becomes visible.
974 mAdapter.notifyItemChanged(index);
975 }
976 }
977
“Chuckffd832c2020-03-22 02:15:58 +0800978 private void updateAppliedStatus(WallpaperInfo wallpaperInfo, boolean isApplied) {
979 if (wallpaperInfo == null) {
980 return;
981 }
982 int index = mWallpapers.indexOf(wallpaperInfo);
983 index = (isRotationEnabled() || mCategory.supportsCustomPhotos())
984 ? index + 1 : index;
985 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
986 if (holder != null) {
987 holder.itemView.findViewById(R.id.check_circle)
988 .setVisibility(isApplied ? View.VISIBLE : View.GONE);
989 } else {
990 // Item is not visible, make sure the item is re-bound when it becomes visible.
991 mAdapter.notifyItemChanged(index);
992 }
993 }
994
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800995 private static boolean shouldShowMetadataInPreview(WallpaperInfo wallpaperInfo) {
996 android.app.WallpaperInfo wallpaperComponent = wallpaperInfo.getWallpaperComponent();
997 return wallpaperComponent == null || wallpaperComponent.getShowMetadataInPreview();
998 }
999
Chuck Liao11f4a762020-04-08 13:24:43 +08001000 private void refreshAppliedWallpaper() {
1001 // Clear the check mark and blue border(if it shows) of the old applied wallpaper.
1002 showCheckMarkAndBorderForAppliedWallpaper(false);
1003
1004 // Update to the new applied wallpaper.
1005 String appliedWallpaperId = getAppliedWallpaperId();
1006 Optional<WallpaperInfo> wallpaperInfoOptional = mWallpapers
1007 .stream()
1008 .filter(wallpaper -> wallpaper.getWallpaperId() != null)
1009 .filter(wallpaper -> wallpaper.getWallpaperId().equals(appliedWallpaperId))
1010 .findFirst();
1011 mAppliedWallpaperInfo = wallpaperInfoOptional.orElse(null);
1012
1013 // Set the check mark and blue border(if user doesn't select) of the new applied wallpaper.
1014 showCheckMarkAndBorderForAppliedWallpaper(true);
1015 }
1016
1017 private String getAppliedWallpaperId() {
1018 WallpaperPreferences prefs =
1019 InjectorProvider.getInjector().getPreferences(getContext());
1020 android.app.WallpaperInfo wallpaperInfo = mWallpaperManager.getWallpaperInfo();
1021 boolean isDestinationBoth =
1022 mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK) < 0;
1023
1024 if (isDestinationBoth || mWallpaperDestination == WallpaperPersister.DEST_HOME_SCREEN) {
1025 return wallpaperInfo != null
1026 ? wallpaperInfo.getServiceName() : prefs.getHomeWallpaperRemoteId();
1027 } else {
1028 return prefs.getLockWallpaperRemoteId();
1029 }
1030 }
1031
1032 private void showCheckMarkAndBorderForAppliedWallpaper(boolean show) {
1033 updateAppliedStatus(mAppliedWallpaperInfo, show);
1034 if (mSelectedWallpaperInfo == null) {
1035 updateActivatedStatus(mAppliedWallpaperInfo, show);
1036 }
1037 }
1038
Jon Miranda16ea1b12017-12-12 14:52:48 -08001039 /**
1040 * ViewHolder subclass for "daily refresh" tile in the RecyclerView, only shown if rotation is
1041 * enabled for this category.
1042 */
1043 private class RotationHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
1044
Chuck Liaoba401232020-03-13 20:11:04 +08001045 private CardView mTileLayout;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001046 private TextView mRotationMessage;
1047 private TextView mRotationTitle;
1048 private ImageView mRefreshIcon;
1049
1050 RotationHolder(View itemView) {
1051 super(itemView);
1052 itemView.setOnClickListener(this);
1053
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -07001054 mTileLayout = itemView.findViewById(R.id.daily_refresh);
1055 mRotationMessage = itemView.findViewById(R.id.rotation_tile_message);
1056 mRotationTitle = itemView.findViewById(R.id.rotation_tile_title);
1057 mRefreshIcon = itemView.findViewById(R.id.rotation_tile_refresh_icon);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001058 mTileLayout.getLayoutParams().height = mTileSizePx.y;
1059
1060 // If the feature flag for "dynamic start rotation tile" is not enabled, fall back to the
1061 // static UI with a blue accent color background and "Tap to turn on" text.
1062 if (!Flags.dynamicStartRotationTileEnabled) {
1063 mTileLayout.setBackgroundColor(
1064 getResources().getColor(R.color.rotation_tile_enabled_background_color));
1065 mRotationMessage.setText(R.string.daily_refresh_tile_subtitle);
1066 mRotationTitle.setTextColor(
1067 getResources().getColor(R.color.rotation_tile_enabled_title_text_color));
1068 mRotationMessage.setTextColor(
1069 getResources().getColor(R.color.rotation_tile_enabled_subtitle_text_color));
1070 mRefreshIcon.setColorFilter(
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -07001071 getResources().getColor(R.color.rotation_tile_enabled_refresh_icon_color),
1072 Mode.SRC_IN);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001073 return;
1074 }
1075
1076 // Initialize the state of the "start rotation" tile (i.e., whether it is gray or blue to
1077 // indicate if rotation is turned on for the current category) with last-known rotation state
1078 // that could be stale. The last-known rotation state is correct in most cases and is a good
1079 // starting point but may not be accurate if the user set a wallpaper through a 3rd party app
1080 // while this app was paused.
1081 int rotationState = mWallpaperRotationInitializer.getRotationInitializationStateDirty(
1082 getContext());
1083 bindRotationInitializationState(rotationState);
1084 }
1085
1086 @Override
1087 public void onClick(View v) {
Samuel Fufa03bc6ac2019-09-19 12:01:50 -07001088 DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
Jon Miranda16ea1b12017-12-12 14:52:48 -08001089 startRotationDialogFragment.setTargetFragment(
1090 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
1091 startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
1092 }
1093
1094 /**
1095 * Binds the provided rotation initialization state to the RotationHolder and updates the tile's
1096 * UI to be in sync with the state (i.e., message and color appropriately reflect the state to
1097 * the user).
1098 */
1099 void bindRotationInitializationState(@RotationInitializationState int rotationState) {
1100 int newBackgroundColor =
1101 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1102 ? getResources().getColor(R.color.rotation_tile_not_enabled_background_color)
1103 : getResources().getColor(R.color.rotation_tile_enabled_background_color);
1104 int newTitleTextColor =
1105 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1106 ? getResources().getColor(R.color.rotation_tile_not_enabled_title_text_color)
1107 : getResources().getColor(R.color.rotation_tile_enabled_title_text_color);
1108 int newSubtitleTextColor =
1109 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1110 ? getResources().getColor(R.color.rotation_tile_not_enabled_subtitle_text_color)
1111 : getResources().getColor(R.color.rotation_tile_enabled_subtitle_text_color);
1112 int newRefreshIconColor =
1113 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1114 ? getResources().getColor(R.color.rotation_tile_not_enabled_refresh_icon_color)
1115 : getResources().getColor(R.color.rotation_tile_enabled_refresh_icon_color);
1116
Chuck Liaoba401232020-03-13 20:11:04 +08001117 mTileLayout.setCardBackgroundColor(newBackgroundColor);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001118 mRotationTitle.setTextColor(newTitleTextColor);
1119 mRotationMessage.setText(getResIdForRotationState(rotationState));
1120 mRotationMessage.setTextColor(newSubtitleTextColor);
1121 mRefreshIcon.setColorFilter(newRefreshIconColor, Mode.SRC_IN);
1122 }
1123 }
1124
1125 /**
1126 * RecyclerView Adapter subclass for the wallpaper tiles in the RecyclerView.
1127 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001128 class IndividualAdapter extends RecyclerView.Adapter<ViewHolder> {
1129 static final int ITEM_VIEW_TYPE_ROTATION = 1;
1130 static final int ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER = 2;
1131 static final int ITEM_VIEW_TYPE_MY_PHOTOS = 3;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001132
1133 private final List<WallpaperInfo> mWallpapers;
1134
1135 private int mPendingSelectedAdapterPosition;
1136 private int mSelectedAdapterPosition;
1137
1138 IndividualAdapter(List<WallpaperInfo> wallpapers) {
1139 mWallpapers = wallpapers;
1140 mPendingSelectedAdapterPosition = -1;
1141 mSelectedAdapterPosition = -1;
1142 }
1143
1144 @Override
1145 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
1146 switch (viewType) {
1147 case ITEM_VIEW_TYPE_ROTATION:
1148 return createRotationHolder(parent);
1149 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1150 return createIndividualHolder(parent);
1151 case ITEM_VIEW_TYPE_MY_PHOTOS:
1152 return createMyPhotosHolder(parent);
1153 default:
1154 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1155 return null;
1156 }
1157 }
1158
1159 @Override
1160 public int getItemViewType(int position) {
1161 if (isRotationEnabled() && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
1162 return ITEM_VIEW_TYPE_ROTATION;
1163 }
1164
1165 // A category cannot have both a "start rotation" tile and a "my photos" tile.
1166 if (mCategory.supportsCustomPhotos()
1167 && !isRotationEnabled()
1168 && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
1169 return ITEM_VIEW_TYPE_MY_PHOTOS;
1170 }
1171
1172 return ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER;
1173 }
1174
1175 @Override
1176 public void onBindViewHolder(ViewHolder holder, int position) {
1177 int viewType = getItemViewType(position);
1178
1179 switch (viewType) {
1180 case ITEM_VIEW_TYPE_ROTATION:
1181 onBindRotationHolder(holder, position);
1182 break;
1183 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1184 onBindIndividualHolder(holder, position);
1185 break;
1186 case ITEM_VIEW_TYPE_MY_PHOTOS:
1187 ((MyPhotosViewHolder) holder).bind();
1188 break;
1189 default:
1190 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1191 }
1192 }
1193
1194 @Override
1195 public int getItemCount() {
1196 return (isRotationEnabled() || mCategory.supportsCustomPhotos())
1197 ? mWallpapers.size() + 1
1198 : mWallpapers.size();
1199 }
1200
1201 private ViewHolder createRotationHolder(ViewGroup parent) {
1202 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1203 View view;
1204
1205 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1206 view = layoutInflater.inflate(R.layout.grid_item_rotation_desktop, parent, false);
1207 SelectionAnimator selectionAnimator =
1208 new CheckmarkSelectionAnimator(getActivity(), view);
1209 return new DesktopRotationHolder(
1210 getActivity(), mTileSizePx.y, view, selectionAnimator,
1211 IndividualPickerFragment.this);
1212 } else { // MOBILE
1213 view = layoutInflater.inflate(R.layout.grid_item_rotation, parent, false);
1214 return new RotationHolder(view);
1215 }
1216 }
1217
1218 private ViewHolder createIndividualHolder(ViewGroup parent) {
1219 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1220 View view = layoutInflater.inflate(R.layout.grid_item_image, parent, false);
Chuck Liao6a37a1c2020-03-07 03:39:43 +08001221 if (!TEMP_BOTTOM_ACTION_BAR_FEATURE) {
1222 view.findViewById(R.id.tile).setPadding(0, 0, 0, 0);
1223 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001224
1225 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1226 SelectionAnimator selectionAnimator =
1227 new CheckmarkSelectionAnimator(getActivity(), view);
1228 return new SetIndividualHolder(
1229 getActivity(), mTileSizePx.y, view,
1230 selectionAnimator,
1231 new OnSetListener() {
1232 @Override
1233 public void onPendingWallpaperSet(int adapterPosition) {
1234 // Deselect and hide loading indicator for any previously pending tile.
1235 if (mPendingSelectedAdapterPosition != -1) {
1236 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1237 mPendingSelectedAdapterPosition);
1238 if (oldViewHolder instanceof SelectableHolder) {
1239 ((SelectableHolder) oldViewHolder).setSelectionState(
1240 SelectableHolder.SELECTION_STATE_DESELECTED);
1241 }
1242 }
1243
1244 if (mSelectedAdapterPosition != -1) {
1245 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1246 mSelectedAdapterPosition);
1247 if (oldViewHolder instanceof SelectableHolder) {
1248 ((SelectableHolder) oldViewHolder).setSelectionState(
1249 SelectableHolder.SELECTION_STATE_DESELECTED);
1250 }
1251 }
1252
1253 mPendingSelectedAdapterPosition = adapterPosition;
1254 }
1255
1256 @Override
1257 public void onWallpaperSet(int adapterPosition) {
1258 // No-op -- UI handles a new wallpaper being set by reacting to the
1259 // WallpaperChangedNotifier.
1260 }
1261
1262 @Override
1263 public void onWallpaperSetFailed(SetIndividualHolder holder) {
1264 showSetWallpaperErrorDialog();
1265 mPendingSetIndividualHolder = holder;
1266 }
1267 });
1268 } else { // MOBILE
Chuck Liao3d1a51c2020-02-17 18:29:34 +08001269 return new PreviewIndividualHolder(getActivity(), mTileSizePx.y, view);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001270 }
1271 }
1272
1273 private ViewHolder createMyPhotosHolder(ViewGroup parent) {
1274 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1275 View view = layoutInflater.inflate(R.layout.grid_item_my_photos, parent, false);
1276
Santiago Etchebeherefab49612019-01-15 12:22:42 -08001277 return new MyPhotosViewHolder(getActivity(),
1278 ((MyPhotosStarterProvider) getActivity()).getMyPhotosStarter(),
1279 mTileSizePx.y, view);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001280 }
1281
1282 /**
1283 * Marks the tile at the given position as selected with a visual indication. Also updates the
1284 * "currently selected" BottomSheet to reflect the newly selected tile.
1285 */
1286 private void updateSelectedTile(int newlySelectedPosition) {
1287 // Prevent multiple spinners from appearing with a user tapping several tiles in rapid
1288 // succession.
1289 if (mPendingSelectedAdapterPosition == mSelectedAdapterPosition) {
1290 return;
1291 }
1292
1293 if (mCurrentWallpaperBottomSheetPresenter != null) {
1294 mCurrentWallpaperBottomSheetPresenter.refreshCurrentWallpapers(
1295 IndividualPickerFragment.this);
1296
1297 if (mCurrentWallpaperBottomSheetExpandedRunnable != null) {
1298 mHandler.removeCallbacks(mCurrentWallpaperBottomSheetExpandedRunnable);
1299 }
1300 mCurrentWallpaperBottomSheetExpandedRunnable = new Runnable() {
1301 @Override
1302 public void run() {
1303 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
1304 }
1305 };
1306 mHandler.postDelayed(mCurrentWallpaperBottomSheetExpandedRunnable, 100);
1307 }
1308
1309 // User may have switched to another category, thus detaching this fragment, so check here.
1310 // NOTE: We do this check after updating the current wallpaper BottomSheet so that the update
1311 // still occurs in the UI after the user selects that other category.
1312 if (getActivity() == null) {
1313 return;
1314 }
1315
1316 // Update the newly selected wallpaper ViewHolder and the old one so that if
1317 // selection UI state applies (desktop UI), it is updated.
1318 if (mSelectedAdapterPosition >= 0) {
1319 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1320 mSelectedAdapterPosition);
1321 if (oldViewHolder instanceof SelectableHolder) {
1322 ((SelectableHolder) oldViewHolder).setSelectionState(
1323 SelectableHolder.SELECTION_STATE_DESELECTED);
1324 }
1325 }
1326
1327 // Animate selection of newly selected tile.
1328 ViewHolder newViewHolder = mImageGrid
1329 .findViewHolderForAdapterPosition(newlySelectedPosition);
1330 if (newViewHolder instanceof SelectableHolder) {
1331 ((SelectableHolder) newViewHolder).setSelectionState(
1332 SelectableHolder.SELECTION_STATE_SELECTED);
1333 }
1334
1335 mSelectedAdapterPosition = newlySelectedPosition;
1336
1337 // If the tile was in the last row of the grid, add space below it so the user can scroll down
1338 // and up to see the BottomSheet without it fully overlapping the newly selected tile.
1339 int spanCount = ((GridLayoutManager) mImageGrid.getLayoutManager()).getSpanCount();
1340 int numRows = (int) Math.ceil((float) getItemCount() / spanCount);
1341 int rowOfNewlySelectedTile = newlySelectedPosition / spanCount;
1342 boolean isInLastRow = rowOfNewlySelectedTile == numRows - 1;
1343
1344 updateImageGridPadding(isInLastRow /* addExtraBottomSpace */);
1345 }
1346
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001347 void onBindRotationHolder(ViewHolder holder, int position) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001348 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1349 String collectionId = mCategory.getCollectionId();
1350 ((DesktopRotationHolder) holder).bind(collectionId);
1351
1352 if (mWallpaperPreferences.getWallpaperPresentationMode()
1353 == WallpaperPreferences.PRESENTATION_MODE_ROTATING
1354 && collectionId.equals(mWallpaperPreferences.getHomeWallpaperCollectionId())) {
1355 mSelectedAdapterPosition = position;
1356 }
1357
1358 if (!mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
1359 updateDesktopDailyRotationThumbnail((DesktopRotationHolder) holder);
1360 mWasUpdateRunnableRun = true;
1361 }
1362 }
1363 }
1364
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001365 void onBindIndividualHolder(ViewHolder holder, int position) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001366 int wallpaperIndex = (isRotationEnabled() || mCategory.supportsCustomPhotos())
1367 ? position - 1 : position;
1368 WallpaperInfo wallpaper = mWallpapers.get(wallpaperIndex);
1369 ((IndividualHolder) holder).bindWallpaper(wallpaper);
“Chuck7ef99722020-03-22 04:34:03 +08001370 String appliedWallpaperId = getAppliedWallpaperId();
“Chuckffd832c2020-03-22 02:15:58 +08001371 boolean isWallpaperApplied = wallpaper.getWallpaperId().equals(appliedWallpaperId);
1372 boolean isWallpaperSelected = wallpaper.equals(mSelectedWallpaperInfo);
1373 boolean hasUserSelectedWallpaper = mSelectedWallpaperInfo != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001374
“Chuckffd832c2020-03-22 02:15:58 +08001375 if (isWallpaperApplied) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001376 mSelectedAdapterPosition = position;
“Chuckffd832c2020-03-22 02:15:58 +08001377 mAppliedWallpaperInfo = wallpaper;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001378 }
Chuck Liaof40063f2020-03-03 18:35:24 +08001379
1380 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
“Chuckffd832c2020-03-22 02:15:58 +08001381 holder.itemView.setActivated(
1382 (isWallpaperApplied && !hasUserSelectedWallpaper) || isWallpaperSelected);
1383 holder.itemView.findViewById(R.id.check_circle).setVisibility(
1384 isWallpaperApplied ? View.VISIBLE : View.GONE);
Chuck Liao69630f12020-03-05 19:01:25 +08001385 holder.itemView.findViewById(R.id.tile).setOnClickListener(
Chuck Liaob3829fb2020-04-01 00:47:50 +08001386 view -> onWallpaperSelected(wallpaper, position));
Chuck Liaof40063f2020-03-03 18:35:24 +08001387 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001388 }
1389 }
Chuck Liaoba401232020-03-13 20:11:04 +08001390
1391 private class GridPaddingDecoration extends RecyclerView.ItemDecoration {
1392
1393 private int mPadding;
1394
1395 GridPaddingDecoration(int padding) {
1396 mPadding = padding;
1397 }
1398
1399 @Override
1400 public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
1401 RecyclerView.State state) {
1402 int position = parent.getChildAdapterPosition(view);
1403 if (position >= 0) {
1404 outRect.left = mPadding;
1405 outRect.right = mPadding;
1406 }
1407 }
1408 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001409}