blob: a2b13a05bb5a258249f8fb68328aaf3f045ecc65 [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;
Chuck Liao8ec38e02020-02-26 20:59:32 +080019import static com.android.wallpaper.widget.BottomActionBar.BottomAction.CANCEL;
chihhangchuang22aa0cc2020-03-25 19:12:42 +080020import static com.android.wallpaper.widget.BottomActionBar.BottomAction.INFORMATION;
Chuck Liao8ec38e02020-02-26 20:59:32 +080021import static com.android.wallpaper.widget.BottomActionBar.BottomAction.ROTATION;
22
Jon Miranda16ea1b12017-12-12 14:52:48 -080023import android.app.Activity;
24import android.app.ProgressDialog;
“Chuck7ef99722020-03-22 04:34:03 +080025import android.app.WallpaperManager;
Jon Miranda16ea1b12017-12-12 14:52:48 -080026import android.content.Context;
Santiago Etchebehereb1854472019-06-06 17:44:54 -070027import android.content.res.Configuration;
Jon Miranda16ea1b12017-12-12 14:52:48 -080028import android.content.res.Resources.NotFoundException;
29import android.graphics.Point;
30import android.graphics.PorterDuff.Mode;
Chuck Liaoba401232020-03-13 20:11:04 +080031import android.graphics.Rect;
Jon Miranda16ea1b12017-12-12 14:52:48 -080032import android.os.Build.VERSION;
33import android.os.Build.VERSION_CODES;
34import android.os.Bundle;
35import android.os.Handler;
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -070036import android.service.wallpaper.WallpaperService;
Jon Miranda16ea1b12017-12-12 14:52:48 -080037import android.util.Log;
38import android.view.LayoutInflater;
39import android.view.View;
40import android.view.ViewGroup;
Jon Miranda16ea1b12017-12-12 14:52:48 -080041import android.widget.ImageView;
42import android.widget.TextView;
43import android.widget.Toast;
44
Santiago Etchebehereb1854472019-06-06 17:44:54 -070045import androidx.annotation.NonNull;
Chuck Liao69630f12020-03-05 19:01:25 +080046import androidx.annotation.Nullable;
Chuck Liaoba401232020-03-13 20:11:04 +080047import androidx.cardview.widget.CardView;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080048import androidx.fragment.app.DialogFragment;
49import androidx.fragment.app.Fragment;
50import 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;
58import com.android.wallpaper.config.Flags;
Santiago Etchebehere8648bb82019-08-06 17:09:02 -070059import com.android.wallpaper.model.Category;
60import com.android.wallpaper.model.CategoryProvider;
61import com.android.wallpaper.model.CategoryReceiver;
Chuck Liao69630f12020-03-05 19:01:25 +080062import com.android.wallpaper.model.LiveWallpaperInfo;
Jon Miranda16ea1b12017-12-12 14:52:48 -080063import com.android.wallpaper.model.WallpaperCategory;
64import com.android.wallpaper.model.WallpaperInfo;
65import com.android.wallpaper.model.WallpaperReceiver;
66import com.android.wallpaper.model.WallpaperRotationInitializer;
67import com.android.wallpaper.model.WallpaperRotationInitializer.Listener;
68import com.android.wallpaper.model.WallpaperRotationInitializer.NetworkPreference;
69import com.android.wallpaper.model.WallpaperRotationInitializer.RotationInitializationState;
Jon Miranda16ea1b12017-12-12 14:52:48 -080070import com.android.wallpaper.module.FormFactorChecker;
71import com.android.wallpaper.module.FormFactorChecker.FormFactor;
72import com.android.wallpaper.module.Injector;
73import com.android.wallpaper.module.InjectorProvider;
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -070074import com.android.wallpaper.module.PackageStatusNotifier;
Jon Miranda16ea1b12017-12-12 14:52:48 -080075import com.android.wallpaper.module.WallpaperChangedNotifier;
76import com.android.wallpaper.module.WallpaperPersister;
77import com.android.wallpaper.module.WallpaperPersister.Destination;
78import com.android.wallpaper.module.WallpaperPreferences;
Chuck Liao69630f12020-03-05 19:01:25 +080079import com.android.wallpaper.module.WallpaperSetter;
Jon Miranda16ea1b12017-12-12 14:52:48 -080080import com.android.wallpaper.picker.BaseActivity;
81import com.android.wallpaper.picker.CurrentWallpaperBottomSheetPresenter;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080082import com.android.wallpaper.picker.MyPhotosStarter.MyPhotosStarterProvider;
Jon Miranda16ea1b12017-12-12 14:52:48 -080083import com.android.wallpaper.picker.RotationStarter;
Chuck Liao69630f12020-03-05 19:01:25 +080084import com.android.wallpaper.picker.SetWallpaperDialogFragment;
Jon Miranda16ea1b12017-12-12 14:52:48 -080085import com.android.wallpaper.picker.SetWallpaperErrorDialogFragment;
86import com.android.wallpaper.picker.StartRotationDialogFragment;
87import com.android.wallpaper.picker.StartRotationErrorDialogFragment;
88import com.android.wallpaper.picker.WallpapersUiContainer;
89import com.android.wallpaper.picker.individual.SetIndividualHolder.OnSetListener;
90import com.android.wallpaper.util.DiskBasedLogger;
91import com.android.wallpaper.util.TileSizeCalculator;
Chuck Liao8ec38e02020-02-26 20:59:32 +080092import com.android.wallpaper.widget.BottomActionBar;
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;
Chuck Liao8ec38e02020-02-26 20:59:32 +080099import java.util.EnumSet;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800100import java.util.List;
Chuck Liao11f4a762020-04-08 13:24:43 +0800101import java.util.Optional;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800102import java.util.Random;
103
104/**
105 * Displays the Main UI for picking an individual wallpaper image.
106 */
107public class IndividualPickerFragment extends Fragment
108 implements RotationStarter, StartRotationErrorDialogFragment.Listener,
109 CurrentWallpaperBottomSheetPresenter.RefreshListener,
Chuck Liao69630f12020-03-05 19:01:25 +0800110 SetWallpaperErrorDialogFragment.Listener, SetWallpaperDialogFragment.Listener {
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800111 /**
112 * Position of a special tile that doesn't belong to an individual wallpaper of the category,
113 * such as "my photos" or "daily rotation".
114 */
115 static final int SPECIAL_FIXED_TILE_ADAPTER_POSITION = 0;
116 static final String ARG_CATEGORY_COLLECTION_ID = "category_collection_id";
117
Jon Miranda16ea1b12017-12-12 14:52:48 -0800118 private static final String TAG = "IndividualPickerFrgmnt";
Jon Miranda16ea1b12017-12-12 14:52:48 -0800119 private static final int UNUSED_REQUEST_CODE = 1;
120 private static final String TAG_START_ROTATION_DIALOG = "start_rotation_dialog";
121 private static final String TAG_START_ROTATION_ERROR_DIALOG = "start_rotation_error_dialog";
122 private static final String PROGRESS_DIALOG_NO_TITLE = null;
123 private static final boolean PROGRESS_DIALOG_INDETERMINATE = true;
124 private static final String TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT =
125 "individual_set_wallpaper_error_dialog";
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700126 private static final String KEY_NIGHT_MODE = "IndividualPickerFragment.NIGHT_MODE";
Jon Miranda16ea1b12017-12-12 14:52:48 -0800127
Chuck Liao8ec38e02020-02-26 20:59:32 +0800128 /**
129 * A temporary flag to hide the bottom action bar feature.
130 */
131 private static final boolean TEMP_BOTTOM_ACTION_BAR_FEATURE = false;
132
Chuck Liaof40063f2020-03-03 18:35:24 +0800133 /**
134 * An interface for updating the thumbnail with the specific wallpaper.
135 */
136 public interface ThumbnailUpdater {
137 /**
138 * Updates the thumbnail with the specific wallpaper.
139 */
140 void updateThumbnail(WallpaperInfo wallpaperInfo);
141
142 /**
143 * Restores to the thumbnails of the wallpapers which were applied.
144 */
145 void restoreThumbnails();
146 }
147
“Chuck7ef99722020-03-22 04:34:03 +0800148 /**
149 * An interface for receiving the destination of the new applied wallpaper.
150 */
151 public interface WallpaperDestinationCallback {
152 /**
153 * Called when the destination of the wallpaper is set.
154 *
155 * @param destination the destination which a wallpaper may be set.
156 * See {@link Destination} for more details.
157 */
158 void onDestinationSet(@Destination int destination);
159 }
160
Chuck Liaob3829fb2020-04-01 00:47:50 +0800161 /**
162 * The listener which will be notified when the wallpaper is selected.
163 */
164 public interface WallpaperSelectedListener {
165 /**
166 * Called when the wallpaper is selected.
167 *
168 * @param position the position of the selected wallpaper
169 */
170 void onWallpaperSelected(int position);
171 }
172
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800173 WallpaperPreferences mWallpaperPreferences;
174 WallpaperChangedNotifier mWallpaperChangedNotifier;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800175 RecyclerView mImageGrid;
176 IndividualAdapter mAdapter;
177 WallpaperCategory mCategory;
178 WallpaperRotationInitializer mWallpaperRotationInitializer;
179 List<WallpaperInfo> mWallpapers;
180 Point mTileSizePx;
181 WallpapersUiContainer mWallpapersUiContainer;
182 @FormFactor
183 int mFormFactor;
184 PackageStatusNotifier mPackageStatusNotifier;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800185
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800186 Handler mHandler;
187 Random mRandom;
188
189 WallpaperChangedNotifier.Listener mWallpaperChangedListener =
190 new WallpaperChangedNotifier.Listener() {
191 @Override
192 public void onWallpaperChanged() {
193 if (mFormFactor != FormFactorChecker.FORM_FACTOR_DESKTOP) {
194 return;
195 }
196
197 ViewHolder selectedViewHolder = mImageGrid.findViewHolderForAdapterPosition(
198 mAdapter.mSelectedAdapterPosition);
199
200 // Null remote ID => My Photos wallpaper, so deselect whatever was previously selected.
201 if (mWallpaperPreferences.getHomeWallpaperRemoteId() == null) {
202 if (selectedViewHolder instanceof SelectableHolder) {
203 ((SelectableHolder) selectedViewHolder).setSelectionState(
204 SelectableHolder.SELECTION_STATE_DESELECTED);
205 }
206 } else {
207 mAdapter.updateSelectedTile(mAdapter.mPendingSelectedAdapterPosition);
208 }
209 }
210 };
211 PackageStatusNotifier.Listener mAppStatusListener;
212
Jon Miranda16ea1b12017-12-12 14:52:48 -0800213 private ProgressDialog mProgressDialog;
214 private boolean mTestingMode;
215 private CurrentWallpaperBottomSheetPresenter mCurrentWallpaperBottomSheetPresenter;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800216 private SetIndividualHolder mPendingSetIndividualHolder;
217
218 /**
219 * Staged error dialog fragments that were unable to be shown when the activity didn't allow
220 * committing fragment transactions.
221 */
222 private SetWallpaperErrorDialogFragment mStagedSetWallpaperErrorDialogFragment;
223 private StartRotationErrorDialogFragment mStagedStartRotationErrorDialogFragment;
224
Jon Miranda16ea1b12017-12-12 14:52:48 -0800225 private Runnable mCurrentWallpaperBottomSheetExpandedRunnable;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800226
227 /**
228 * Whether {@code mUpdateDailyWallpaperThumbRunnable} has been run at least once in this
229 * invocation of the fragment.
230 */
231 private boolean mWasUpdateRunnableRun;
232
233 /**
234 * A Runnable which regularly updates the thumbnail for the "Daily wallpapers" tile in desktop
235 * mode.
236 */
237 private Runnable mUpdateDailyWallpaperThumbRunnable = new Runnable() {
238 @Override
239 public void run() {
240 ViewHolder viewHolder = mImageGrid.findViewHolderForAdapterPosition(
241 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
242 if (viewHolder instanceof DesktopRotationHolder) {
243 updateDesktopDailyRotationThumbnail((DesktopRotationHolder) viewHolder);
244 } else { // viewHolder is null
245 // If the rotation tile is unavailable (because user has scrolled down, causing the
246 // ViewHolder to be recycled), schedule the update for some time later. Once user scrolls up
247 // again, the ViewHolder will be re-bound and its thumbnail will be updated.
248 mHandler.postDelayed(mUpdateDailyWallpaperThumbRunnable,
249 DesktopRotationHolder.CROSSFADE_DURATION_MILLIS
250 + DesktopRotationHolder.CROSSFADE_DURATION_PAUSE_MILLIS);
251 }
252 }
253 };
254
Chuck Liao8ec38e02020-02-26 20:59:32 +0800255 private BottomActionBar mBottomActionBar;
Chuck Liao69630f12020-03-05 19:01:25 +0800256 private WallpaperSetter mWallpaperSetter;
“Chuckffd832c2020-03-22 02:15:58 +0800257 private WallpaperPersister mWallpaperPersister;
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800258 @Nullable private WallpaperInfo mSelectedWallpaperInfo;
“Chuckffd832c2020-03-22 02:15:58 +0800259 private WallpaperInfo mAppliedWallpaperInfo;
“Chuck7ef99722020-03-22 04:34:03 +0800260 private WallpaperManager mWallpaperManager;
261 private int mWallpaperDestination;
Chuck Liaob3829fb2020-04-01 00:47:50 +0800262 private WallpaperSelectedListener mWallpaperSelectedListener;
Chuck Liao8ec38e02020-02-26 20:59:32 +0800263
Jon Miranda16ea1b12017-12-12 14:52:48 -0800264 public static IndividualPickerFragment newInstance(String collectionId) {
265 Bundle args = new Bundle();
266 args.putString(ARG_CATEGORY_COLLECTION_ID, collectionId);
267
268 IndividualPickerFragment fragment = new IndividualPickerFragment();
269 fragment.setArguments(args);
270 return fragment;
271 }
272
“Chuck7ef99722020-03-22 04:34:03 +0800273 /**
274 * Highlights the applied wallpaper (if it exists) according to the destination a wallpaper
275 * would be set.
276 *
277 * @param wallpaperDestination the destination a wallpaper would be set.
278 * It will be either {@link Destination#DEST_HOME_SCREEN}
279 * or {@link Destination#DEST_LOCK_SCREEN}.
280 */
281 public void highlightAppliedWallpaper(@Destination int wallpaperDestination) {
282 mWallpaperDestination = wallpaperDestination;
Chuck Liao11f4a762020-04-08 13:24:43 +0800283 if (mWallpapers != null) {
284 refreshAppliedWallpaper();
“Chuck7ef99722020-03-22 04:34:03 +0800285 }
286 }
287
Jon Miranda16ea1b12017-12-12 14:52:48 -0800288 private static int getResIdForRotationState(@RotationInitializationState int rotationState) {
289 switch (rotationState) {
290 case WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED:
291 return R.string.daily_refresh_tile_subtitle;
292 case WallpaperRotationInitializer.ROTATION_HOME_ONLY:
293 return R.string.home_screen_message;
294 case WallpaperRotationInitializer.ROTATION_HOME_AND_LOCK:
295 return R.string.home_and_lock_short_label;
296 default:
297 Log.e(TAG, "Unknown rotation intialization state: " + rotationState);
298 return R.string.home_screen_message;
299 }
300 }
301
302 private void updateDesktopDailyRotationThumbnail(DesktopRotationHolder holder) {
303 int wallpapersIndex = mRandom.nextInt(mWallpapers.size());
304 Asset newThumbnailAsset = mWallpapers.get(wallpapersIndex).getThumbAsset(
305 getActivity());
306 holder.updateThumbnail(newThumbnailAsset, new DrawableLoadedListener() {
307 @Override
308 public void onDrawableLoaded() {
309 if (getActivity() == null) {
310 return;
311 }
312
313 // Schedule the next update of the thumbnail.
314 int delayMillis = DesktopRotationHolder.CROSSFADE_DURATION_MILLIS
315 + DesktopRotationHolder.CROSSFADE_DURATION_PAUSE_MILLIS;
316 mHandler.postDelayed(mUpdateDailyWallpaperThumbRunnable, delayMillis);
317 }
318 });
319 }
320
321 @Override
322 public void onCreate(Bundle savedInstanceState) {
323 super.onCreate(savedInstanceState);
324
325 Injector injector = InjectorProvider.getInjector();
326 Context appContext = getContext().getApplicationContext();
327 mWallpaperPreferences = injector.getPreferences(appContext);
328
329 mWallpaperChangedNotifier = WallpaperChangedNotifier.getInstance();
330 mWallpaperChangedNotifier.registerListener(mWallpaperChangedListener);
331
“Chuck7ef99722020-03-22 04:34:03 +0800332 mWallpaperManager = WallpaperManager.getInstance(appContext);
333
Jon Miranda16ea1b12017-12-12 14:52:48 -0800334 mFormFactor = injector.getFormFactorChecker(appContext).getFormFactor();
335
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700336 mPackageStatusNotifier = injector.getPackageStatusNotifier(appContext);
337
“Chuckffd832c2020-03-22 02:15:58 +0800338 mWallpaperPersister = injector.getWallpaperPersister(appContext);
Chuck Liao69630f12020-03-05 19:01:25 +0800339 mWallpaperSetter = new WallpaperSetter(
“Chuckffd832c2020-03-22 02:15:58 +0800340 mWallpaperPersister,
Chuck Liao69630f12020-03-05 19:01:25 +0800341 injector.getPreferences(appContext),
342 injector.getUserEventLogger(appContext),
343 false);
344
Jon Miranda16ea1b12017-12-12 14:52:48 -0800345 mWallpapers = new ArrayList<>();
346 mRandom = new Random();
347 mHandler = new Handler();
348
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700349 // Clear Glide's cache if night-mode changed to ensure thumbnails are reloaded
350 if (savedInstanceState != null && (savedInstanceState.getInt(KEY_NIGHT_MODE)
351 != (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK))) {
352 Glide.get(getContext()).clearMemory();
353 }
354
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700355 CategoryProvider categoryProvider = injector.getCategoryProvider(appContext);
356 categoryProvider.fetchCategories(new CategoryReceiver() {
357 @Override
358 public void onCategoryReceived(Category category) {
359 // Do nothing.
360 }
361
362 @Override
363 public void doneFetchingCategories() {
364 mCategory = (WallpaperCategory) categoryProvider.getCategory(
365 getArguments().getString(ARG_CATEGORY_COLLECTION_ID));
366 if (mCategory == null) {
367 DiskBasedLogger.e(TAG, "Failed to find the category.", getContext());
368
369 // The absence of this category in the CategoryProvider indicates a broken
370 // state, see b/38030129. Hence, finish the activity and return.
371 getActivity().finish();
372 return;
373 }
374 onCategoryLoaded();
375 }
376 }, false);
377 }
378
379 protected void onCategoryLoaded() {
380 mWallpaperRotationInitializer = mCategory.getWallpaperRotationInitializer();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700381 fetchWallpapers(false);
382
383 if (mCategory.supportsThirdParty()) {
384 mAppStatusListener = (packageName, status) -> {
385 if (status != PackageStatusNotifier.PackageStatus.REMOVED ||
386 mCategory.containsThirdParty(packageName)) {
387 fetchWallpapers(true);
388 }
389 };
390 mPackageStatusNotifier.addListener(mAppStatusListener,
391 WallpaperService.SERVICE_INTERFACE);
392 }
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700393
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700394 maybeSetUpImageGrid();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700395 }
396
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800397 void fetchWallpapers(boolean forceReload) {
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700398 mWallpapers.clear();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800399 mCategory.fetchWallpapers(getActivity().getApplicationContext(), new WallpaperReceiver() {
400 @Override
401 public void onWallpapersReceived(List<WallpaperInfo> wallpapers) {
402 for (WallpaperInfo wallpaper : wallpapers) {
403 mWallpapers.add(wallpaper);
404 }
405
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700406 // Wallpapers may load after the adapter is initialized, in which case we have
407 // to explicitly notify that the data set has changed.
Jon Miranda16ea1b12017-12-12 14:52:48 -0800408 if (mAdapter != null) {
409 mAdapter.notifyDataSetChanged();
410 }
411
412 if (mWallpapersUiContainer != null) {
413 mWallpapersUiContainer.onWallpapersReady();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700414 } else {
415 if (wallpapers.isEmpty()) {
416 // If there are no more wallpapers and we're on phone, just finish the
417 // Activity.
418 Activity activity = getActivity();
419 if (activity != null
420 && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
421 activity.finish();
422 }
423 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800424 }
425 }
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700426 }, forceReload);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800427 }
428
429 @Override
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700430 public void onSaveInstanceState(@NonNull Bundle outState) {
431 super.onSaveInstanceState(outState);
Santiago Etchebehere0ec065c2019-06-13 11:30:21 -0700432 outState.putInt(KEY_NIGHT_MODE,
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700433 getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK);
434 }
435
436 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800437 public View onCreateView(LayoutInflater inflater, ViewGroup container,
438 Bundle savedInstanceState) {
439 View view = inflater.inflate(R.layout.fragment_individual_picker, container, false);
440
441 mTileSizePx = TileSizeCalculator.getIndividualTileSize(getActivity());
442
443 mImageGrid = (RecyclerView) view.findViewById(R.id.wallpaper_grid);
444 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
445 int gridPaddingPx = getResources().getDimensionPixelSize(R.dimen.grid_padding_desktop);
446 updateImageGridPadding(false /* addExtraBottomSpace */);
447 mImageGrid.setScrollBarSize(gridPaddingPx);
448 }
Chuck Liaoba401232020-03-13 20:11:04 +0800449 mImageGrid.addItemDecoration(new GridPaddingDecoration(
450 getResources().getDimensionPixelSize(R.dimen.grid_padding)));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800451
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700452 maybeSetUpImageGrid();
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700453
Jon Miranda16ea1b12017-12-12 14:52:48 -0800454 setUpBottomSheet();
455
Chuck Liao8ec38e02020-02-26 20:59:32 +0800456 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
457 mBottomActionBar = getActivity().findViewById(R.id.bottom_actionbar);
458
Chuck Liao69630f12020-03-05 19:01:25 +0800459 mBottomActionBar.setActionClickListener(CANCEL, unused -> {
460 if (mSelectedWallpaperInfo != null) {
Chuck Liaob3829fb2020-04-01 00:47:50 +0800461 onWallpaperSelected(null, 0);
Chuck Liao69630f12020-03-05 19:01:25 +0800462 return;
463 }
464 getActivity().onBackPressed();
465 });
Chuck Liao8ec38e02020-02-26 20:59:32 +0800466 mBottomActionBar.setActionClickListener(ROTATION, unused -> {
467 DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
468 startRotationDialogFragment.setTargetFragment(
469 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
470 startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
471 });
Chuck Liao69630f12020-03-05 19:01:25 +0800472 mBottomActionBar.setActionClickListener(APPLY, unused -> {
473 mBottomActionBar.disableActions();
474 mWallpaperSetter.requestDestination(getActivity(), getFragmentManager(), this,
475 mSelectedWallpaperInfo instanceof LiveWallpaperInfo);
476 });
Chuck Liao8ec38e02020-02-26 20:59:32 +0800477
Chuck Liao4f059312020-03-13 23:09:46 +0800478 mBottomActionBar.show();
Chuck Liao8ec38e02020-02-26 20:59:32 +0800479 mBottomActionBar.showActionsOnly(
480 isRotationEnabled() ? EnumSet.of(CANCEL, ROTATION) : EnumSet.of(CANCEL));
481 }
482
Jon Miranda16ea1b12017-12-12 14:52:48 -0800483 return view;
484 }
485
486 @Override
Chuck Liao8ec38e02020-02-26 20:59:32 +0800487 public void onDestroyView() {
488 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
Chuck Liao4f059312020-03-13 23:09:46 +0800489 mBottomActionBar.hide();
Chuck Liao8ec38e02020-02-26 20:59:32 +0800490 mBottomActionBar.clearActionClickListeners();
Chuck Liao69630f12020-03-05 19:01:25 +0800491 updateThumbnail(null);
Chuck Liao8ec38e02020-02-26 20:59:32 +0800492 }
493 super.onDestroyView();
494 }
495
496 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800497 public void onClickTryAgain(@Destination int unused) {
498 if (mPendingSetIndividualHolder != null) {
499 mPendingSetIndividualHolder.setWallpaper();
500 }
501 }
502
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800503 void updateImageGridPadding(boolean addExtraBottomSpace) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800504 int gridPaddingPx = getResources().getDimensionPixelSize(R.dimen.grid_padding_desktop);
505 int bottomSheetHeightPx = getResources().getDimensionPixelSize(
506 R.dimen.current_wallpaper_bottom_sheet_layout_height);
507 int paddingBottomPx = addExtraBottomSpace ? bottomSheetHeightPx : 0;
508 // Only left and top may be set in order for the GridMarginDecoration to work properly.
509 mImageGrid.setPadding(
510 gridPaddingPx, gridPaddingPx, 0, paddingBottomPx);
511 }
512
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700513 private void maybeSetUpImageGrid() {
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700514 // Skip if mImageGrid been initialized yet
515 if (mImageGrid == null) {
516 return;
517 }
518 // Skip if category hasn't loaded yet
519 if (mCategory == null) {
520 return;
521 }
522 // Skip if the adapter was already created
523 if (mAdapter != null) {
524 return;
525 }
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700526 setUpImageGrid();
527 }
528
529 /**
530 * Create the adapter and assign it to mImageGrid.
531 * Both mImageGrid and mCategory are guaranteed to not be null when this method is called.
532 */
533 void setUpImageGrid() {
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800534 mAdapter = new IndividualAdapter(mWallpapers);
535 mImageGrid.setAdapter(mAdapter);
536 mImageGrid.setLayoutManager(new GridLayoutManager(getActivity(), getNumColumns()));
537 }
538
Jon Miranda16ea1b12017-12-12 14:52:48 -0800539 /**
540 * Enables and populates the "Currently set" wallpaper BottomSheet.
541 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800542 void setUpBottomSheet() {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800543 mImageGrid.addOnScrollListener(new OnScrollListener() {
544 @Override
545 public void onScrolled(RecyclerView recyclerView, int dx, final int dy) {
546 if (mCurrentWallpaperBottomSheetPresenter == null) {
547 return;
548 }
549
550 if (mCurrentWallpaperBottomSheetExpandedRunnable != null) {
551 mHandler.removeCallbacks(mCurrentWallpaperBottomSheetExpandedRunnable);
552 }
553 mCurrentWallpaperBottomSheetExpandedRunnable = new Runnable() {
554 @Override
555 public void run() {
556 if (dy > 0) {
557 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(false);
558 } else {
559 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
560 }
561 }
562 };
563 mHandler.postDelayed(mCurrentWallpaperBottomSheetExpandedRunnable, 100);
564 }
565 });
566 }
567
568 @Override
569 public void onResume() {
570 super.onResume();
571
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700572 WallpaperPreferences preferences = InjectorProvider.getInjector()
573 .getPreferences(getActivity());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800574 preferences.setLastAppActiveTimestamp(new Date().getTime());
575
576 // Reset Glide memory settings to a "normal" level of usage since it may have been lowered in
577 // PreviewFragment.
578 Glide.get(getActivity()).setMemoryCategory(MemoryCategory.NORMAL);
579
580 // Show the staged 'start rotation' error dialog fragment if there is one that was unable to be
581 // shown earlier when this fragment's hosting activity didn't allow committing fragment
582 // transactions.
583 if (mStagedStartRotationErrorDialogFragment != null) {
584 mStagedStartRotationErrorDialogFragment.show(
585 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
586 mStagedStartRotationErrorDialogFragment = null;
587 }
588
589 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one
590 // that was unable to be shown earlier when this fragment's hosting activity didn't allow
591 // committing fragment transactions.
592 if (mStagedSetWallpaperErrorDialogFragment != null) {
593 mStagedSetWallpaperErrorDialogFragment.show(
594 getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
595 mStagedSetWallpaperErrorDialogFragment = null;
596 }
597
598 if (isRotationEnabled()) {
599 if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
600 // Refresh the state of the "start rotation" in case something changed the current daily
601 // rotation while this fragment was paused.
602 RotationHolder rotationHolder = (RotationHolder) mImageGrid
603 .findViewHolderForAdapterPosition(
604 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
605 // The RotationHolder may be null if the RecyclerView has not created the view
606 // holder yet.
607 if (rotationHolder != null && Flags.dynamicStartRotationTileEnabled) {
608 refreshRotationHolder(rotationHolder);
609 }
610 } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
611 if (mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
612 // Must be resuming from a previously stopped state, so re-schedule the update of the
613 // daily wallpapers tile thumbnail.
614 mUpdateDailyWallpaperThumbRunnable.run();
615 }
616 }
617 }
618
619 }
620
621 @Override
622 public void onStop() {
623 super.onStop();
624 mHandler.removeCallbacks(mUpdateDailyWallpaperThumbRunnable);
625 }
626
627 @Override
628 public void onDestroy() {
629 super.onDestroy();
630 if (mProgressDialog != null) {
631 mProgressDialog.dismiss();
632 }
633 mWallpaperChangedNotifier.unregisterListener(mWallpaperChangedListener);
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700634 if (mAppStatusListener != null) {
635 mPackageStatusNotifier.removeListener(mAppStatusListener);
636 }
Chuck Liao69630f12020-03-05 19:01:25 +0800637 mWallpaperSetter.cleanUp();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800638 }
639
640 @Override
641 public void retryStartRotation(@NetworkPreference int networkPreference) {
642 startRotation(networkPreference);
643 }
644
645 public void setCurrentWallpaperBottomSheetPresenter(
646 CurrentWallpaperBottomSheetPresenter presenter) {
647 mCurrentWallpaperBottomSheetPresenter = presenter;
648 }
649
650 public void setWallpapersUiContainer(WallpapersUiContainer uiContainer) {
651 mWallpapersUiContainer = uiContainer;
652 }
653
Chuck Liaob3829fb2020-04-01 00:47:50 +0800654 public void setOnWallpaperSelectedListener(
655 WallpaperSelectedListener wallpaperSelectedListener) {
656 mWallpaperSelectedListener = wallpaperSelectedListener;
657 }
658
659 /**
660 * Resizes the layout's height.
661 */
662 public void resizeLayout(int height) {
663 mImageGrid.getLayoutParams().height = height;
664 mImageGrid.requestLayout();
665 }
666
667 /**
668 * Scrolls to the specific item.
669 *
670 * @param position the position of the item
671 */
672 public void scrollToPosition(int position) {
673 ((GridLayoutManager) mImageGrid.getLayoutManager())
674 .scrollToPositionWithOffset(position, /* offset= */ 0);
675 }
676
Jon Miranda16ea1b12017-12-12 14:52:48 -0800677 /**
678 * Enable a test mode of operation -- in which certain UI features are disabled to allow for
679 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog
680 * constantly keeps the UI thread alive and blocks a test forever.
681 *
682 * @param testingMode
683 */
684 void setTestingMode(boolean testingMode) {
685 mTestingMode = testingMode;
686 }
687
688 /**
689 * Asynchronously fetches the refreshed rotation initialization state that is up to date with the
690 * state of the user's device and binds the state of the current category's rotation to the "start
691 * rotation" tile.
692 */
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700693 private void refreshRotationHolder(RotationHolder rotationHolder) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800694 mWallpaperRotationInitializer.fetchRotationInitializationState(getContext(),
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700695 rotationState -> {
696 // Update the UI state of the "start rotation" tile displayed on screen.
697 // Do this in a Handler so it is scheduled at the end of the message queue.
698 // This is necessary to ensure we do not remove or add data from the adapter
699 // while the layout is still being computed. RecyclerView documentation
700 // therefore recommends performing such changes in a Handler.
701 new Handler().post(() -> {
702 // A config change may have destroyed the activity since the refresh
703 // started, so check for that to avoid an NPE.
704 if (getActivity() == null) {
705 return;
706 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800707
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700708 rotationHolder.bindRotationInitializationState(rotationState);
709 });
Jon Miranda16ea1b12017-12-12 14:52:48 -0800710 });
711 }
712
713 @Override
714 public void startRotation(@NetworkPreference final int networkPreference) {
715 if (!isRotationEnabled()) {
716 Log.e(TAG, "Rotation is not enabled for this category " + mCategory.getTitle());
717 return;
718 }
719
720 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
721 // causes Espresso to hang once the dialog is shown.
722 if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE && !mTestingMode) {
723 int themeResId;
724 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
725 themeResId = R.style.ProgressDialogThemePreL;
726 } else {
727 themeResId = R.style.LightDialogTheme;
728 }
729 mProgressDialog = new ProgressDialog(getActivity(), themeResId);
730
731 mProgressDialog.setTitle(PROGRESS_DIALOG_NO_TITLE);
732 mProgressDialog.setMessage(
733 getResources().getString(R.string.start_rotation_progress_message));
734 mProgressDialog.setIndeterminate(PROGRESS_DIALOG_INDETERMINATE);
735 mProgressDialog.show();
736 }
737
738 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
739 mAdapter.mPendingSelectedAdapterPosition = SPECIAL_FIXED_TILE_ADAPTER_POSITION;
740 }
741
742 final Context appContext = getActivity().getApplicationContext();
743
744 mWallpaperRotationInitializer.setFirstWallpaperInRotation(
745 appContext,
746 networkPreference,
747 new Listener() {
748 @Override
749 public void onFirstWallpaperInRotationSet() {
750 if (mProgressDialog != null) {
751 mProgressDialog.dismiss();
752 }
753
754 // The fragment may be detached from its containing activity if the user exits the
755 // app before the first wallpaper image in rotation finishes downloading.
756 Activity activity = getActivity();
757
Jon Miranda16ea1b12017-12-12 14:52:48 -0800758
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700759 if (mWallpaperRotationInitializer.startRotation(appContext)) {
760 if (activity != null
761 && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
762 try {
763 Toast.makeText(getActivity(),
764 R.string.wallpaper_set_successfully_message,
765 Toast.LENGTH_SHORT).show();
766 } catch (NotFoundException e) {
767 Log.e(TAG, "Could not show toast " + e);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800768 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800769
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700770 activity.setResult(Activity.RESULT_OK);
771 activity.finish();
772 } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
773 mAdapter.updateSelectedTile(SPECIAL_FIXED_TILE_ADAPTER_POSITION);
774 }
775 } else { // Failed to start rotation.
776 showStartRotationErrorDialog(networkPreference);
777
778 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
779 DesktopRotationHolder rotationViewHolder =
780 (DesktopRotationHolder)
781 mImageGrid.findViewHolderForAdapterPosition(
782 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
783 rotationViewHolder.setSelectionState(
784 SelectableHolder.SELECTION_STATE_DESELECTED);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800785 }
786 }
787 }
788
789 @Override
790 public void onError() {
791 if (mProgressDialog != null) {
792 mProgressDialog.dismiss();
793 }
794
795 showStartRotationErrorDialog(networkPreference);
796
797 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
798 DesktopRotationHolder rotationViewHolder =
799 (DesktopRotationHolder) mImageGrid.findViewHolderForAdapterPosition(
800 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
801 rotationViewHolder.setSelectionState(SelectableHolder.SELECTION_STATE_DESELECTED);
802 }
803 }
804 });
805 }
806
807 private void showStartRotationErrorDialog(@NetworkPreference int networkPreference) {
808 BaseActivity activity = (BaseActivity) getActivity();
809 if (activity != null) {
810 StartRotationErrorDialogFragment startRotationErrorDialogFragment =
811 StartRotationErrorDialogFragment.newInstance(networkPreference);
812 startRotationErrorDialogFragment.setTargetFragment(
813 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
814
815 if (activity.isSafeToCommitFragmentTransaction()) {
816 startRotationErrorDialogFragment.show(
817 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
818 } else {
819 mStagedStartRotationErrorDialogFragment = startRotationErrorDialogFragment;
820 }
821 }
822 }
823
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800824 int getNumColumns() {
Ching-Sung Li9df77a32019-07-10 11:45:30 +0800825 Activity activity = getActivity();
826 return activity == null ? 0 : TileSizeCalculator.getNumIndividualColumns(activity);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800827 }
828
829 /**
830 * Returns whether rotation is enabled for this category.
831 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800832 boolean isRotationEnabled() {
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700833 return mWallpaperRotationInitializer != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800834 }
835
836 @Override
837 public void onCurrentWallpaperRefreshed() {
838 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
839 }
840
Chuck Liao69630f12020-03-05 19:01:25 +0800841
842 @Override
843 public void onSet(int destination) {
844 if (mSelectedWallpaperInfo == null) {
845 Log.e(TAG, "Unable to set wallpaper since the selected wallpaper info is null");
846 return;
847 }
848
“Chuckffd832c2020-03-22 02:15:58 +0800849 mWallpaperPersister.setWallpaperInfoInPreview(mSelectedWallpaperInfo);
Chuck Liao69630f12020-03-05 19:01:25 +0800850 if (mSelectedWallpaperInfo instanceof LiveWallpaperInfo) {
851 mWallpaperSetter.setCurrentWallpaper(getActivity(), mSelectedWallpaperInfo, null,
852 destination, 0, null, mSetWallpaperCallback);
853 } else {
854 mWallpaperSetter.setCurrentWallpaper(
855 getActivity(), mSelectedWallpaperInfo, destination, mSetWallpaperCallback);
856 }
“Chuck7ef99722020-03-22 04:34:03 +0800857 onWallpaperDestinationSet(destination);
Chuck Liao69630f12020-03-05 19:01:25 +0800858 }
859
860 private WallpaperPersister.SetWallpaperCallback mSetWallpaperCallback =
861 new WallpaperPersister.SetWallpaperCallback() {
862 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800863 public void onSuccess(WallpaperInfo wallpaperInfo) {
Chuck Liao69630f12020-03-05 19:01:25 +0800864 // TODO(b/150913705): Show the snack bar.
865 mBottomActionBar.enableActions();
Chuck Liao11f4a762020-04-08 13:24:43 +0800866 refreshAppliedWallpaper();
“Chuckffd832c2020-03-22 02:15:58 +0800867
868 mWallpaperPersister.onLiveWallpaperSet();
Chuck Liao69630f12020-03-05 19:01:25 +0800869 }
870
871 @Override
872 public void onError(@Nullable Throwable throwable) {
873 Log.e(TAG, "Can't apply the wallpaper.");
874 mBottomActionBar.enableActions();
875 }
876 };
877
878 @Override
879 public void onDialogDismissed(boolean withItemSelected) {
880 if (!withItemSelected) {
881 mBottomActionBar.enableActions();
882 }
883 }
884
Jon Miranda16ea1b12017-12-12 14:52:48 -0800885 /**
886 * Shows a "set wallpaper" error dialog with a failure message and button to try again.
887 */
888 private void showSetWallpaperErrorDialog() {
889 SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance(
890 R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH);
891 dialogFragment.setTargetFragment(this, UNUSED_REQUEST_CODE);
892
893 if (((BaseActivity) getActivity()).isSafeToCommitFragmentTransaction()) {
894 dialogFragment.show(getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
895 } else {
896 mStagedSetWallpaperErrorDialogFragment = dialogFragment;
897 }
898 }
899
Chuck Liao69630f12020-03-05 19:01:25 +0800900 private void updateBottomActions(boolean hasWallpaperSelected) {
901 mBottomActionBar.showActions(
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800902 hasWallpaperSelected ? EnumSet.of(APPLY, INFORMATION) : EnumSet.of(ROTATION));
Chuck Liao69630f12020-03-05 19:01:25 +0800903 mBottomActionBar.hideActions(
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800904 hasWallpaperSelected ? EnumSet.of(ROTATION) : EnumSet.of(APPLY, INFORMATION));
Chuck Liao69630f12020-03-05 19:01:25 +0800905 }
906
907 private void updateThumbnail(WallpaperInfo selectedWallpaperInfo) {
Chuck Liaof40063f2020-03-03 18:35:24 +0800908 ThumbnailUpdater thumbnailUpdater = (ThumbnailUpdater) getParentFragment();
Chuck Liao69630f12020-03-05 19:01:25 +0800909 if (thumbnailUpdater == null) {
910 return;
911 }
912
913 if (selectedWallpaperInfo != null) {
914 thumbnailUpdater.updateThumbnail(selectedWallpaperInfo);
915 } else {
916 thumbnailUpdater.restoreThumbnails();
Chuck Liaof40063f2020-03-03 18:35:24 +0800917 }
918 }
919
“Chuck7ef99722020-03-22 04:34:03 +0800920 private void onWallpaperDestinationSet(int destination) {
921 WallpaperDestinationCallback wallpaperDestinationCallback =
922 (WallpaperDestinationCallback) getParentFragment();
923 if (wallpaperDestinationCallback == null) {
924 return;
925 }
926
927 wallpaperDestinationCallback.onDestinationSet(destination);
928 }
929
Chuck Liaob3829fb2020-04-01 00:47:50 +0800930 private void onWallpaperSelected(@Nullable WallpaperInfo newSelectedWallpaperInfo,
931 int position) {
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800932 if (mSelectedWallpaperInfo == newSelectedWallpaperInfo) {
“Chuckffd832c2020-03-22 02:15:58 +0800933 return;
934 }
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800935 // Update current wallpaper.
“Chuckffd832c2020-03-22 02:15:58 +0800936 updateActivatedStatus(mSelectedWallpaperInfo == null
937 ? mAppliedWallpaperInfo : mSelectedWallpaperInfo, false);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800938 // Update new selected wallpaper.
939 updateActivatedStatus(newSelectedWallpaperInfo == null
940 ? mAppliedWallpaperInfo : newSelectedWallpaperInfo, true);
941
942 mSelectedWallpaperInfo = newSelectedWallpaperInfo;
943 updateBottomActions(mSelectedWallpaperInfo != null);
944 updateThumbnail(mSelectedWallpaperInfo);
945 // Populate wallpaper info to bottom sheet page.
946 if (mSelectedWallpaperInfo != null) {
947 mBottomActionBar.populateInfoPage(
Chuck Liaob3829fb2020-04-01 00:47:50 +0800948 mSelectedWallpaperInfo.getAttributions(getContext()),
949 shouldShowMetadataInPreview(mSelectedWallpaperInfo));
950 }
951
952 if (mWallpaperSelectedListener != null) {
953 mWallpaperSelectedListener.onWallpaperSelected(position);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800954 }
Chuck Liaof40063f2020-03-03 18:35:24 +0800955 }
956
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800957 private void updateActivatedStatus(WallpaperInfo wallpaperInfo, boolean isActivated) {
“Chuckffd832c2020-03-22 02:15:58 +0800958 if (wallpaperInfo == null) {
959 return;
960 }
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800961 int index = mWallpapers.indexOf(wallpaperInfo);
962 index = (isRotationEnabled() || mCategory.supportsCustomPhotos())
963 ? index + 1 : index;
964 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
965 if (holder != null) {
966 holder.itemView.setActivated(isActivated);
967 } else {
968 // Item is not visible, make sure the item is re-bound when it becomes visible.
969 mAdapter.notifyItemChanged(index);
970 }
971 }
972
“Chuckffd832c2020-03-22 02:15:58 +0800973 private void updateAppliedStatus(WallpaperInfo wallpaperInfo, boolean isApplied) {
974 if (wallpaperInfo == null) {
975 return;
976 }
977 int index = mWallpapers.indexOf(wallpaperInfo);
978 index = (isRotationEnabled() || mCategory.supportsCustomPhotos())
979 ? index + 1 : index;
980 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
981 if (holder != null) {
982 holder.itemView.findViewById(R.id.check_circle)
983 .setVisibility(isApplied ? View.VISIBLE : View.GONE);
984 } else {
985 // Item is not visible, make sure the item is re-bound when it becomes visible.
986 mAdapter.notifyItemChanged(index);
987 }
988 }
989
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800990 private static boolean shouldShowMetadataInPreview(WallpaperInfo wallpaperInfo) {
991 android.app.WallpaperInfo wallpaperComponent = wallpaperInfo.getWallpaperComponent();
992 return wallpaperComponent == null || wallpaperComponent.getShowMetadataInPreview();
993 }
994
Chuck Liao11f4a762020-04-08 13:24:43 +0800995 private void refreshAppliedWallpaper() {
996 // Clear the check mark and blue border(if it shows) of the old applied wallpaper.
997 showCheckMarkAndBorderForAppliedWallpaper(false);
998
999 // Update to the new applied wallpaper.
1000 String appliedWallpaperId = getAppliedWallpaperId();
1001 Optional<WallpaperInfo> wallpaperInfoOptional = mWallpapers
1002 .stream()
1003 .filter(wallpaper -> wallpaper.getWallpaperId() != null)
1004 .filter(wallpaper -> wallpaper.getWallpaperId().equals(appliedWallpaperId))
1005 .findFirst();
1006 mAppliedWallpaperInfo = wallpaperInfoOptional.orElse(null);
1007
1008 // Set the check mark and blue border(if user doesn't select) of the new applied wallpaper.
1009 showCheckMarkAndBorderForAppliedWallpaper(true);
1010 }
1011
1012 private String getAppliedWallpaperId() {
1013 WallpaperPreferences prefs =
1014 InjectorProvider.getInjector().getPreferences(getContext());
1015 android.app.WallpaperInfo wallpaperInfo = mWallpaperManager.getWallpaperInfo();
1016 boolean isDestinationBoth =
1017 mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK) < 0;
1018
1019 if (isDestinationBoth || mWallpaperDestination == WallpaperPersister.DEST_HOME_SCREEN) {
1020 return wallpaperInfo != null
1021 ? wallpaperInfo.getServiceName() : prefs.getHomeWallpaperRemoteId();
1022 } else {
1023 return prefs.getLockWallpaperRemoteId();
1024 }
1025 }
1026
1027 private void showCheckMarkAndBorderForAppliedWallpaper(boolean show) {
1028 updateAppliedStatus(mAppliedWallpaperInfo, show);
1029 if (mSelectedWallpaperInfo == null) {
1030 updateActivatedStatus(mAppliedWallpaperInfo, show);
1031 }
1032 }
1033
Jon Miranda16ea1b12017-12-12 14:52:48 -08001034 /**
1035 * ViewHolder subclass for "daily refresh" tile in the RecyclerView, only shown if rotation is
1036 * enabled for this category.
1037 */
1038 private class RotationHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
1039
Chuck Liaoba401232020-03-13 20:11:04 +08001040 private CardView mTileLayout;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001041 private TextView mRotationMessage;
1042 private TextView mRotationTitle;
1043 private ImageView mRefreshIcon;
1044
1045 RotationHolder(View itemView) {
1046 super(itemView);
1047 itemView.setOnClickListener(this);
1048
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -07001049 mTileLayout = itemView.findViewById(R.id.daily_refresh);
1050 mRotationMessage = itemView.findViewById(R.id.rotation_tile_message);
1051 mRotationTitle = itemView.findViewById(R.id.rotation_tile_title);
1052 mRefreshIcon = itemView.findViewById(R.id.rotation_tile_refresh_icon);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001053 mTileLayout.getLayoutParams().height = mTileSizePx.y;
1054
1055 // If the feature flag for "dynamic start rotation tile" is not enabled, fall back to the
1056 // static UI with a blue accent color background and "Tap to turn on" text.
1057 if (!Flags.dynamicStartRotationTileEnabled) {
1058 mTileLayout.setBackgroundColor(
1059 getResources().getColor(R.color.rotation_tile_enabled_background_color));
1060 mRotationMessage.setText(R.string.daily_refresh_tile_subtitle);
1061 mRotationTitle.setTextColor(
1062 getResources().getColor(R.color.rotation_tile_enabled_title_text_color));
1063 mRotationMessage.setTextColor(
1064 getResources().getColor(R.color.rotation_tile_enabled_subtitle_text_color));
1065 mRefreshIcon.setColorFilter(
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -07001066 getResources().getColor(R.color.rotation_tile_enabled_refresh_icon_color),
1067 Mode.SRC_IN);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001068 return;
1069 }
1070
1071 // Initialize the state of the "start rotation" tile (i.e., whether it is gray or blue to
1072 // indicate if rotation is turned on for the current category) with last-known rotation state
1073 // that could be stale. The last-known rotation state is correct in most cases and is a good
1074 // starting point but may not be accurate if the user set a wallpaper through a 3rd party app
1075 // while this app was paused.
1076 int rotationState = mWallpaperRotationInitializer.getRotationInitializationStateDirty(
1077 getContext());
1078 bindRotationInitializationState(rotationState);
1079 }
1080
1081 @Override
1082 public void onClick(View v) {
Samuel Fufa03bc6ac2019-09-19 12:01:50 -07001083 DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
Jon Miranda16ea1b12017-12-12 14:52:48 -08001084 startRotationDialogFragment.setTargetFragment(
1085 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
1086 startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
1087 }
1088
1089 /**
1090 * Binds the provided rotation initialization state to the RotationHolder and updates the tile's
1091 * UI to be in sync with the state (i.e., message and color appropriately reflect the state to
1092 * the user).
1093 */
1094 void bindRotationInitializationState(@RotationInitializationState int rotationState) {
1095 int newBackgroundColor =
1096 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1097 ? getResources().getColor(R.color.rotation_tile_not_enabled_background_color)
1098 : getResources().getColor(R.color.rotation_tile_enabled_background_color);
1099 int newTitleTextColor =
1100 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1101 ? getResources().getColor(R.color.rotation_tile_not_enabled_title_text_color)
1102 : getResources().getColor(R.color.rotation_tile_enabled_title_text_color);
1103 int newSubtitleTextColor =
1104 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1105 ? getResources().getColor(R.color.rotation_tile_not_enabled_subtitle_text_color)
1106 : getResources().getColor(R.color.rotation_tile_enabled_subtitle_text_color);
1107 int newRefreshIconColor =
1108 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1109 ? getResources().getColor(R.color.rotation_tile_not_enabled_refresh_icon_color)
1110 : getResources().getColor(R.color.rotation_tile_enabled_refresh_icon_color);
1111
Chuck Liaoba401232020-03-13 20:11:04 +08001112 mTileLayout.setCardBackgroundColor(newBackgroundColor);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001113 mRotationTitle.setTextColor(newTitleTextColor);
1114 mRotationMessage.setText(getResIdForRotationState(rotationState));
1115 mRotationMessage.setTextColor(newSubtitleTextColor);
1116 mRefreshIcon.setColorFilter(newRefreshIconColor, Mode.SRC_IN);
1117 }
1118 }
1119
1120 /**
1121 * RecyclerView Adapter subclass for the wallpaper tiles in the RecyclerView.
1122 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001123 class IndividualAdapter extends RecyclerView.Adapter<ViewHolder> {
1124 static final int ITEM_VIEW_TYPE_ROTATION = 1;
1125 static final int ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER = 2;
1126 static final int ITEM_VIEW_TYPE_MY_PHOTOS = 3;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001127
1128 private final List<WallpaperInfo> mWallpapers;
1129
1130 private int mPendingSelectedAdapterPosition;
1131 private int mSelectedAdapterPosition;
1132
1133 IndividualAdapter(List<WallpaperInfo> wallpapers) {
1134 mWallpapers = wallpapers;
1135 mPendingSelectedAdapterPosition = -1;
1136 mSelectedAdapterPosition = -1;
1137 }
1138
1139 @Override
1140 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
1141 switch (viewType) {
1142 case ITEM_VIEW_TYPE_ROTATION:
1143 return createRotationHolder(parent);
1144 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1145 return createIndividualHolder(parent);
1146 case ITEM_VIEW_TYPE_MY_PHOTOS:
1147 return createMyPhotosHolder(parent);
1148 default:
1149 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1150 return null;
1151 }
1152 }
1153
1154 @Override
1155 public int getItemViewType(int position) {
1156 if (isRotationEnabled() && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
1157 return ITEM_VIEW_TYPE_ROTATION;
1158 }
1159
1160 // A category cannot have both a "start rotation" tile and a "my photos" tile.
1161 if (mCategory.supportsCustomPhotos()
1162 && !isRotationEnabled()
1163 && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
1164 return ITEM_VIEW_TYPE_MY_PHOTOS;
1165 }
1166
1167 return ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER;
1168 }
1169
1170 @Override
1171 public void onBindViewHolder(ViewHolder holder, int position) {
1172 int viewType = getItemViewType(position);
1173
1174 switch (viewType) {
1175 case ITEM_VIEW_TYPE_ROTATION:
1176 onBindRotationHolder(holder, position);
1177 break;
1178 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1179 onBindIndividualHolder(holder, position);
1180 break;
1181 case ITEM_VIEW_TYPE_MY_PHOTOS:
1182 ((MyPhotosViewHolder) holder).bind();
1183 break;
1184 default:
1185 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1186 }
1187 }
1188
1189 @Override
1190 public int getItemCount() {
1191 return (isRotationEnabled() || mCategory.supportsCustomPhotos())
1192 ? mWallpapers.size() + 1
1193 : mWallpapers.size();
1194 }
1195
1196 private ViewHolder createRotationHolder(ViewGroup parent) {
1197 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1198 View view;
1199
1200 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1201 view = layoutInflater.inflate(R.layout.grid_item_rotation_desktop, parent, false);
1202 SelectionAnimator selectionAnimator =
1203 new CheckmarkSelectionAnimator(getActivity(), view);
1204 return new DesktopRotationHolder(
1205 getActivity(), mTileSizePx.y, view, selectionAnimator,
1206 IndividualPickerFragment.this);
1207 } else { // MOBILE
1208 view = layoutInflater.inflate(R.layout.grid_item_rotation, parent, false);
1209 return new RotationHolder(view);
1210 }
1211 }
1212
1213 private ViewHolder createIndividualHolder(ViewGroup parent) {
1214 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1215 View view = layoutInflater.inflate(R.layout.grid_item_image, parent, false);
Chuck Liao6a37a1c2020-03-07 03:39:43 +08001216 if (!TEMP_BOTTOM_ACTION_BAR_FEATURE) {
1217 view.findViewById(R.id.tile).setPadding(0, 0, 0, 0);
1218 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001219
1220 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1221 SelectionAnimator selectionAnimator =
1222 new CheckmarkSelectionAnimator(getActivity(), view);
1223 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) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001361 int wallpaperIndex = (isRotationEnabled() || mCategory.supportsCustomPhotos())
1362 ? 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
1375 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
“Chuckffd832c2020-03-22 02:15:58 +08001376 holder.itemView.setActivated(
1377 (isWallpaperApplied && !hasUserSelectedWallpaper) || isWallpaperSelected);
1378 holder.itemView.findViewById(R.id.check_circle).setVisibility(
1379 isWallpaperApplied ? View.VISIBLE : View.GONE);
Chuck Liao69630f12020-03-05 19:01:25 +08001380 holder.itemView.findViewById(R.id.tile).setOnClickListener(
Chuck Liaob3829fb2020-04-01 00:47:50 +08001381 view -> onWallpaperSelected(wallpaper, position));
Chuck Liaof40063f2020-03-03 18:35:24 +08001382 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001383 }
1384 }
Chuck Liaoba401232020-03-13 20:11:04 +08001385
1386 private class GridPaddingDecoration extends RecyclerView.ItemDecoration {
1387
1388 private int mPadding;
1389
1390 GridPaddingDecoration(int padding) {
1391 mPadding = padding;
1392 }
1393
1394 @Override
1395 public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
1396 RecyclerView.State state) {
1397 int position = parent.getChildAdapterPosition(view);
1398 if (position >= 0) {
1399 outRect.left = mPadding;
1400 outRect.right = mPadding;
1401 }
1402 }
1403 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001404}