blob: b48c9f7c919e94a21768a5c55f5111882757bdac [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";
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();
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700452
Jon Miranda16ea1b12017-12-12 14:52:48 -0800453 setUpBottomSheet();
Ching-Sung Li073812b2020-04-07 21:19:21 +0800454 setupBottomActionBar();
Chuck Liao8ec38e02020-02-26 20:59:32 +0800455
Jon Miranda16ea1b12017-12-12 14:52:48 -0800456 return view;
457 }
458
459 @Override
Chuck Liao8ec38e02020-02-26 20:59:32 +0800460 public void onDestroyView() {
461 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
Chuck Liao4f059312020-03-13 23:09:46 +0800462 mBottomActionBar.hide();
Chuck Liao8ec38e02020-02-26 20:59:32 +0800463 mBottomActionBar.clearActionClickListeners();
Chuck Liao69630f12020-03-05 19:01:25 +0800464 updateThumbnail(null);
Chuck Liao8ec38e02020-02-26 20:59:32 +0800465 }
466 super.onDestroyView();
467 }
468
469 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800470 public void onClickTryAgain(@Destination int unused) {
471 if (mPendingSetIndividualHolder != null) {
472 mPendingSetIndividualHolder.setWallpaper();
473 }
474 }
475
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800476 void updateImageGridPadding(boolean addExtraBottomSpace) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800477 int gridPaddingPx = getResources().getDimensionPixelSize(R.dimen.grid_padding_desktop);
478 int bottomSheetHeightPx = getResources().getDimensionPixelSize(
479 R.dimen.current_wallpaper_bottom_sheet_layout_height);
480 int paddingBottomPx = addExtraBottomSpace ? bottomSheetHeightPx : 0;
481 // Only left and top may be set in order for the GridMarginDecoration to work properly.
482 mImageGrid.setPadding(
483 gridPaddingPx, gridPaddingPx, 0, paddingBottomPx);
484 }
485
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700486 private void maybeSetUpImageGrid() {
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700487 // Skip if mImageGrid been initialized yet
488 if (mImageGrid == null) {
489 return;
490 }
491 // Skip if category hasn't loaded yet
492 if (mCategory == null) {
493 return;
494 }
495 // Skip if the adapter was already created
496 if (mAdapter != null) {
497 return;
498 }
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700499 setUpImageGrid();
500 }
501
502 /**
503 * Create the adapter and assign it to mImageGrid.
504 * Both mImageGrid and mCategory are guaranteed to not be null when this method is called.
505 */
506 void setUpImageGrid() {
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800507 mAdapter = new IndividualAdapter(mWallpapers);
508 mImageGrid.setAdapter(mAdapter);
509 mImageGrid.setLayoutManager(new GridLayoutManager(getActivity(), getNumColumns()));
510 }
511
Jon Miranda16ea1b12017-12-12 14:52:48 -0800512 /**
513 * Enables and populates the "Currently set" wallpaper BottomSheet.
514 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800515 void setUpBottomSheet() {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800516 mImageGrid.addOnScrollListener(new OnScrollListener() {
517 @Override
518 public void onScrolled(RecyclerView recyclerView, int dx, final int dy) {
519 if (mCurrentWallpaperBottomSheetPresenter == null) {
520 return;
521 }
522
523 if (mCurrentWallpaperBottomSheetExpandedRunnable != null) {
524 mHandler.removeCallbacks(mCurrentWallpaperBottomSheetExpandedRunnable);
525 }
526 mCurrentWallpaperBottomSheetExpandedRunnable = new Runnable() {
527 @Override
528 public void run() {
529 if (dy > 0) {
530 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(false);
531 } else {
532 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
533 }
534 }
535 };
536 mHandler.postDelayed(mCurrentWallpaperBottomSheetExpandedRunnable, 100);
537 }
538 });
539 }
540
Ching-Sung Li073812b2020-04-07 21:19:21 +0800541 void setupBottomActionBar() {
542 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
543 mBottomActionBar = getActivity().findViewById(R.id.bottom_actionbar);
544
545 mBottomActionBar.setActionClickListener(CANCEL, unused -> {
546 if (mSelectedWallpaperInfo != null) {
547 onWallpaperSelected(null, 0);
548 return;
549 }
550 getActivity().onBackPressed();
551 });
552 mBottomActionBar.setActionClickListener(ROTATION, unused -> {
553 DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
554 startRotationDialogFragment.setTargetFragment(
555 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
556 startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
557 });
558 mBottomActionBar.setActionClickListener(APPLY, unused -> {
559 mBottomActionBar.disableActions();
560 mWallpaperSetter.requestDestination(getActivity(), getFragmentManager(), this,
561 mSelectedWallpaperInfo instanceof LiveWallpaperInfo);
562 });
563
564 mBottomActionBar.show();
565 mBottomActionBar.showActionsOnly(
566 isRotationEnabled() ? EnumSet.of(CANCEL, ROTATION) : EnumSet.of(CANCEL));
567 }
568 }
569
Jon Miranda16ea1b12017-12-12 14:52:48 -0800570 @Override
571 public void onResume() {
572 super.onResume();
573
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700574 WallpaperPreferences preferences = InjectorProvider.getInjector()
575 .getPreferences(getActivity());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800576 preferences.setLastAppActiveTimestamp(new Date().getTime());
577
578 // Reset Glide memory settings to a "normal" level of usage since it may have been lowered in
579 // PreviewFragment.
580 Glide.get(getActivity()).setMemoryCategory(MemoryCategory.NORMAL);
581
582 // Show the staged 'start rotation' error dialog fragment if there is one that was unable to be
583 // shown earlier when this fragment's hosting activity didn't allow committing fragment
584 // transactions.
585 if (mStagedStartRotationErrorDialogFragment != null) {
586 mStagedStartRotationErrorDialogFragment.show(
587 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
588 mStagedStartRotationErrorDialogFragment = null;
589 }
590
591 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one
592 // that was unable to be shown earlier when this fragment's hosting activity didn't allow
593 // committing fragment transactions.
594 if (mStagedSetWallpaperErrorDialogFragment != null) {
595 mStagedSetWallpaperErrorDialogFragment.show(
596 getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
597 mStagedSetWallpaperErrorDialogFragment = null;
598 }
599
600 if (isRotationEnabled()) {
601 if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
602 // Refresh the state of the "start rotation" in case something changed the current daily
603 // rotation while this fragment was paused.
604 RotationHolder rotationHolder = (RotationHolder) mImageGrid
605 .findViewHolderForAdapterPosition(
606 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
607 // The RotationHolder may be null if the RecyclerView has not created the view
608 // holder yet.
609 if (rotationHolder != null && Flags.dynamicStartRotationTileEnabled) {
610 refreshRotationHolder(rotationHolder);
611 }
612 } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
613 if (mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
614 // Must be resuming from a previously stopped state, so re-schedule the update of the
615 // daily wallpapers tile thumbnail.
616 mUpdateDailyWallpaperThumbRunnable.run();
617 }
618 }
619 }
620
621 }
622
623 @Override
624 public void onStop() {
625 super.onStop();
626 mHandler.removeCallbacks(mUpdateDailyWallpaperThumbRunnable);
627 }
628
629 @Override
630 public void onDestroy() {
631 super.onDestroy();
632 if (mProgressDialog != null) {
633 mProgressDialog.dismiss();
634 }
635 mWallpaperChangedNotifier.unregisterListener(mWallpaperChangedListener);
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700636 if (mAppStatusListener != null) {
637 mPackageStatusNotifier.removeListener(mAppStatusListener);
638 }
Chuck Liao69630f12020-03-05 19:01:25 +0800639 mWallpaperSetter.cleanUp();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800640 }
641
642 @Override
643 public void retryStartRotation(@NetworkPreference int networkPreference) {
644 startRotation(networkPreference);
645 }
646
647 public void setCurrentWallpaperBottomSheetPresenter(
648 CurrentWallpaperBottomSheetPresenter presenter) {
649 mCurrentWallpaperBottomSheetPresenter = presenter;
650 }
651
652 public void setWallpapersUiContainer(WallpapersUiContainer uiContainer) {
653 mWallpapersUiContainer = uiContainer;
654 }
655
Chuck Liaob3829fb2020-04-01 00:47:50 +0800656 public void setOnWallpaperSelectedListener(
657 WallpaperSelectedListener wallpaperSelectedListener) {
658 mWallpaperSelectedListener = wallpaperSelectedListener;
659 }
660
661 /**
662 * Resizes the layout's height.
663 */
664 public void resizeLayout(int height) {
665 mImageGrid.getLayoutParams().height = height;
666 mImageGrid.requestLayout();
667 }
668
669 /**
670 * Scrolls to the specific item.
671 *
672 * @param position the position of the item
673 */
674 public void scrollToPosition(int position) {
675 ((GridLayoutManager) mImageGrid.getLayoutManager())
676 .scrollToPositionWithOffset(position, /* offset= */ 0);
677 }
678
Jon Miranda16ea1b12017-12-12 14:52:48 -0800679 /**
680 * Enable a test mode of operation -- in which certain UI features are disabled to allow for
681 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog
682 * constantly keeps the UI thread alive and blocks a test forever.
683 *
684 * @param testingMode
685 */
686 void setTestingMode(boolean testingMode) {
687 mTestingMode = testingMode;
688 }
689
690 /**
691 * Asynchronously fetches the refreshed rotation initialization state that is up to date with the
692 * state of the user's device and binds the state of the current category's rotation to the "start
693 * rotation" tile.
694 */
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700695 private void refreshRotationHolder(RotationHolder rotationHolder) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800696 mWallpaperRotationInitializer.fetchRotationInitializationState(getContext(),
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700697 rotationState -> {
698 // Update the UI state of the "start rotation" tile displayed on screen.
699 // Do this in a Handler so it is scheduled at the end of the message queue.
700 // This is necessary to ensure we do not remove or add data from the adapter
701 // while the layout is still being computed. RecyclerView documentation
702 // therefore recommends performing such changes in a Handler.
703 new Handler().post(() -> {
704 // A config change may have destroyed the activity since the refresh
705 // started, so check for that to avoid an NPE.
706 if (getActivity() == null) {
707 return;
708 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800709
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700710 rotationHolder.bindRotationInitializationState(rotationState);
711 });
Jon Miranda16ea1b12017-12-12 14:52:48 -0800712 });
713 }
714
715 @Override
716 public void startRotation(@NetworkPreference final int networkPreference) {
717 if (!isRotationEnabled()) {
718 Log.e(TAG, "Rotation is not enabled for this category " + mCategory.getTitle());
719 return;
720 }
721
722 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
723 // causes Espresso to hang once the dialog is shown.
724 if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE && !mTestingMode) {
725 int themeResId;
726 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
727 themeResId = R.style.ProgressDialogThemePreL;
728 } else {
729 themeResId = R.style.LightDialogTheme;
730 }
731 mProgressDialog = new ProgressDialog(getActivity(), themeResId);
732
733 mProgressDialog.setTitle(PROGRESS_DIALOG_NO_TITLE);
734 mProgressDialog.setMessage(
735 getResources().getString(R.string.start_rotation_progress_message));
736 mProgressDialog.setIndeterminate(PROGRESS_DIALOG_INDETERMINATE);
737 mProgressDialog.show();
738 }
739
740 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
741 mAdapter.mPendingSelectedAdapterPosition = SPECIAL_FIXED_TILE_ADAPTER_POSITION;
742 }
743
744 final Context appContext = getActivity().getApplicationContext();
745
746 mWallpaperRotationInitializer.setFirstWallpaperInRotation(
747 appContext,
748 networkPreference,
749 new Listener() {
750 @Override
751 public void onFirstWallpaperInRotationSet() {
752 if (mProgressDialog != null) {
753 mProgressDialog.dismiss();
754 }
755
756 // The fragment may be detached from its containing activity if the user exits the
757 // app before the first wallpaper image in rotation finishes downloading.
758 Activity activity = getActivity();
759
Jon Miranda16ea1b12017-12-12 14:52:48 -0800760
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700761 if (mWallpaperRotationInitializer.startRotation(appContext)) {
762 if (activity != null
763 && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
764 try {
765 Toast.makeText(getActivity(),
766 R.string.wallpaper_set_successfully_message,
767 Toast.LENGTH_SHORT).show();
768 } catch (NotFoundException e) {
769 Log.e(TAG, "Could not show toast " + e);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800770 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800771
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700772 activity.setResult(Activity.RESULT_OK);
773 activity.finish();
774 } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
775 mAdapter.updateSelectedTile(SPECIAL_FIXED_TILE_ADAPTER_POSITION);
776 }
777 } else { // Failed to start rotation.
778 showStartRotationErrorDialog(networkPreference);
779
780 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
781 DesktopRotationHolder rotationViewHolder =
782 (DesktopRotationHolder)
783 mImageGrid.findViewHolderForAdapterPosition(
784 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
785 rotationViewHolder.setSelectionState(
786 SelectableHolder.SELECTION_STATE_DESELECTED);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800787 }
788 }
789 }
790
791 @Override
792 public void onError() {
793 if (mProgressDialog != null) {
794 mProgressDialog.dismiss();
795 }
796
797 showStartRotationErrorDialog(networkPreference);
798
799 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
800 DesktopRotationHolder rotationViewHolder =
801 (DesktopRotationHolder) mImageGrid.findViewHolderForAdapterPosition(
802 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
803 rotationViewHolder.setSelectionState(SelectableHolder.SELECTION_STATE_DESELECTED);
804 }
805 }
806 });
807 }
808
809 private void showStartRotationErrorDialog(@NetworkPreference int networkPreference) {
810 BaseActivity activity = (BaseActivity) getActivity();
811 if (activity != null) {
812 StartRotationErrorDialogFragment startRotationErrorDialogFragment =
813 StartRotationErrorDialogFragment.newInstance(networkPreference);
814 startRotationErrorDialogFragment.setTargetFragment(
815 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
816
817 if (activity.isSafeToCommitFragmentTransaction()) {
818 startRotationErrorDialogFragment.show(
819 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
820 } else {
821 mStagedStartRotationErrorDialogFragment = startRotationErrorDialogFragment;
822 }
823 }
824 }
825
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800826 int getNumColumns() {
Ching-Sung Li9df77a32019-07-10 11:45:30 +0800827 Activity activity = getActivity();
828 return activity == null ? 0 : TileSizeCalculator.getNumIndividualColumns(activity);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800829 }
830
831 /**
832 * Returns whether rotation is enabled for this category.
833 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800834 boolean isRotationEnabled() {
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700835 return mWallpaperRotationInitializer != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800836 }
837
838 @Override
839 public void onCurrentWallpaperRefreshed() {
840 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
841 }
842
Chuck Liao69630f12020-03-05 19:01:25 +0800843
844 @Override
845 public void onSet(int destination) {
846 if (mSelectedWallpaperInfo == null) {
847 Log.e(TAG, "Unable to set wallpaper since the selected wallpaper info is null");
848 return;
849 }
850
“Chuckffd832c2020-03-22 02:15:58 +0800851 mWallpaperPersister.setWallpaperInfoInPreview(mSelectedWallpaperInfo);
Chuck Liao69630f12020-03-05 19:01:25 +0800852 if (mSelectedWallpaperInfo instanceof LiveWallpaperInfo) {
853 mWallpaperSetter.setCurrentWallpaper(getActivity(), mSelectedWallpaperInfo, null,
854 destination, 0, null, mSetWallpaperCallback);
855 } else {
856 mWallpaperSetter.setCurrentWallpaper(
857 getActivity(), mSelectedWallpaperInfo, destination, mSetWallpaperCallback);
858 }
“Chuck7ef99722020-03-22 04:34:03 +0800859 onWallpaperDestinationSet(destination);
Chuck Liao69630f12020-03-05 19:01:25 +0800860 }
861
862 private WallpaperPersister.SetWallpaperCallback mSetWallpaperCallback =
863 new WallpaperPersister.SetWallpaperCallback() {
864 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800865 public void onSuccess(WallpaperInfo wallpaperInfo) {
Chuck Liao69630f12020-03-05 19:01:25 +0800866 // TODO(b/150913705): Show the snack bar.
867 mBottomActionBar.enableActions();
Chuck Liao11f4a762020-04-08 13:24:43 +0800868 refreshAppliedWallpaper();
“Chuckffd832c2020-03-22 02:15:58 +0800869
870 mWallpaperPersister.onLiveWallpaperSet();
Chuck Liao69630f12020-03-05 19:01:25 +0800871 }
872
873 @Override
874 public void onError(@Nullable Throwable throwable) {
875 Log.e(TAG, "Can't apply the wallpaper.");
876 mBottomActionBar.enableActions();
877 }
878 };
879
880 @Override
881 public void onDialogDismissed(boolean withItemSelected) {
882 if (!withItemSelected) {
883 mBottomActionBar.enableActions();
884 }
885 }
886
Jon Miranda16ea1b12017-12-12 14:52:48 -0800887 /**
888 * Shows a "set wallpaper" error dialog with a failure message and button to try again.
889 */
890 private void showSetWallpaperErrorDialog() {
891 SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance(
892 R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH);
893 dialogFragment.setTargetFragment(this, UNUSED_REQUEST_CODE);
894
895 if (((BaseActivity) getActivity()).isSafeToCommitFragmentTransaction()) {
896 dialogFragment.show(getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
897 } else {
898 mStagedSetWallpaperErrorDialogFragment = dialogFragment;
899 }
900 }
901
Ching-Sung Li073812b2020-04-07 21:19:21 +0800902 void updateBottomActions(boolean hasWallpaperSelected) {
Chuck Liao69630f12020-03-05 19:01:25 +0800903 mBottomActionBar.showActions(
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800904 hasWallpaperSelected ? EnumSet.of(APPLY, INFORMATION) : EnumSet.of(ROTATION));
Chuck Liao69630f12020-03-05 19:01:25 +0800905 mBottomActionBar.hideActions(
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800906 hasWallpaperSelected ? EnumSet.of(ROTATION) : EnumSet.of(APPLY, INFORMATION));
Chuck Liao69630f12020-03-05 19:01:25 +0800907 }
908
909 private void updateThumbnail(WallpaperInfo selectedWallpaperInfo) {
Chuck Liaof40063f2020-03-03 18:35:24 +0800910 ThumbnailUpdater thumbnailUpdater = (ThumbnailUpdater) getParentFragment();
Chuck Liao69630f12020-03-05 19:01:25 +0800911 if (thumbnailUpdater == null) {
912 return;
913 }
914
915 if (selectedWallpaperInfo != null) {
916 thumbnailUpdater.updateThumbnail(selectedWallpaperInfo);
917 } else {
918 thumbnailUpdater.restoreThumbnails();
Chuck Liaof40063f2020-03-03 18:35:24 +0800919 }
920 }
921
“Chuck7ef99722020-03-22 04:34:03 +0800922 private void onWallpaperDestinationSet(int destination) {
923 WallpaperDestinationCallback wallpaperDestinationCallback =
924 (WallpaperDestinationCallback) getParentFragment();
925 if (wallpaperDestinationCallback == null) {
926 return;
927 }
928
929 wallpaperDestinationCallback.onDestinationSet(destination);
930 }
931
Ching-Sung Li073812b2020-04-07 21:19:21 +0800932 void onWallpaperSelected(@Nullable WallpaperInfo newSelectedWallpaperInfo,
Chuck Liaob3829fb2020-04-01 00:47:50 +0800933 int position) {
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800934 if (mSelectedWallpaperInfo == newSelectedWallpaperInfo) {
“Chuckffd832c2020-03-22 02:15:58 +0800935 return;
936 }
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800937 // Update current wallpaper.
“Chuckffd832c2020-03-22 02:15:58 +0800938 updateActivatedStatus(mSelectedWallpaperInfo == null
939 ? mAppliedWallpaperInfo : mSelectedWallpaperInfo, false);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800940 // Update new selected wallpaper.
941 updateActivatedStatus(newSelectedWallpaperInfo == null
942 ? mAppliedWallpaperInfo : newSelectedWallpaperInfo, true);
943
944 mSelectedWallpaperInfo = newSelectedWallpaperInfo;
945 updateBottomActions(mSelectedWallpaperInfo != null);
946 updateThumbnail(mSelectedWallpaperInfo);
947 // Populate wallpaper info to bottom sheet page.
948 if (mSelectedWallpaperInfo != null) {
949 mBottomActionBar.populateInfoPage(
Chuck Liaob3829fb2020-04-01 00:47:50 +0800950 mSelectedWallpaperInfo.getAttributions(getContext()),
951 shouldShowMetadataInPreview(mSelectedWallpaperInfo));
952 }
953
954 if (mWallpaperSelectedListener != null) {
955 mWallpaperSelectedListener.onWallpaperSelected(position);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800956 }
Chuck Liaof40063f2020-03-03 18:35:24 +0800957 }
958
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800959 private void updateActivatedStatus(WallpaperInfo wallpaperInfo, boolean isActivated) {
“Chuckffd832c2020-03-22 02:15:58 +0800960 if (wallpaperInfo == null) {
961 return;
962 }
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800963 int index = mWallpapers.indexOf(wallpaperInfo);
964 index = (isRotationEnabled() || mCategory.supportsCustomPhotos())
965 ? index + 1 : index;
966 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
967 if (holder != null) {
968 holder.itemView.setActivated(isActivated);
969 } else {
970 // Item is not visible, make sure the item is re-bound when it becomes visible.
971 mAdapter.notifyItemChanged(index);
972 }
973 }
974
“Chuckffd832c2020-03-22 02:15:58 +0800975 private void updateAppliedStatus(WallpaperInfo wallpaperInfo, boolean isApplied) {
976 if (wallpaperInfo == null) {
977 return;
978 }
979 int index = mWallpapers.indexOf(wallpaperInfo);
980 index = (isRotationEnabled() || mCategory.supportsCustomPhotos())
981 ? index + 1 : index;
982 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
983 if (holder != null) {
984 holder.itemView.findViewById(R.id.check_circle)
985 .setVisibility(isApplied ? View.VISIBLE : View.GONE);
986 } else {
987 // Item is not visible, make sure the item is re-bound when it becomes visible.
988 mAdapter.notifyItemChanged(index);
989 }
990 }
991
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800992 private static boolean shouldShowMetadataInPreview(WallpaperInfo wallpaperInfo) {
993 android.app.WallpaperInfo wallpaperComponent = wallpaperInfo.getWallpaperComponent();
994 return wallpaperComponent == null || wallpaperComponent.getShowMetadataInPreview();
995 }
996
Chuck Liao11f4a762020-04-08 13:24:43 +0800997 private void refreshAppliedWallpaper() {
998 // Clear the check mark and blue border(if it shows) of the old applied wallpaper.
999 showCheckMarkAndBorderForAppliedWallpaper(false);
1000
1001 // Update to the new applied wallpaper.
1002 String appliedWallpaperId = getAppliedWallpaperId();
1003 Optional<WallpaperInfo> wallpaperInfoOptional = mWallpapers
1004 .stream()
1005 .filter(wallpaper -> wallpaper.getWallpaperId() != null)
1006 .filter(wallpaper -> wallpaper.getWallpaperId().equals(appliedWallpaperId))
1007 .findFirst();
1008 mAppliedWallpaperInfo = wallpaperInfoOptional.orElse(null);
1009
1010 // Set the check mark and blue border(if user doesn't select) of the new applied wallpaper.
1011 showCheckMarkAndBorderForAppliedWallpaper(true);
1012 }
1013
1014 private String getAppliedWallpaperId() {
1015 WallpaperPreferences prefs =
1016 InjectorProvider.getInjector().getPreferences(getContext());
1017 android.app.WallpaperInfo wallpaperInfo = mWallpaperManager.getWallpaperInfo();
1018 boolean isDestinationBoth =
1019 mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK) < 0;
1020
1021 if (isDestinationBoth || mWallpaperDestination == WallpaperPersister.DEST_HOME_SCREEN) {
1022 return wallpaperInfo != null
1023 ? wallpaperInfo.getServiceName() : prefs.getHomeWallpaperRemoteId();
1024 } else {
1025 return prefs.getLockWallpaperRemoteId();
1026 }
1027 }
1028
1029 private void showCheckMarkAndBorderForAppliedWallpaper(boolean show) {
1030 updateAppliedStatus(mAppliedWallpaperInfo, show);
1031 if (mSelectedWallpaperInfo == null) {
1032 updateActivatedStatus(mAppliedWallpaperInfo, show);
1033 }
1034 }
1035
Jon Miranda16ea1b12017-12-12 14:52:48 -08001036 /**
1037 * ViewHolder subclass for "daily refresh" tile in the RecyclerView, only shown if rotation is
1038 * enabled for this category.
1039 */
1040 private class RotationHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
1041
Chuck Liaoba401232020-03-13 20:11:04 +08001042 private CardView mTileLayout;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001043 private TextView mRotationMessage;
1044 private TextView mRotationTitle;
1045 private ImageView mRefreshIcon;
1046
1047 RotationHolder(View itemView) {
1048 super(itemView);
1049 itemView.setOnClickListener(this);
1050
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -07001051 mTileLayout = itemView.findViewById(R.id.daily_refresh);
1052 mRotationMessage = itemView.findViewById(R.id.rotation_tile_message);
1053 mRotationTitle = itemView.findViewById(R.id.rotation_tile_title);
1054 mRefreshIcon = itemView.findViewById(R.id.rotation_tile_refresh_icon);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001055 mTileLayout.getLayoutParams().height = mTileSizePx.y;
1056
1057 // If the feature flag for "dynamic start rotation tile" is not enabled, fall back to the
1058 // static UI with a blue accent color background and "Tap to turn on" text.
1059 if (!Flags.dynamicStartRotationTileEnabled) {
1060 mTileLayout.setBackgroundColor(
1061 getResources().getColor(R.color.rotation_tile_enabled_background_color));
1062 mRotationMessage.setText(R.string.daily_refresh_tile_subtitle);
1063 mRotationTitle.setTextColor(
1064 getResources().getColor(R.color.rotation_tile_enabled_title_text_color));
1065 mRotationMessage.setTextColor(
1066 getResources().getColor(R.color.rotation_tile_enabled_subtitle_text_color));
1067 mRefreshIcon.setColorFilter(
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -07001068 getResources().getColor(R.color.rotation_tile_enabled_refresh_icon_color),
1069 Mode.SRC_IN);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001070 return;
1071 }
1072
1073 // Initialize the state of the "start rotation" tile (i.e., whether it is gray or blue to
1074 // indicate if rotation is turned on for the current category) with last-known rotation state
1075 // that could be stale. The last-known rotation state is correct in most cases and is a good
1076 // starting point but may not be accurate if the user set a wallpaper through a 3rd party app
1077 // while this app was paused.
1078 int rotationState = mWallpaperRotationInitializer.getRotationInitializationStateDirty(
1079 getContext());
1080 bindRotationInitializationState(rotationState);
1081 }
1082
1083 @Override
1084 public void onClick(View v) {
Samuel Fufa03bc6ac2019-09-19 12:01:50 -07001085 DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
Jon Miranda16ea1b12017-12-12 14:52:48 -08001086 startRotationDialogFragment.setTargetFragment(
1087 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
1088 startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
1089 }
1090
1091 /**
1092 * Binds the provided rotation initialization state to the RotationHolder and updates the tile's
1093 * UI to be in sync with the state (i.e., message and color appropriately reflect the state to
1094 * the user).
1095 */
1096 void bindRotationInitializationState(@RotationInitializationState int rotationState) {
1097 int newBackgroundColor =
1098 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1099 ? getResources().getColor(R.color.rotation_tile_not_enabled_background_color)
1100 : getResources().getColor(R.color.rotation_tile_enabled_background_color);
1101 int newTitleTextColor =
1102 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1103 ? getResources().getColor(R.color.rotation_tile_not_enabled_title_text_color)
1104 : getResources().getColor(R.color.rotation_tile_enabled_title_text_color);
1105 int newSubtitleTextColor =
1106 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1107 ? getResources().getColor(R.color.rotation_tile_not_enabled_subtitle_text_color)
1108 : getResources().getColor(R.color.rotation_tile_enabled_subtitle_text_color);
1109 int newRefreshIconColor =
1110 (rotationState == WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED)
1111 ? getResources().getColor(R.color.rotation_tile_not_enabled_refresh_icon_color)
1112 : getResources().getColor(R.color.rotation_tile_enabled_refresh_icon_color);
1113
Chuck Liaoba401232020-03-13 20:11:04 +08001114 mTileLayout.setCardBackgroundColor(newBackgroundColor);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001115 mRotationTitle.setTextColor(newTitleTextColor);
1116 mRotationMessage.setText(getResIdForRotationState(rotationState));
1117 mRotationMessage.setTextColor(newSubtitleTextColor);
1118 mRefreshIcon.setColorFilter(newRefreshIconColor, Mode.SRC_IN);
1119 }
1120 }
1121
1122 /**
1123 * RecyclerView Adapter subclass for the wallpaper tiles in the RecyclerView.
1124 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001125 class IndividualAdapter extends RecyclerView.Adapter<ViewHolder> {
1126 static final int ITEM_VIEW_TYPE_ROTATION = 1;
1127 static final int ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER = 2;
1128 static final int ITEM_VIEW_TYPE_MY_PHOTOS = 3;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001129
1130 private final List<WallpaperInfo> mWallpapers;
1131
1132 private int mPendingSelectedAdapterPosition;
1133 private int mSelectedAdapterPosition;
1134
1135 IndividualAdapter(List<WallpaperInfo> wallpapers) {
1136 mWallpapers = wallpapers;
1137 mPendingSelectedAdapterPosition = -1;
1138 mSelectedAdapterPosition = -1;
1139 }
1140
1141 @Override
1142 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
1143 switch (viewType) {
1144 case ITEM_VIEW_TYPE_ROTATION:
1145 return createRotationHolder(parent);
1146 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1147 return createIndividualHolder(parent);
1148 case ITEM_VIEW_TYPE_MY_PHOTOS:
1149 return createMyPhotosHolder(parent);
1150 default:
1151 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1152 return null;
1153 }
1154 }
1155
1156 @Override
1157 public int getItemViewType(int position) {
1158 if (isRotationEnabled() && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
1159 return ITEM_VIEW_TYPE_ROTATION;
1160 }
1161
1162 // A category cannot have both a "start rotation" tile and a "my photos" tile.
1163 if (mCategory.supportsCustomPhotos()
1164 && !isRotationEnabled()
1165 && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
1166 return ITEM_VIEW_TYPE_MY_PHOTOS;
1167 }
1168
1169 return ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER;
1170 }
1171
1172 @Override
1173 public void onBindViewHolder(ViewHolder holder, int position) {
1174 int viewType = getItemViewType(position);
1175
1176 switch (viewType) {
1177 case ITEM_VIEW_TYPE_ROTATION:
1178 onBindRotationHolder(holder, position);
1179 break;
1180 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1181 onBindIndividualHolder(holder, position);
1182 break;
1183 case ITEM_VIEW_TYPE_MY_PHOTOS:
1184 ((MyPhotosViewHolder) holder).bind();
1185 break;
1186 default:
1187 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1188 }
1189 }
1190
1191 @Override
1192 public int getItemCount() {
1193 return (isRotationEnabled() || mCategory.supportsCustomPhotos())
1194 ? mWallpapers.size() + 1
1195 : mWallpapers.size();
1196 }
1197
1198 private ViewHolder createRotationHolder(ViewGroup parent) {
1199 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1200 View view;
1201
1202 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1203 view = layoutInflater.inflate(R.layout.grid_item_rotation_desktop, parent, false);
1204 SelectionAnimator selectionAnimator =
1205 new CheckmarkSelectionAnimator(getActivity(), view);
1206 return new DesktopRotationHolder(
1207 getActivity(), mTileSizePx.y, view, selectionAnimator,
1208 IndividualPickerFragment.this);
1209 } else { // MOBILE
1210 view = layoutInflater.inflate(R.layout.grid_item_rotation, parent, false);
1211 return new RotationHolder(view);
1212 }
1213 }
1214
1215 private ViewHolder createIndividualHolder(ViewGroup parent) {
1216 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1217 View view = layoutInflater.inflate(R.layout.grid_item_image, parent, false);
Chuck Liao6a37a1c2020-03-07 03:39:43 +08001218 if (!TEMP_BOTTOM_ACTION_BAR_FEATURE) {
1219 view.findViewById(R.id.tile).setPadding(0, 0, 0, 0);
1220 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001221
1222 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1223 SelectionAnimator selectionAnimator =
1224 new CheckmarkSelectionAnimator(getActivity(), view);
1225 return new SetIndividualHolder(
1226 getActivity(), mTileSizePx.y, view,
1227 selectionAnimator,
1228 new OnSetListener() {
1229 @Override
1230 public void onPendingWallpaperSet(int adapterPosition) {
1231 // Deselect and hide loading indicator for any previously pending tile.
1232 if (mPendingSelectedAdapterPosition != -1) {
1233 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1234 mPendingSelectedAdapterPosition);
1235 if (oldViewHolder instanceof SelectableHolder) {
1236 ((SelectableHolder) oldViewHolder).setSelectionState(
1237 SelectableHolder.SELECTION_STATE_DESELECTED);
1238 }
1239 }
1240
1241 if (mSelectedAdapterPosition != -1) {
1242 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1243 mSelectedAdapterPosition);
1244 if (oldViewHolder instanceof SelectableHolder) {
1245 ((SelectableHolder) oldViewHolder).setSelectionState(
1246 SelectableHolder.SELECTION_STATE_DESELECTED);
1247 }
1248 }
1249
1250 mPendingSelectedAdapterPosition = adapterPosition;
1251 }
1252
1253 @Override
1254 public void onWallpaperSet(int adapterPosition) {
1255 // No-op -- UI handles a new wallpaper being set by reacting to the
1256 // WallpaperChangedNotifier.
1257 }
1258
1259 @Override
1260 public void onWallpaperSetFailed(SetIndividualHolder holder) {
1261 showSetWallpaperErrorDialog();
1262 mPendingSetIndividualHolder = holder;
1263 }
1264 });
1265 } else { // MOBILE
Chuck Liao3d1a51c2020-02-17 18:29:34 +08001266 return new PreviewIndividualHolder(getActivity(), mTileSizePx.y, view);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001267 }
1268 }
1269
1270 private ViewHolder createMyPhotosHolder(ViewGroup parent) {
1271 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1272 View view = layoutInflater.inflate(R.layout.grid_item_my_photos, parent, false);
1273
Santiago Etchebeherefab49612019-01-15 12:22:42 -08001274 return new MyPhotosViewHolder(getActivity(),
1275 ((MyPhotosStarterProvider) getActivity()).getMyPhotosStarter(),
1276 mTileSizePx.y, view);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001277 }
1278
1279 /**
1280 * Marks the tile at the given position as selected with a visual indication. Also updates the
1281 * "currently selected" BottomSheet to reflect the newly selected tile.
1282 */
1283 private void updateSelectedTile(int newlySelectedPosition) {
1284 // Prevent multiple spinners from appearing with a user tapping several tiles in rapid
1285 // succession.
1286 if (mPendingSelectedAdapterPosition == mSelectedAdapterPosition) {
1287 return;
1288 }
1289
1290 if (mCurrentWallpaperBottomSheetPresenter != null) {
1291 mCurrentWallpaperBottomSheetPresenter.refreshCurrentWallpapers(
1292 IndividualPickerFragment.this);
1293
1294 if (mCurrentWallpaperBottomSheetExpandedRunnable != null) {
1295 mHandler.removeCallbacks(mCurrentWallpaperBottomSheetExpandedRunnable);
1296 }
1297 mCurrentWallpaperBottomSheetExpandedRunnable = new Runnable() {
1298 @Override
1299 public void run() {
1300 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
1301 }
1302 };
1303 mHandler.postDelayed(mCurrentWallpaperBottomSheetExpandedRunnable, 100);
1304 }
1305
1306 // User may have switched to another category, thus detaching this fragment, so check here.
1307 // NOTE: We do this check after updating the current wallpaper BottomSheet so that the update
1308 // still occurs in the UI after the user selects that other category.
1309 if (getActivity() == null) {
1310 return;
1311 }
1312
1313 // Update the newly selected wallpaper ViewHolder and the old one so that if
1314 // selection UI state applies (desktop UI), it is updated.
1315 if (mSelectedAdapterPosition >= 0) {
1316 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1317 mSelectedAdapterPosition);
1318 if (oldViewHolder instanceof SelectableHolder) {
1319 ((SelectableHolder) oldViewHolder).setSelectionState(
1320 SelectableHolder.SELECTION_STATE_DESELECTED);
1321 }
1322 }
1323
1324 // Animate selection of newly selected tile.
1325 ViewHolder newViewHolder = mImageGrid
1326 .findViewHolderForAdapterPosition(newlySelectedPosition);
1327 if (newViewHolder instanceof SelectableHolder) {
1328 ((SelectableHolder) newViewHolder).setSelectionState(
1329 SelectableHolder.SELECTION_STATE_SELECTED);
1330 }
1331
1332 mSelectedAdapterPosition = newlySelectedPosition;
1333
1334 // If the tile was in the last row of the grid, add space below it so the user can scroll down
1335 // and up to see the BottomSheet without it fully overlapping the newly selected tile.
1336 int spanCount = ((GridLayoutManager) mImageGrid.getLayoutManager()).getSpanCount();
1337 int numRows = (int) Math.ceil((float) getItemCount() / spanCount);
1338 int rowOfNewlySelectedTile = newlySelectedPosition / spanCount;
1339 boolean isInLastRow = rowOfNewlySelectedTile == numRows - 1;
1340
1341 updateImageGridPadding(isInLastRow /* addExtraBottomSpace */);
1342 }
1343
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001344 void onBindRotationHolder(ViewHolder holder, int position) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001345 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1346 String collectionId = mCategory.getCollectionId();
1347 ((DesktopRotationHolder) holder).bind(collectionId);
1348
1349 if (mWallpaperPreferences.getWallpaperPresentationMode()
1350 == WallpaperPreferences.PRESENTATION_MODE_ROTATING
1351 && collectionId.equals(mWallpaperPreferences.getHomeWallpaperCollectionId())) {
1352 mSelectedAdapterPosition = position;
1353 }
1354
1355 if (!mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
1356 updateDesktopDailyRotationThumbnail((DesktopRotationHolder) holder);
1357 mWasUpdateRunnableRun = true;
1358 }
1359 }
1360 }
1361
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001362 void onBindIndividualHolder(ViewHolder holder, int position) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001363 int wallpaperIndex = (isRotationEnabled() || mCategory.supportsCustomPhotos())
1364 ? position - 1 : position;
1365 WallpaperInfo wallpaper = mWallpapers.get(wallpaperIndex);
1366 ((IndividualHolder) holder).bindWallpaper(wallpaper);
“Chuck7ef99722020-03-22 04:34:03 +08001367 String appliedWallpaperId = getAppliedWallpaperId();
“Chuckffd832c2020-03-22 02:15:58 +08001368 boolean isWallpaperApplied = wallpaper.getWallpaperId().equals(appliedWallpaperId);
1369 boolean isWallpaperSelected = wallpaper.equals(mSelectedWallpaperInfo);
1370 boolean hasUserSelectedWallpaper = mSelectedWallpaperInfo != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001371
“Chuckffd832c2020-03-22 02:15:58 +08001372 if (isWallpaperApplied) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001373 mSelectedAdapterPosition = position;
“Chuckffd832c2020-03-22 02:15:58 +08001374 mAppliedWallpaperInfo = wallpaper;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001375 }
Chuck Liaof40063f2020-03-03 18:35:24 +08001376
1377 if (TEMP_BOTTOM_ACTION_BAR_FEATURE) {
“Chuckffd832c2020-03-22 02:15:58 +08001378 holder.itemView.setActivated(
1379 (isWallpaperApplied && !hasUserSelectedWallpaper) || isWallpaperSelected);
1380 holder.itemView.findViewById(R.id.check_circle).setVisibility(
1381 isWallpaperApplied ? View.VISIBLE : View.GONE);
Chuck Liao69630f12020-03-05 19:01:25 +08001382 holder.itemView.findViewById(R.id.tile).setOnClickListener(
Chuck Liaob3829fb2020-04-01 00:47:50 +08001383 view -> onWallpaperSelected(wallpaper, position));
Chuck Liaof40063f2020-03-03 18:35:24 +08001384 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001385 }
1386 }
Chuck Liaoba401232020-03-13 20:11:04 +08001387
1388 private class GridPaddingDecoration extends RecyclerView.ItemDecoration {
1389
1390 private int mPadding;
1391
1392 GridPaddingDecoration(int padding) {
1393 mPadding = padding;
1394 }
1395
1396 @Override
1397 public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
1398 RecyclerView.State state) {
1399 int position = parent.getChildAdapterPosition(view);
1400 if (position >= 0) {
1401 outRect.left = mPadding;
1402 outRect.right = mPadding;
1403 }
1404 }
1405 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001406}