blob: 668c820a16740ff403191dda6597d4d2e6aedabf [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;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080049import androidx.recyclerview.widget.GridLayoutManager;
50import androidx.recyclerview.widget.RecyclerView;
51import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
52import androidx.recyclerview.widget.RecyclerView.ViewHolder;
53
Jon Miranda16ea1b12017-12-12 14:52:48 -080054import com.android.wallpaper.R;
55import com.android.wallpaper.asset.Asset;
56import com.android.wallpaper.asset.Asset.DrawableLoadedListener;
57import com.android.wallpaper.config.Flags;
Santiago Etchebehere8648bb82019-08-06 17:09:02 -070058import com.android.wallpaper.model.Category;
59import com.android.wallpaper.model.CategoryProvider;
60import com.android.wallpaper.model.CategoryReceiver;
Chuck Liao69630f12020-03-05 19:01:25 +080061import com.android.wallpaper.model.LiveWallpaperInfo;
Jon Miranda16ea1b12017-12-12 14:52:48 -080062import com.android.wallpaper.model.WallpaperCategory;
63import com.android.wallpaper.model.WallpaperInfo;
64import com.android.wallpaper.model.WallpaperReceiver;
65import com.android.wallpaper.model.WallpaperRotationInitializer;
66import com.android.wallpaper.model.WallpaperRotationInitializer.Listener;
67import com.android.wallpaper.model.WallpaperRotationInitializer.NetworkPreference;
68import com.android.wallpaper.model.WallpaperRotationInitializer.RotationInitializationState;
Jon Miranda16ea1b12017-12-12 14:52:48 -080069import com.android.wallpaper.module.FormFactorChecker;
70import com.android.wallpaper.module.FormFactorChecker.FormFactor;
71import com.android.wallpaper.module.Injector;
72import com.android.wallpaper.module.InjectorProvider;
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -070073import com.android.wallpaper.module.PackageStatusNotifier;
Jon Miranda16ea1b12017-12-12 14:52:48 -080074import com.android.wallpaper.module.WallpaperChangedNotifier;
75import com.android.wallpaper.module.WallpaperPersister;
76import com.android.wallpaper.module.WallpaperPersister.Destination;
77import com.android.wallpaper.module.WallpaperPreferences;
Chuck Liao69630f12020-03-05 19:01:25 +080078import com.android.wallpaper.module.WallpaperSetter;
Jon Miranda16ea1b12017-12-12 14:52:48 -080079import com.android.wallpaper.picker.BaseActivity;
chihhangchuang3efb6832020-04-17 02:06:25 +080080import com.android.wallpaper.picker.BottomActionBarFragment;
Jon Miranda16ea1b12017-12-12 14:52:48 -080081import 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 */
chihhangchuang3efb6832020-04-17 02:06:25 +0800107public class IndividualPickerFragment extends BottomActionBarFragment
Jon Miranda16ea1b12017-12-12 14:52:48 -0800108 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";
Ching-Sung Li073812b2020-04-07 21:19:21 +0800117 /**
118 * A temporary flag to hide the bottom action bar feature.
119 */
120 static final boolean TEMP_BOTTOM_ACTION_BAR_FEATURE = false;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800121
Jon Miranda16ea1b12017-12-12 14:52:48 -0800122 private static final String TAG = "IndividualPickerFrgmnt";
Jon Miranda16ea1b12017-12-12 14:52:48 -0800123 private static final int UNUSED_REQUEST_CODE = 1;
124 private static final String TAG_START_ROTATION_DIALOG = "start_rotation_dialog";
125 private static final String TAG_START_ROTATION_ERROR_DIALOG = "start_rotation_error_dialog";
126 private static final String PROGRESS_DIALOG_NO_TITLE = null;
127 private static final boolean PROGRESS_DIALOG_INDETERMINATE = true;
128 private static final String TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT =
129 "individual_set_wallpaper_error_dialog";
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700130 private static final String KEY_NIGHT_MODE = "IndividualPickerFragment.NIGHT_MODE";
Jon Miranda16ea1b12017-12-12 14:52:48 -0800131
Chuck Liao8ec38e02020-02-26 20:59:32 +0800132 /**
Chuck Liaof40063f2020-03-03 18:35:24 +0800133 * An interface for updating the thumbnail with the specific wallpaper.
134 */
135 public interface ThumbnailUpdater {
136 /**
137 * Updates the thumbnail with the specific wallpaper.
138 */
139 void updateThumbnail(WallpaperInfo wallpaperInfo);
140
141 /**
142 * Restores to the thumbnails of the wallpapers which were applied.
143 */
144 void restoreThumbnails();
145 }
146
“Chuck7ef99722020-03-22 04:34:03 +0800147 /**
148 * An interface for receiving the destination of the new applied wallpaper.
149 */
150 public interface WallpaperDestinationCallback {
151 /**
152 * Called when the destination of the wallpaper is set.
153 *
154 * @param destination the destination which a wallpaper may be set.
155 * See {@link Destination} for more details.
156 */
157 void onDestinationSet(@Destination int destination);
158 }
159
Chuck Liaob3829fb2020-04-01 00:47:50 +0800160 /**
161 * The listener which will be notified when the wallpaper is selected.
162 */
163 public interface WallpaperSelectedListener {
164 /**
165 * Called when the wallpaper is selected.
166 *
167 * @param position the position of the selected wallpaper
168 */
169 void onWallpaperSelected(int position);
170 }
171
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800172 WallpaperPreferences mWallpaperPreferences;
173 WallpaperChangedNotifier mWallpaperChangedNotifier;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800174 RecyclerView mImageGrid;
175 IndividualAdapter mAdapter;
176 WallpaperCategory mCategory;
177 WallpaperRotationInitializer mWallpaperRotationInitializer;
178 List<WallpaperInfo> mWallpapers;
179 Point mTileSizePx;
180 WallpapersUiContainer mWallpapersUiContainer;
181 @FormFactor
182 int mFormFactor;
183 PackageStatusNotifier mPackageStatusNotifier;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800184
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800185 Handler mHandler;
186 Random mRandom;
187
188 WallpaperChangedNotifier.Listener mWallpaperChangedListener =
189 new WallpaperChangedNotifier.Listener() {
190 @Override
191 public void onWallpaperChanged() {
192 if (mFormFactor != FormFactorChecker.FORM_FACTOR_DESKTOP) {
193 return;
194 }
195
196 ViewHolder selectedViewHolder = mImageGrid.findViewHolderForAdapterPosition(
197 mAdapter.mSelectedAdapterPosition);
198
199 // Null remote ID => My Photos wallpaper, so deselect whatever was previously selected.
200 if (mWallpaperPreferences.getHomeWallpaperRemoteId() == null) {
201 if (selectedViewHolder instanceof SelectableHolder) {
202 ((SelectableHolder) selectedViewHolder).setSelectionState(
203 SelectableHolder.SELECTION_STATE_DESELECTED);
204 }
205 } else {
206 mAdapter.updateSelectedTile(mAdapter.mPendingSelectedAdapterPosition);
207 }
208 }
209 };
210 PackageStatusNotifier.Listener mAppStatusListener;
Ching-Sung Li073812b2020-04-07 21:19:21 +0800211 BottomActionBar mBottomActionBar;
212 @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;
540 mBottomActionBar.showActionsOnly(
541 isRotationEnabled() ? EnumSet.of(CANCEL, ROTATION) : EnumSet.of(CANCEL));
Ching-Sung Li073812b2020-04-07 21:19:21 +0800542 mBottomActionBar.setActionClickListener(CANCEL, unused -> {
543 if (mSelectedWallpaperInfo != null) {
544 onWallpaperSelected(null, 0);
545 return;
546 }
547 getActivity().onBackPressed();
548 });
549 mBottomActionBar.setActionClickListener(ROTATION, unused -> {
550 DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
551 startRotationDialogFragment.setTargetFragment(
552 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
553 startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
554 });
555 mBottomActionBar.setActionClickListener(APPLY, unused -> {
556 mBottomActionBar.disableActions();
557 mWallpaperSetter.requestDestination(getActivity(), getFragmentManager(), this,
558 mSelectedWallpaperInfo instanceof LiveWallpaperInfo);
559 });
Ching-Sung Li073812b2020-04-07 21:19:21 +0800560 mBottomActionBar.show();
Ching-Sung Li073812b2020-04-07 21:19:21 +0800561 }
562 }
563
Jon Miranda16ea1b12017-12-12 14:52:48 -0800564 @Override
565 public void onResume() {
566 super.onResume();
567
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700568 WallpaperPreferences preferences = InjectorProvider.getInjector()
569 .getPreferences(getActivity());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800570 preferences.setLastAppActiveTimestamp(new Date().getTime());
571
572 // Reset Glide memory settings to a "normal" level of usage since it may have been lowered in
573 // PreviewFragment.
574 Glide.get(getActivity()).setMemoryCategory(MemoryCategory.NORMAL);
575
576 // Show the staged 'start rotation' error dialog fragment if there is one that was unable to be
577 // shown earlier when this fragment's hosting activity didn't allow committing fragment
578 // transactions.
579 if (mStagedStartRotationErrorDialogFragment != null) {
580 mStagedStartRotationErrorDialogFragment.show(
581 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
582 mStagedStartRotationErrorDialogFragment = null;
583 }
584
585 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one
586 // that was unable to be shown earlier when this fragment's hosting activity didn't allow
587 // committing fragment transactions.
588 if (mStagedSetWallpaperErrorDialogFragment != null) {
589 mStagedSetWallpaperErrorDialogFragment.show(
590 getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
591 mStagedSetWallpaperErrorDialogFragment = null;
592 }
593
594 if (isRotationEnabled()) {
595 if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
596 // Refresh the state of the "start rotation" in case something changed the current daily
597 // rotation while this fragment was paused.
598 RotationHolder rotationHolder = (RotationHolder) mImageGrid
599 .findViewHolderForAdapterPosition(
600 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
601 // The RotationHolder may be null if the RecyclerView has not created the view
602 // holder yet.
603 if (rotationHolder != null && Flags.dynamicStartRotationTileEnabled) {
604 refreshRotationHolder(rotationHolder);
605 }
606 } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
607 if (mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
608 // Must be resuming from a previously stopped state, so re-schedule the update of the
609 // daily wallpapers tile thumbnail.
610 mUpdateDailyWallpaperThumbRunnable.run();
611 }
612 }
613 }
614
615 }
616
617 @Override
618 public void onStop() {
619 super.onStop();
620 mHandler.removeCallbacks(mUpdateDailyWallpaperThumbRunnable);
621 }
622
623 @Override
624 public void onDestroy() {
625 super.onDestroy();
626 if (mProgressDialog != null) {
627 mProgressDialog.dismiss();
628 }
629 mWallpaperChangedNotifier.unregisterListener(mWallpaperChangedListener);
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700630 if (mAppStatusListener != null) {
631 mPackageStatusNotifier.removeListener(mAppStatusListener);
632 }
Chuck Liao69630f12020-03-05 19:01:25 +0800633 mWallpaperSetter.cleanUp();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800634 }
635
636 @Override
637 public void retryStartRotation(@NetworkPreference int networkPreference) {
638 startRotation(networkPreference);
639 }
640
641 public void setCurrentWallpaperBottomSheetPresenter(
642 CurrentWallpaperBottomSheetPresenter presenter) {
643 mCurrentWallpaperBottomSheetPresenter = presenter;
644 }
645
646 public void setWallpapersUiContainer(WallpapersUiContainer uiContainer) {
647 mWallpapersUiContainer = uiContainer;
648 }
649
Chuck Liaob3829fb2020-04-01 00:47:50 +0800650 public void setOnWallpaperSelectedListener(
651 WallpaperSelectedListener wallpaperSelectedListener) {
652 mWallpaperSelectedListener = wallpaperSelectedListener;
653 }
654
655 /**
656 * Resizes the layout's height.
657 */
658 public void resizeLayout(int height) {
659 mImageGrid.getLayoutParams().height = height;
660 mImageGrid.requestLayout();
661 }
662
663 /**
664 * Scrolls to the specific item.
665 *
666 * @param position the position of the item
667 */
668 public void scrollToPosition(int position) {
669 ((GridLayoutManager) mImageGrid.getLayoutManager())
670 .scrollToPositionWithOffset(position, /* offset= */ 0);
671 }
672
Jon Miranda16ea1b12017-12-12 14:52:48 -0800673 /**
674 * Enable a test mode of operation -- in which certain UI features are disabled to allow for
675 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog
676 * constantly keeps the UI thread alive and blocks a test forever.
677 *
678 * @param testingMode
679 */
680 void setTestingMode(boolean testingMode) {
681 mTestingMode = testingMode;
682 }
683
684 /**
685 * Asynchronously fetches the refreshed rotation initialization state that is up to date with the
686 * state of the user's device and binds the state of the current category's rotation to the "start
687 * rotation" tile.
688 */
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700689 private void refreshRotationHolder(RotationHolder rotationHolder) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800690 mWallpaperRotationInitializer.fetchRotationInitializationState(getContext(),
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700691 rotationState -> {
692 // Update the UI state of the "start rotation" tile displayed on screen.
693 // Do this in a Handler so it is scheduled at the end of the message queue.
694 // This is necessary to ensure we do not remove or add data from the adapter
695 // while the layout is still being computed. RecyclerView documentation
696 // therefore recommends performing such changes in a Handler.
697 new Handler().post(() -> {
698 // A config change may have destroyed the activity since the refresh
699 // started, so check for that to avoid an NPE.
700 if (getActivity() == null) {
701 return;
702 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800703
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700704 rotationHolder.bindRotationInitializationState(rotationState);
705 });
Jon Miranda16ea1b12017-12-12 14:52:48 -0800706 });
707 }
708
709 @Override
710 public void startRotation(@NetworkPreference final int networkPreference) {
711 if (!isRotationEnabled()) {
712 Log.e(TAG, "Rotation is not enabled for this category " + mCategory.getTitle());
713 return;
714 }
715
716 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
717 // causes Espresso to hang once the dialog is shown.
718 if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE && !mTestingMode) {
719 int themeResId;
720 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
721 themeResId = R.style.ProgressDialogThemePreL;
722 } else {
723 themeResId = R.style.LightDialogTheme;
724 }
725 mProgressDialog = new ProgressDialog(getActivity(), themeResId);
726
727 mProgressDialog.setTitle(PROGRESS_DIALOG_NO_TITLE);
728 mProgressDialog.setMessage(
729 getResources().getString(R.string.start_rotation_progress_message));
730 mProgressDialog.setIndeterminate(PROGRESS_DIALOG_INDETERMINATE);
731 mProgressDialog.show();
732 }
733
734 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
735 mAdapter.mPendingSelectedAdapterPosition = SPECIAL_FIXED_TILE_ADAPTER_POSITION;
736 }
737
738 final Context appContext = getActivity().getApplicationContext();
739
740 mWallpaperRotationInitializer.setFirstWallpaperInRotation(
741 appContext,
742 networkPreference,
743 new Listener() {
744 @Override
745 public void onFirstWallpaperInRotationSet() {
746 if (mProgressDialog != null) {
747 mProgressDialog.dismiss();
748 }
749
750 // The fragment may be detached from its containing activity if the user exits the
751 // app before the first wallpaper image in rotation finishes downloading.
752 Activity activity = getActivity();
753
Jon Miranda16ea1b12017-12-12 14:52:48 -0800754
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700755 if (mWallpaperRotationInitializer.startRotation(appContext)) {
756 if (activity != null
757 && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
758 try {
759 Toast.makeText(getActivity(),
760 R.string.wallpaper_set_successfully_message,
761 Toast.LENGTH_SHORT).show();
762 } catch (NotFoundException e) {
763 Log.e(TAG, "Could not show toast " + e);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800764 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800765
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700766 activity.setResult(Activity.RESULT_OK);
767 activity.finish();
768 } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
769 mAdapter.updateSelectedTile(SPECIAL_FIXED_TILE_ADAPTER_POSITION);
770 }
771 } else { // Failed to start rotation.
772 showStartRotationErrorDialog(networkPreference);
773
774 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
775 DesktopRotationHolder rotationViewHolder =
776 (DesktopRotationHolder)
777 mImageGrid.findViewHolderForAdapterPosition(
778 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
779 rotationViewHolder.setSelectionState(
780 SelectableHolder.SELECTION_STATE_DESELECTED);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800781 }
782 }
783 }
784
785 @Override
786 public void onError() {
787 if (mProgressDialog != null) {
788 mProgressDialog.dismiss();
789 }
790
791 showStartRotationErrorDialog(networkPreference);
792
793 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
794 DesktopRotationHolder rotationViewHolder =
795 (DesktopRotationHolder) mImageGrid.findViewHolderForAdapterPosition(
796 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
797 rotationViewHolder.setSelectionState(SelectableHolder.SELECTION_STATE_DESELECTED);
798 }
799 }
800 });
801 }
802
803 private void showStartRotationErrorDialog(@NetworkPreference int networkPreference) {
804 BaseActivity activity = (BaseActivity) getActivity();
805 if (activity != null) {
806 StartRotationErrorDialogFragment startRotationErrorDialogFragment =
807 StartRotationErrorDialogFragment.newInstance(networkPreference);
808 startRotationErrorDialogFragment.setTargetFragment(
809 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
810
811 if (activity.isSafeToCommitFragmentTransaction()) {
812 startRotationErrorDialogFragment.show(
813 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
814 } else {
815 mStagedStartRotationErrorDialogFragment = startRotationErrorDialogFragment;
816 }
817 }
818 }
819
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800820 int getNumColumns() {
Ching-Sung Li9df77a32019-07-10 11:45:30 +0800821 Activity activity = getActivity();
822 return activity == null ? 0 : TileSizeCalculator.getNumIndividualColumns(activity);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800823 }
824
825 /**
826 * Returns whether rotation is enabled for this category.
827 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800828 boolean isRotationEnabled() {
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700829 return mWallpaperRotationInitializer != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800830 }
831
832 @Override
833 public void onCurrentWallpaperRefreshed() {
834 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
835 }
836
Chuck Liao69630f12020-03-05 19:01:25 +0800837
838 @Override
839 public void onSet(int destination) {
840 if (mSelectedWallpaperInfo == null) {
841 Log.e(TAG, "Unable to set wallpaper since the selected wallpaper info is null");
842 return;
843 }
844
“Chuckffd832c2020-03-22 02:15:58 +0800845 mWallpaperPersister.setWallpaperInfoInPreview(mSelectedWallpaperInfo);
Chuck Liao69630f12020-03-05 19:01:25 +0800846 if (mSelectedWallpaperInfo instanceof LiveWallpaperInfo) {
847 mWallpaperSetter.setCurrentWallpaper(getActivity(), mSelectedWallpaperInfo, null,
848 destination, 0, null, mSetWallpaperCallback);
849 } else {
850 mWallpaperSetter.setCurrentWallpaper(
851 getActivity(), mSelectedWallpaperInfo, destination, mSetWallpaperCallback);
852 }
“Chuck7ef99722020-03-22 04:34:03 +0800853 onWallpaperDestinationSet(destination);
Chuck Liao69630f12020-03-05 19:01:25 +0800854 }
855
856 private WallpaperPersister.SetWallpaperCallback mSetWallpaperCallback =
857 new WallpaperPersister.SetWallpaperCallback() {
858 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800859 public void onSuccess(WallpaperInfo wallpaperInfo) {
Chuck Liao69630f12020-03-05 19:01:25 +0800860 // TODO(b/150913705): Show the snack bar.
861 mBottomActionBar.enableActions();
Chuck Liao11f4a762020-04-08 13:24:43 +0800862 refreshAppliedWallpaper();
“Chuckffd832c2020-03-22 02:15:58 +0800863
864 mWallpaperPersister.onLiveWallpaperSet();
Chuck Liao69630f12020-03-05 19:01:25 +0800865 }
866
867 @Override
868 public void onError(@Nullable Throwable throwable) {
869 Log.e(TAG, "Can't apply the wallpaper.");
870 mBottomActionBar.enableActions();
871 }
872 };
873
874 @Override
875 public void onDialogDismissed(boolean withItemSelected) {
876 if (!withItemSelected) {
877 mBottomActionBar.enableActions();
878 }
879 }
880
Jon Miranda16ea1b12017-12-12 14:52:48 -0800881 /**
882 * Shows a "set wallpaper" error dialog with a failure message and button to try again.
883 */
884 private void showSetWallpaperErrorDialog() {
885 SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance(
886 R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH);
887 dialogFragment.setTargetFragment(this, UNUSED_REQUEST_CODE);
888
889 if (((BaseActivity) getActivity()).isSafeToCommitFragmentTransaction()) {
890 dialogFragment.show(getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
891 } else {
892 mStagedSetWallpaperErrorDialogFragment = dialogFragment;
893 }
894 }
895
Ching-Sung Li073812b2020-04-07 21:19:21 +0800896 void updateBottomActions(boolean hasWallpaperSelected) {
chihhangchuang3efb6832020-04-17 02:06:25 +0800897 mBottomActionBar.showActionsOnly(
898 hasWallpaperSelected
899 ? EnumSet.of(CANCEL, INFORMATION, APPLY)
900 : EnumSet.of(CANCEL, ROTATION));
Chuck Liao69630f12020-03-05 19:01:25 +0800901 }
902
903 private void updateThumbnail(WallpaperInfo selectedWallpaperInfo) {
Chuck Liaof40063f2020-03-03 18:35:24 +0800904 ThumbnailUpdater thumbnailUpdater = (ThumbnailUpdater) getParentFragment();
Chuck Liao69630f12020-03-05 19:01:25 +0800905 if (thumbnailUpdater == null) {
906 return;
907 }
908
909 if (selectedWallpaperInfo != null) {
910 thumbnailUpdater.updateThumbnail(selectedWallpaperInfo);
911 } else {
912 thumbnailUpdater.restoreThumbnails();
Chuck Liaof40063f2020-03-03 18:35:24 +0800913 }
914 }
915
“Chuck7ef99722020-03-22 04:34:03 +0800916 private void onWallpaperDestinationSet(int destination) {
917 WallpaperDestinationCallback wallpaperDestinationCallback =
918 (WallpaperDestinationCallback) getParentFragment();
919 if (wallpaperDestinationCallback == null) {
920 return;
921 }
922
923 wallpaperDestinationCallback.onDestinationSet(destination);
924 }
925
Ching-Sung Li073812b2020-04-07 21:19:21 +0800926 void onWallpaperSelected(@Nullable WallpaperInfo newSelectedWallpaperInfo,
Chuck Liaob3829fb2020-04-01 00:47:50 +0800927 int position) {
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800928 if (mSelectedWallpaperInfo == newSelectedWallpaperInfo) {
“Chuckffd832c2020-03-22 02:15:58 +0800929 return;
930 }
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800931 // Update current wallpaper.
“Chuckffd832c2020-03-22 02:15:58 +0800932 updateActivatedStatus(mSelectedWallpaperInfo == null
933 ? mAppliedWallpaperInfo : mSelectedWallpaperInfo, false);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800934 // Update new selected wallpaper.
935 updateActivatedStatus(newSelectedWallpaperInfo == null
936 ? mAppliedWallpaperInfo : newSelectedWallpaperInfo, true);
937
938 mSelectedWallpaperInfo = newSelectedWallpaperInfo;
939 updateBottomActions(mSelectedWallpaperInfo != null);
940 updateThumbnail(mSelectedWallpaperInfo);
941 // Populate wallpaper info to bottom sheet page.
942 if (mSelectedWallpaperInfo != null) {
943 mBottomActionBar.populateInfoPage(
Chuck Liaob3829fb2020-04-01 00:47:50 +0800944 mSelectedWallpaperInfo.getAttributions(getContext()),
945 shouldShowMetadataInPreview(mSelectedWallpaperInfo));
946 }
947
948 if (mWallpaperSelectedListener != null) {
949 mWallpaperSelectedListener.onWallpaperSelected(position);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800950 }
Chuck Liaof40063f2020-03-03 18:35:24 +0800951 }
952
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800953 private void updateActivatedStatus(WallpaperInfo wallpaperInfo, boolean isActivated) {
“Chuckffd832c2020-03-22 02:15:58 +0800954 if (wallpaperInfo == null) {
955 return;
956 }
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800957 int index = mWallpapers.indexOf(wallpaperInfo);
958 index = (isRotationEnabled() || mCategory.supportsCustomPhotos())
959 ? index + 1 : index;
960 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
961 if (holder != null) {
962 holder.itemView.setActivated(isActivated);
963 } else {
964 // Item is not visible, make sure the item is re-bound when it becomes visible.
965 mAdapter.notifyItemChanged(index);
966 }
967 }
968
“Chuckffd832c2020-03-22 02:15:58 +0800969 private void updateAppliedStatus(WallpaperInfo wallpaperInfo, boolean isApplied) {
970 if (wallpaperInfo == null) {
971 return;
972 }
973 int index = mWallpapers.indexOf(wallpaperInfo);
974 index = (isRotationEnabled() || mCategory.supportsCustomPhotos())
975 ? index + 1 : index;
976 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
977 if (holder != null) {
978 holder.itemView.findViewById(R.id.check_circle)
979 .setVisibility(isApplied ? View.VISIBLE : View.GONE);
980 } else {
981 // Item is not visible, make sure the item is re-bound when it becomes visible.
982 mAdapter.notifyItemChanged(index);
983 }
984 }
985
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800986 private static boolean shouldShowMetadataInPreview(WallpaperInfo wallpaperInfo) {
987 android.app.WallpaperInfo wallpaperComponent = wallpaperInfo.getWallpaperComponent();
988 return wallpaperComponent == null || wallpaperComponent.getShowMetadataInPreview();
989 }
990
Chuck Liao11f4a762020-04-08 13:24:43 +0800991 private void refreshAppliedWallpaper() {
992 // Clear the check mark and blue border(if it shows) of the old applied wallpaper.
993 showCheckMarkAndBorderForAppliedWallpaper(false);
994
995 // Update to the new applied wallpaper.
996 String appliedWallpaperId = getAppliedWallpaperId();
997 Optional<WallpaperInfo> wallpaperInfoOptional = mWallpapers
998 .stream()
999 .filter(wallpaper -> wallpaper.getWallpaperId() != null)
1000 .filter(wallpaper -> wallpaper.getWallpaperId().equals(appliedWallpaperId))
1001 .findFirst();
1002 mAppliedWallpaperInfo = wallpaperInfoOptional.orElse(null);
1003
1004 // Set the check mark and blue border(if user doesn't select) of the new applied wallpaper.
1005 showCheckMarkAndBorderForAppliedWallpaper(true);
1006 }
1007
1008 private String getAppliedWallpaperId() {
1009 WallpaperPreferences prefs =
1010 InjectorProvider.getInjector().getPreferences(getContext());
1011 android.app.WallpaperInfo wallpaperInfo = mWallpaperManager.getWallpaperInfo();
1012 boolean isDestinationBoth =
1013 mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK) < 0;
1014
1015 if (isDestinationBoth || mWallpaperDestination == WallpaperPersister.DEST_HOME_SCREEN) {
1016 return wallpaperInfo != null
1017 ? wallpaperInfo.getServiceName() : prefs.getHomeWallpaperRemoteId();
1018 } else {
1019 return prefs.getLockWallpaperRemoteId();
1020 }
1021 }
1022
1023 private void showCheckMarkAndBorderForAppliedWallpaper(boolean show) {
1024 updateAppliedStatus(mAppliedWallpaperInfo, show);
1025 if (mSelectedWallpaperInfo == null) {
1026 updateActivatedStatus(mAppliedWallpaperInfo, show);
1027 }
1028 }
1029
Jon Miranda16ea1b12017-12-12 14:52:48 -08001030 /**
1031 * ViewHolder subclass for "daily refresh" tile in the RecyclerView, only shown if rotation is
1032 * enabled for this category.
1033 */
1034 private class RotationHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
1035
Chuck Liaoba401232020-03-13 20:11:04 +08001036 private CardView mTileLayout;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001037 private TextView mRotationMessage;
1038 private TextView mRotationTitle;
1039 private ImageView mRefreshIcon;
1040
1041 RotationHolder(View itemView) {
1042 super(itemView);
1043 itemView.setOnClickListener(this);
1044
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -07001045 mTileLayout = itemView.findViewById(R.id.daily_refresh);
1046 mRotationMessage = itemView.findViewById(R.id.rotation_tile_message);
1047 mRotationTitle = itemView.findViewById(R.id.rotation_tile_title);
1048 mRefreshIcon = itemView.findViewById(R.id.rotation_tile_refresh_icon);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001049 mTileLayout.getLayoutParams().height = mTileSizePx.y;
1050
1051 // If the feature flag for "dynamic start rotation tile" is not enabled, fall back to the
1052 // static UI with a blue accent color background and "Tap to turn on" text.
1053 if (!Flags.dynamicStartRotationTileEnabled) {
1054 mTileLayout.setBackgroundColor(
1055 getResources().getColor(R.color.rotation_tile_enabled_background_color));
1056 mRotationMessage.setText(R.string.daily_refresh_tile_subtitle);
1057 mRotationTitle.setTextColor(
1058 getResources().getColor(R.color.rotation_tile_enabled_title_text_color));
1059 mRotationMessage.setTextColor(
1060 getResources().getColor(R.color.rotation_tile_enabled_subtitle_text_color));
1061 mRefreshIcon.setColorFilter(
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -07001062 getResources().getColor(R.color.rotation_tile_enabled_refresh_icon_color),
1063 Mode.SRC_IN);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001064 return;
1065 }
1066
1067 // Initialize the state of the "start rotation" tile (i.e., whether it is gray or blue to
1068 // indicate if rotation is turned on for the current category) with last-known rotation state
1069 // that could be stale. The last-known rotation state is correct in most cases and is a good
1070 // starting point but may not be accurate if the user set a wallpaper through a 3rd party app
1071 // while this app was paused.
1072 int rotationState = mWallpaperRotationInitializer.getRotationInitializationStateDirty(
1073 getContext());
1074 bindRotationInitializationState(rotationState);
1075 }
1076
1077 @Override
1078 public void onClick(View v) {
Samuel Fufa03bc6ac2019-09-19 12:01:50 -07001079 DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
Jon Miranda16ea1b12017-12-12 14:52:48 -08001080 startRotationDialogFragment.setTargetFragment(
1081 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
1082 startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
1083 }
1084
1085 /**
1086 * Binds the provided rotation initialization state to the RotationHolder and updates the tile's
1087 * UI to be in sync with the state (i.e., message and color appropriately reflect the state to
1088 * the user).
1089 */
1090 void bindRotationInitializationState(@RotationInitializationState int rotationState) {
1091 int newBackgroundColor =
1092 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1093 ? getResources().getColor(R.color.rotation_tile_not_enabled_background_color)
1094 : getResources().getColor(R.color.rotation_tile_enabled_background_color);
1095 int newTitleTextColor =
1096 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1097 ? getResources().getColor(R.color.rotation_tile_not_enabled_title_text_color)
1098 : getResources().getColor(R.color.rotation_tile_enabled_title_text_color);
1099 int newSubtitleTextColor =
1100 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1101 ? getResources().getColor(R.color.rotation_tile_not_enabled_subtitle_text_color)
1102 : getResources().getColor(R.color.rotation_tile_enabled_subtitle_text_color);
1103 int newRefreshIconColor =
1104 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1105 ? getResources().getColor(R.color.rotation_tile_not_enabled_refresh_icon_color)
1106 : getResources().getColor(R.color.rotation_tile_enabled_refresh_icon_color);
1107
Chuck Liaoba401232020-03-13 20:11:04 +08001108 mTileLayout.setCardBackgroundColor(newBackgroundColor);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001109 mRotationTitle.setTextColor(newTitleTextColor);
1110 mRotationMessage.setText(getResIdForRotationState(rotationState));
1111 mRotationMessage.setTextColor(newSubtitleTextColor);
1112 mRefreshIcon.setColorFilter(newRefreshIconColor, Mode.SRC_IN);
1113 }
1114 }
1115
1116 /**
1117 * RecyclerView Adapter subclass for the wallpaper tiles in the RecyclerView.
1118 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001119 class IndividualAdapter extends RecyclerView.Adapter<ViewHolder> {
1120 static final int ITEM_VIEW_TYPE_ROTATION = 1;
1121 static final int ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER = 2;
1122 static final int ITEM_VIEW_TYPE_MY_PHOTOS = 3;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001123
1124 private final List<WallpaperInfo> mWallpapers;
1125
1126 private int mPendingSelectedAdapterPosition;
1127 private int mSelectedAdapterPosition;
1128
1129 IndividualAdapter(List<WallpaperInfo> wallpapers) {
1130 mWallpapers = wallpapers;
1131 mPendingSelectedAdapterPosition = -1;
1132 mSelectedAdapterPosition = -1;
1133 }
1134
1135 @Override
1136 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
1137 switch (viewType) {
1138 case ITEM_VIEW_TYPE_ROTATION:
1139 return createRotationHolder(parent);
1140 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1141 return createIndividualHolder(parent);
1142 case ITEM_VIEW_TYPE_MY_PHOTOS:
1143 return createMyPhotosHolder(parent);
1144 default:
1145 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1146 return null;
1147 }
1148 }
1149
1150 @Override
1151 public int getItemViewType(int position) {
1152 if (isRotationEnabled() && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
1153 return ITEM_VIEW_TYPE_ROTATION;
1154 }
1155
1156 // A category cannot have both a "start rotation" tile and a "my photos" tile.
1157 if (mCategory.supportsCustomPhotos()
1158 && !isRotationEnabled()
1159 && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
1160 return ITEM_VIEW_TYPE_MY_PHOTOS;
1161 }
1162
1163 return ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER;
1164 }
1165
1166 @Override
1167 public void onBindViewHolder(ViewHolder holder, int position) {
1168 int viewType = getItemViewType(position);
1169
1170 switch (viewType) {
1171 case ITEM_VIEW_TYPE_ROTATION:
1172 onBindRotationHolder(holder, position);
1173 break;
1174 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1175 onBindIndividualHolder(holder, position);
1176 break;
1177 case ITEM_VIEW_TYPE_MY_PHOTOS:
1178 ((MyPhotosViewHolder) holder).bind();
1179 break;
1180 default:
1181 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1182 }
1183 }
1184
1185 @Override
1186 public int getItemCount() {
1187 return (isRotationEnabled() || mCategory.supportsCustomPhotos())
1188 ? mWallpapers.size() + 1
1189 : mWallpapers.size();
1190 }
1191
1192 private ViewHolder createRotationHolder(ViewGroup parent) {
1193 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1194 View view;
1195
1196 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1197 view = layoutInflater.inflate(R.layout.grid_item_rotation_desktop, parent, false);
1198 SelectionAnimator selectionAnimator =
1199 new CheckmarkSelectionAnimator(getActivity(), view);
1200 return new DesktopRotationHolder(
1201 getActivity(), mTileSizePx.y, view, selectionAnimator,
1202 IndividualPickerFragment.this);
1203 } else { // MOBILE
1204 view = layoutInflater.inflate(R.layout.grid_item_rotation, parent, false);
1205 return new RotationHolder(view);
1206 }
1207 }
1208
1209 private ViewHolder createIndividualHolder(ViewGroup parent) {
1210 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1211 View view = layoutInflater.inflate(R.layout.grid_item_image, parent, false);
Chuck Liao6a37a1c2020-03-07 03:39:43 +08001212 if (!TEMP_BOTTOM_ACTION_BAR_FEATURE) {
1213 view.findViewById(R.id.tile).setPadding(0, 0, 0, 0);
1214 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001215
1216 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1217 SelectionAnimator selectionAnimator =
1218 new CheckmarkSelectionAnimator(getActivity(), view);
1219 return new SetIndividualHolder(
1220 getActivity(), mTileSizePx.y, view,
1221 selectionAnimator,
1222 new OnSetListener() {
1223 @Override
1224 public void onPendingWallpaperSet(int adapterPosition) {
1225 // Deselect and hide loading indicator for any previously pending tile.
1226 if (mPendingSelectedAdapterPosition != -1) {
1227 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1228 mPendingSelectedAdapterPosition);
1229 if (oldViewHolder instanceof SelectableHolder) {
1230 ((SelectableHolder) oldViewHolder).setSelectionState(
1231 SelectableHolder.SELECTION_STATE_DESELECTED);
1232 }
1233 }
1234
1235 if (mSelectedAdapterPosition != -1) {
1236 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1237 mSelectedAdapterPosition);
1238 if (oldViewHolder instanceof SelectableHolder) {
1239 ((SelectableHolder) oldViewHolder).setSelectionState(
1240 SelectableHolder.SELECTION_STATE_DESELECTED);
1241 }
1242 }
1243
1244 mPendingSelectedAdapterPosition = adapterPosition;
1245 }
1246
1247 @Override
1248 public void onWallpaperSet(int adapterPosition) {
1249 // No-op -- UI handles a new wallpaper being set by reacting to the
1250 // WallpaperChangedNotifier.
1251 }
1252
1253 @Override
1254 public void onWallpaperSetFailed(SetIndividualHolder holder) {
1255 showSetWallpaperErrorDialog();
1256 mPendingSetIndividualHolder = holder;
1257 }
1258 });
1259 } else { // MOBILE
Chuck Liao3d1a51c2020-02-17 18:29:34 +08001260 return new PreviewIndividualHolder(getActivity(), mTileSizePx.y, view);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001261 }
1262 }
1263
1264 private ViewHolder createMyPhotosHolder(ViewGroup parent) {
1265 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1266 View view = layoutInflater.inflate(R.layout.grid_item_my_photos, parent, false);
1267
Santiago Etchebeherefab49612019-01-15 12:22:42 -08001268 return new MyPhotosViewHolder(getActivity(),
1269 ((MyPhotosStarterProvider) getActivity()).getMyPhotosStarter(),
1270 mTileSizePx.y, view);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001271 }
1272
1273 /**
1274 * Marks the tile at the given position as selected with a visual indication. Also updates the
1275 * "currently selected" BottomSheet to reflect the newly selected tile.
1276 */
1277 private void updateSelectedTile(int newlySelectedPosition) {
1278 // Prevent multiple spinners from appearing with a user tapping several tiles in rapid
1279 // succession.
1280 if (mPendingSelectedAdapterPosition == mSelectedAdapterPosition) {
1281 return;
1282 }
1283
1284 if (mCurrentWallpaperBottomSheetPresenter != null) {
1285 mCurrentWallpaperBottomSheetPresenter.refreshCurrentWallpapers(
1286 IndividualPickerFragment.this);
1287
1288 if (mCurrentWallpaperBottomSheetExpandedRunnable != null) {
1289 mHandler.removeCallbacks(mCurrentWallpaperBottomSheetExpandedRunnable);
1290 }
1291 mCurrentWallpaperBottomSheetExpandedRunnable = new Runnable() {
1292 @Override
1293 public void run() {
1294 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
1295 }
1296 };
1297 mHandler.postDelayed(mCurrentWallpaperBottomSheetExpandedRunnable, 100);
1298 }
1299
1300 // User may have switched to another category, thus detaching this fragment, so check here.
1301 // NOTE: We do this check after updating the current wallpaper BottomSheet so that the update
1302 // still occurs in the UI after the user selects that other category.
1303 if (getActivity() == null) {
1304 return;
1305 }
1306
1307 // Update the newly selected wallpaper ViewHolder and the old one so that if
1308 // selection UI state applies (desktop UI), it is updated.
1309 if (mSelectedAdapterPosition >= 0) {
1310 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1311 mSelectedAdapterPosition);
1312 if (oldViewHolder instanceof SelectableHolder) {
1313 ((SelectableHolder) oldViewHolder).setSelectionState(
1314 SelectableHolder.SELECTION_STATE_DESELECTED);
1315 }
1316 }
1317
1318 // Animate selection of newly selected tile.
1319 ViewHolder newViewHolder = mImageGrid
1320 .findViewHolderForAdapterPosition(newlySelectedPosition);
1321 if (newViewHolder instanceof SelectableHolder) {
1322 ((SelectableHolder) newViewHolder).setSelectionState(
1323 SelectableHolder.SELECTION_STATE_SELECTED);
1324 }
1325
1326 mSelectedAdapterPosition = newlySelectedPosition;
1327
1328 // If the tile was in the last row of the grid, add space below it so the user can scroll down
1329 // and up to see the BottomSheet without it fully overlapping the newly selected tile.
1330 int spanCount = ((GridLayoutManager) mImageGrid.getLayoutManager()).getSpanCount();
1331 int numRows = (int) Math.ceil((float) getItemCount() / spanCount);
1332 int rowOfNewlySelectedTile = newlySelectedPosition / spanCount;
1333 boolean isInLastRow = rowOfNewlySelectedTile == numRows - 1;
1334
1335 updateImageGridPadding(isInLastRow /* addExtraBottomSpace */);
1336 }
1337
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001338 void onBindRotationHolder(ViewHolder holder, int position) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001339 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1340 String collectionId = mCategory.getCollectionId();
1341 ((DesktopRotationHolder) holder).bind(collectionId);
1342
1343 if (mWallpaperPreferences.getWallpaperPresentationMode()
1344 == WallpaperPreferences.PRESENTATION_MODE_ROTATING
1345 && collectionId.equals(mWallpaperPreferences.getHomeWallpaperCollectionId())) {
1346 mSelectedAdapterPosition = position;
1347 }
1348
1349 if (!mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
1350 updateDesktopDailyRotationThumbnail((DesktopRotationHolder) holder);
1351 mWasUpdateRunnableRun = true;
1352 }
1353 }
1354 }
1355
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001356 void onBindIndividualHolder(ViewHolder holder, int position) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001357 int wallpaperIndex = (isRotationEnabled() || mCategory.supportsCustomPhotos())
1358 ? position - 1 : position;
1359 WallpaperInfo wallpaper = mWallpapers.get(wallpaperIndex);
1360 ((IndividualHolder) holder).bindWallpaper(wallpaper);
“Chuck7ef99722020-03-22 04:34:03 +08001361 String appliedWallpaperId = getAppliedWallpaperId();
“Chuckffd832c2020-03-22 02:15:58 +08001362 boolean isWallpaperApplied = wallpaper.getWallpaperId().equals(appliedWallpaperId);
1363 boolean isWallpaperSelected = wallpaper.equals(mSelectedWallpaperInfo);
1364 boolean hasUserSelectedWallpaper = mSelectedWallpaperInfo != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001365
“Chuckffd832c2020-03-22 02:15:58 +08001366 if (isWallpaperApplied) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001367 mSelectedAdapterPosition = position;
“Chuckffd832c2020-03-22 02:15:58 +08001368 mAppliedWallpaperInfo = wallpaper;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001369 }
Chuck Liaof40063f2020-03-03 18:35:24 +08001370
1371 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
“Chuckffd832c2020-03-22 02:15:58 +08001372 holder.itemView.setActivated(
1373 (isWallpaperApplied && !hasUserSelectedWallpaper) || isWallpaperSelected);
1374 holder.itemView.findViewById(R.id.check_circle).setVisibility(
1375 isWallpaperApplied ? View.VISIBLE : View.GONE);
Chuck Liao69630f12020-03-05 19:01:25 +08001376 holder.itemView.findViewById(R.id.tile).setOnClickListener(
Chuck Liaob3829fb2020-04-01 00:47:50 +08001377 view -> onWallpaperSelected(wallpaper, position));
Chuck Liaof40063f2020-03-03 18:35:24 +08001378 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001379 }
1380 }
Chuck Liaoba401232020-03-13 20:11:04 +08001381
1382 private class GridPaddingDecoration extends RecyclerView.ItemDecoration {
1383
1384 private int mPadding;
1385
1386 GridPaddingDecoration(int padding) {
1387 mPadding = padding;
1388 }
1389
1390 @Override
1391 public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
1392 RecyclerView.State state) {
1393 int position = parent.getChildAdapterPosition(view);
1394 if (position >= 0) {
1395 outRect.left = mPadding;
1396 outRect.right = mPadding;
1397 }
1398 }
1399 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001400}