blob: 260d121fb21d83c96a4229f199c488287646e6e4 [file] [log] [blame]
Jon Miranda16ea1b12017-12-12 14:52:48 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.wallpaper.picker.individual;
17
Chuck Liao7dc21572020-05-14 18:37:36 +080018import static com.android.wallpaper.picker.WallpaperPickerDelegate.PREVIEW_WALLPAPER_REQUEST_CODE;
Chuck Liao69630f12020-03-05 19:01:25 +080019import static com.android.wallpaper.widget.BottomActionBar.BottomAction.APPLY;
Chuck Liao7dc21572020-05-14 18:37:36 +080020import static com.android.wallpaper.widget.BottomActionBar.BottomAction.EDIT;
chihhangchuang22aa0cc2020-03-25 19:12:42 +080021import static com.android.wallpaper.widget.BottomActionBar.BottomAction.INFORMATION;
Chuck Liao8ec38e02020-02-26 20:59:32 +080022import static com.android.wallpaper.widget.BottomActionBar.BottomAction.ROTATION;
23
Jon Miranda16ea1b12017-12-12 14:52:48 -080024import android.app.Activity;
25import android.app.ProgressDialog;
“Chuck7ef99722020-03-22 04:34:03 +080026import android.app.WallpaperManager;
Jon Miranda16ea1b12017-12-12 14:52:48 -080027import android.content.Context;
Chihhang Chuang85f099a2020-06-16 18:04:39 +080028import android.content.DialogInterface;
chihhangchuangc687d912020-05-04 14:33:05 +080029import android.content.Intent;
Santiago Etchebehereb1854472019-06-06 17:44:54 -070030import android.content.res.Configuration;
Jon Miranda16ea1b12017-12-12 14:52:48 -080031import android.content.res.Resources.NotFoundException;
32import android.graphics.Point;
Chuck Liaoba401232020-03-13 20:11:04 +080033import android.graphics.Rect;
Jon Miranda16ea1b12017-12-12 14:52:48 -080034import android.os.Build.VERSION;
35import android.os.Build.VERSION_CODES;
36import android.os.Bundle;
37import android.os.Handler;
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -070038import android.service.wallpaper.WallpaperService;
Jon Miranda16ea1b12017-12-12 14:52:48 -080039import android.util.Log;
40import android.view.LayoutInflater;
41import android.view.View;
42import android.view.ViewGroup;
Jon Miranda16ea1b12017-12-12 14:52:48 -080043import android.widget.Toast;
44
Santiago Etchebehereb1854472019-06-06 17:44:54 -070045import androidx.annotation.NonNull;
Chuck Liao69630f12020-03-05 19:01:25 +080046import androidx.annotation.Nullable;
Chuck Liaof6b4b192020-08-07 02:31:32 +080047import androidx.core.widget.ContentLoadingProgressBar;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080048import androidx.fragment.app.DialogFragment;
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;
Santiago Etchebehere8648bb82019-08-06 17:09:02 -070057import com.android.wallpaper.model.Category;
58import com.android.wallpaper.model.CategoryProvider;
59import com.android.wallpaper.model.CategoryReceiver;
Chuck Liao69630f12020-03-05 19:01:25 +080060import com.android.wallpaper.model.LiveWallpaperInfo;
Jon Miranda16ea1b12017-12-12 14:52:48 -080061import com.android.wallpaper.model.WallpaperCategory;
62import com.android.wallpaper.model.WallpaperInfo;
63import com.android.wallpaper.model.WallpaperReceiver;
64import com.android.wallpaper.model.WallpaperRotationInitializer;
65import com.android.wallpaper.model.WallpaperRotationInitializer.Listener;
66import com.android.wallpaper.model.WallpaperRotationInitializer.NetworkPreference;
Jon Miranda16ea1b12017-12-12 14:52:48 -080067import com.android.wallpaper.module.FormFactorChecker;
68import com.android.wallpaper.module.FormFactorChecker.FormFactor;
69import com.android.wallpaper.module.Injector;
70import com.android.wallpaper.module.InjectorProvider;
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -070071import com.android.wallpaper.module.PackageStatusNotifier;
chihhangchuangc687d912020-05-04 14:33:05 +080072import com.android.wallpaper.module.UserEventLogger;
Jon Miranda16ea1b12017-12-12 14:52:48 -080073import com.android.wallpaper.module.WallpaperChangedNotifier;
74import com.android.wallpaper.module.WallpaperPersister;
75import com.android.wallpaper.module.WallpaperPersister.Destination;
76import com.android.wallpaper.module.WallpaperPreferences;
Chuck Liao69630f12020-03-05 19:01:25 +080077import com.android.wallpaper.module.WallpaperSetter;
Jon Miranda16ea1b12017-12-12 14:52:48 -080078import com.android.wallpaper.picker.BaseActivity;
chihhangchuang3efb6832020-04-17 02:06:25 +080079import com.android.wallpaper.picker.BottomActionBarFragment;
Jon Miranda16ea1b12017-12-12 14:52:48 -080080import com.android.wallpaper.picker.CurrentWallpaperBottomSheetPresenter;
Chuck Liaob17d1502020-09-07 21:55:30 +080081import com.android.wallpaper.picker.FragmentTransactionChecker;
Santiago Etchebeherefab49612019-01-15 12:22:42 -080082import com.android.wallpaper.picker.MyPhotosStarter.MyPhotosStarterProvider;
Chuck Liao7dc21572020-05-14 18:37:36 +080083import com.android.wallpaper.picker.PreviewActivity;
Jon Miranda16ea1b12017-12-12 14:52:48 -080084import com.android.wallpaper.picker.RotationStarter;
Chuck Liao69630f12020-03-05 19:01:25 +080085import com.android.wallpaper.picker.SetWallpaperDialogFragment;
Jon Miranda16ea1b12017-12-12 14:52:48 -080086import com.android.wallpaper.picker.SetWallpaperErrorDialogFragment;
87import com.android.wallpaper.picker.StartRotationDialogFragment;
88import com.android.wallpaper.picker.StartRotationErrorDialogFragment;
chihhangchuangc687d912020-05-04 14:33:05 +080089import com.android.wallpaper.picker.WallpaperInfoHelper;
Jon Miranda16ea1b12017-12-12 14:52:48 -080090import com.android.wallpaper.picker.WallpapersUiContainer;
91import com.android.wallpaper.picker.individual.SetIndividualHolder.OnSetListener;
92import com.android.wallpaper.util.DiskBasedLogger;
Santiago Etchebehere53c63432020-05-07 18:55:35 -070093import com.android.wallpaper.util.SizeCalculator;
Chuck Liao8ec38e02020-02-26 20:59:32 +080094import com.android.wallpaper.widget.BottomActionBar;
chihhangchuang1a29e752020-04-28 18:22:53 +080095import com.android.wallpaper.widget.WallpaperInfoView;
Wesley.CW Wangdc68fde2020-06-15 19:12:33 +080096import com.android.wallpaper.widget.WallpaperPickerRecyclerViewAccessibilityDelegate;
97import com.android.wallpaper.widget.WallpaperPickerRecyclerViewAccessibilityDelegate.BottomSheetHost;
Sunny Goyal8600a3f2018-08-15 12:48:01 -070098
Jon Miranda16ea1b12017-12-12 14:52:48 -080099import com.bumptech.glide.Glide;
100import com.bumptech.glide.MemoryCategory;
101
102import java.util.ArrayList;
103import java.util.Date;
104import java.util.List;
Chuck Liao11f4a762020-04-08 13:24:43 +0800105import java.util.Optional;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800106import java.util.Random;
107
108/**
109 * Displays the Main UI for picking an individual wallpaper image.
110 */
chihhangchuang3efb6832020-04-17 02:06:25 +0800111public class IndividualPickerFragment extends BottomActionBarFragment
Jon Miranda16ea1b12017-12-12 14:52:48 -0800112 implements RotationStarter, StartRotationErrorDialogFragment.Listener,
113 CurrentWallpaperBottomSheetPresenter.RefreshListener,
Chihhang Chuang85f099a2020-06-16 18:04:39 +0800114 SetWallpaperErrorDialogFragment.Listener, SetWallpaperDialogFragment.Listener,
115 StartRotationDialogFragment.Listener {
Chuck Liao46644b92020-06-08 14:20:50 +0800116
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800117 /**
118 * Position of a special tile that doesn't belong to an individual wallpaper of the category,
119 * such as "my photos" or "daily rotation".
120 */
121 static final int SPECIAL_FIXED_TILE_ADAPTER_POSITION = 0;
122 static final String ARG_CATEGORY_COLLECTION_ID = "category_collection_id";
123
Jon Miranda16ea1b12017-12-12 14:52:48 -0800124 private static final String TAG = "IndividualPickerFrgmnt";
Jon Miranda16ea1b12017-12-12 14:52:48 -0800125 private static final int UNUSED_REQUEST_CODE = 1;
126 private static final String TAG_START_ROTATION_DIALOG = "start_rotation_dialog";
127 private static final String TAG_START_ROTATION_ERROR_DIALOG = "start_rotation_error_dialog";
128 private static final String PROGRESS_DIALOG_NO_TITLE = null;
129 private static final boolean PROGRESS_DIALOG_INDETERMINATE = true;
130 private static final String TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT =
131 "individual_set_wallpaper_error_dialog";
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700132 private static final String KEY_NIGHT_MODE = "IndividualPickerFragment.NIGHT_MODE";
Jon Miranda16ea1b12017-12-12 14:52:48 -0800133
Chuck Liao8ec38e02020-02-26 20:59:32 +0800134 /**
Chuck Liaof40063f2020-03-03 18:35:24 +0800135 * An interface for updating the thumbnail with the specific wallpaper.
136 */
137 public interface ThumbnailUpdater {
138 /**
139 * Updates the thumbnail with the specific wallpaper.
140 */
141 void updateThumbnail(WallpaperInfo wallpaperInfo);
142
143 /**
144 * Restores to the thumbnails of the wallpapers which were applied.
145 */
146 void restoreThumbnails();
147 }
148
“Chuck7ef99722020-03-22 04:34:03 +0800149 /**
150 * An interface for receiving the destination of the new applied wallpaper.
151 */
152 public interface WallpaperDestinationCallback {
153 /**
154 * Called when the destination of the wallpaper is set.
155 *
156 * @param destination the destination which a wallpaper may be set.
157 * See {@link Destination} for more details.
158 */
159 void onDestinationSet(@Destination int destination);
160 }
161
Chuck Liaob3829fb2020-04-01 00:47:50 +0800162 /**
163 * The listener which will be notified when the wallpaper is selected.
164 */
165 public interface WallpaperSelectedListener {
166 /**
167 * Called when the wallpaper is selected.
168 *
169 * @param position the position of the selected wallpaper
170 */
171 void onWallpaperSelected(int position);
172 }
173
Chuck Liaof6b4b192020-08-07 02:31:32 +0800174 /**
175 * Interface to be implemented by a Fragment hosting a {@link IndividualPickerFragment}
176 */
177 public interface IndividualPickerFragmentHost {
178 /**
179 * Sets the title in the toolbar.
180 */
181 void setToolbarTitle(CharSequence title);
182
183 /**
184 * Moves to the previous fragment.
185 */
186 void moveToPreviousFragment();
187 }
188
Ching-Sung Lied6560f2020-05-04 19:25:09 +0800189 WallpaperPersister mWallpaperPersister;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800190 WallpaperPreferences mWallpaperPreferences;
191 WallpaperChangedNotifier mWallpaperChangedNotifier;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800192 RecyclerView mImageGrid;
193 IndividualAdapter mAdapter;
194 WallpaperCategory mCategory;
195 WallpaperRotationInitializer mWallpaperRotationInitializer;
196 List<WallpaperInfo> mWallpapers;
197 Point mTileSizePx;
198 WallpapersUiContainer mWallpapersUiContainer;
199 @FormFactor
200 int mFormFactor;
201 PackageStatusNotifier mPackageStatusNotifier;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800202
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800203 Handler mHandler;
204 Random mRandom;
Chuck Liaof6b4b192020-08-07 02:31:32 +0800205 boolean mIsWallpapersReceived;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800206
207 WallpaperChangedNotifier.Listener mWallpaperChangedListener =
208 new WallpaperChangedNotifier.Listener() {
209 @Override
210 public void onWallpaperChanged() {
211 if (mFormFactor != FormFactorChecker.FORM_FACTOR_DESKTOP) {
212 return;
213 }
214
215 ViewHolder selectedViewHolder = mImageGrid.findViewHolderForAdapterPosition(
216 mAdapter.mSelectedAdapterPosition);
217
218 // Null remote ID => My Photos wallpaper, so deselect whatever was previously selected.
219 if (mWallpaperPreferences.getHomeWallpaperRemoteId() == null) {
220 if (selectedViewHolder instanceof SelectableHolder) {
221 ((SelectableHolder) selectedViewHolder).setSelectionState(
222 SelectableHolder.SELECTION_STATE_DESELECTED);
223 }
224 } else {
225 mAdapter.updateSelectedTile(mAdapter.mPendingSelectedAdapterPosition);
226 }
227 }
228 };
229 PackageStatusNotifier.Listener mAppStatusListener;
Ching-Sung Li073812b2020-04-07 21:19:21 +0800230 BottomActionBar mBottomActionBar;
chihhangchuang1a29e752020-04-28 18:22:53 +0800231 WallpaperInfoView mWallpaperInfoView;
Ching-Sung Li073812b2020-04-07 21:19:21 +0800232 @Nullable WallpaperInfo mSelectedWallpaperInfo;
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800233
chihhangchuangc687d912020-05-04 14:33:05 +0800234 private UserEventLogger mUserEventLogger;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800235 private ProgressDialog mProgressDialog;
236 private boolean mTestingMode;
237 private CurrentWallpaperBottomSheetPresenter mCurrentWallpaperBottomSheetPresenter;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800238 private SetIndividualHolder mPendingSetIndividualHolder;
Chuck Liaof6b4b192020-08-07 02:31:32 +0800239 private ContentLoadingProgressBar mLoading;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800240
241 /**
242 * Staged error dialog fragments that were unable to be shown when the activity didn't allow
243 * committing fragment transactions.
244 */
245 private SetWallpaperErrorDialogFragment mStagedSetWallpaperErrorDialogFragment;
246 private StartRotationErrorDialogFragment mStagedStartRotationErrorDialogFragment;
247
Jon Miranda16ea1b12017-12-12 14:52:48 -0800248 private Runnable mCurrentWallpaperBottomSheetExpandedRunnable;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800249
250 /**
251 * Whether {@code mUpdateDailyWallpaperThumbRunnable} has been run at least once in this
252 * invocation of the fragment.
253 */
254 private boolean mWasUpdateRunnableRun;
255
256 /**
257 * A Runnable which regularly updates the thumbnail for the "Daily wallpapers" tile in desktop
258 * mode.
259 */
260 private Runnable mUpdateDailyWallpaperThumbRunnable = new Runnable() {
261 @Override
262 public void run() {
263 ViewHolder viewHolder = mImageGrid.findViewHolderForAdapterPosition(
264 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
265 if (viewHolder instanceof DesktopRotationHolder) {
266 updateDesktopDailyRotationThumbnail((DesktopRotationHolder) viewHolder);
267 } else { // viewHolder is null
268 // If the rotation tile is unavailable (because user has scrolled down, causing the
269 // ViewHolder to be recycled), schedule the update for some time later. Once user scrolls up
270 // again, the ViewHolder will be re-bound and its thumbnail will be updated.
271 mHandler.postDelayed(mUpdateDailyWallpaperThumbRunnable,
272 DesktopRotationHolder.CROSSFADE_DURATION_MILLIS
273 + DesktopRotationHolder.CROSSFADE_DURATION_PAUSE_MILLIS);
274 }
275 }
276 };
277
Chuck Liao69630f12020-03-05 19:01:25 +0800278 private WallpaperSetter mWallpaperSetter;
“Chuckffd832c2020-03-22 02:15:58 +0800279 private WallpaperInfo mAppliedWallpaperInfo;
“Chuck7ef99722020-03-22 04:34:03 +0800280 private WallpaperManager mWallpaperManager;
281 private int mWallpaperDestination;
Chuck Liaob3829fb2020-04-01 00:47:50 +0800282 private WallpaperSelectedListener mWallpaperSelectedListener;
Chuck Liao8ec38e02020-02-26 20:59:32 +0800283
Jon Miranda16ea1b12017-12-12 14:52:48 -0800284 public static IndividualPickerFragment newInstance(String collectionId) {
285 Bundle args = new Bundle();
286 args.putString(ARG_CATEGORY_COLLECTION_ID, collectionId);
287
288 IndividualPickerFragment fragment = new IndividualPickerFragment();
289 fragment.setArguments(args);
290 return fragment;
291 }
292
“Chuck7ef99722020-03-22 04:34:03 +0800293 /**
294 * Highlights the applied wallpaper (if it exists) according to the destination a wallpaper
295 * would be set.
296 *
297 * @param wallpaperDestination the destination a wallpaper would be set.
298 * It will be either {@link Destination#DEST_HOME_SCREEN}
299 * or {@link Destination#DEST_LOCK_SCREEN}.
300 */
301 public void highlightAppliedWallpaper(@Destination int wallpaperDestination) {
302 mWallpaperDestination = wallpaperDestination;
Chuck Liao11f4a762020-04-08 13:24:43 +0800303 if (mWallpapers != null) {
304 refreshAppliedWallpaper();
“Chuck7ef99722020-03-22 04:34:03 +0800305 }
306 }
307
Jon Miranda16ea1b12017-12-12 14:52:48 -0800308 private void updateDesktopDailyRotationThumbnail(DesktopRotationHolder holder) {
309 int wallpapersIndex = mRandom.nextInt(mWallpapers.size());
310 Asset newThumbnailAsset = mWallpapers.get(wallpapersIndex).getThumbAsset(
311 getActivity());
312 holder.updateThumbnail(newThumbnailAsset, new DrawableLoadedListener() {
313 @Override
314 public void onDrawableLoaded() {
315 if (getActivity() == null) {
316 return;
317 }
318
319 // Schedule the next update of the thumbnail.
320 int delayMillis = DesktopRotationHolder.CROSSFADE_DURATION_MILLIS
321 + DesktopRotationHolder.CROSSFADE_DURATION_PAUSE_MILLIS;
322 mHandler.postDelayed(mUpdateDailyWallpaperThumbRunnable, delayMillis);
323 }
324 });
325 }
326
327 @Override
328 public void onCreate(Bundle savedInstanceState) {
329 super.onCreate(savedInstanceState);
330
331 Injector injector = InjectorProvider.getInjector();
332 Context appContext = getContext().getApplicationContext();
333 mWallpaperPreferences = injector.getPreferences(appContext);
334
335 mWallpaperChangedNotifier = WallpaperChangedNotifier.getInstance();
336 mWallpaperChangedNotifier.registerListener(mWallpaperChangedListener);
337
“Chuck7ef99722020-03-22 04:34:03 +0800338 mWallpaperManager = WallpaperManager.getInstance(appContext);
339
Jon Miranda16ea1b12017-12-12 14:52:48 -0800340 mFormFactor = injector.getFormFactorChecker(appContext).getFormFactor();
341
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700342 mPackageStatusNotifier = injector.getPackageStatusNotifier(appContext);
343
chihhangchuangc687d912020-05-04 14:33:05 +0800344 mUserEventLogger = injector.getUserEventLogger(appContext);
345
“Chuckffd832c2020-03-22 02:15:58 +0800346 mWallpaperPersister = injector.getWallpaperPersister(appContext);
Chuck Liao69630f12020-03-05 19:01:25 +0800347 mWallpaperSetter = new WallpaperSetter(
“Chuckffd832c2020-03-22 02:15:58 +0800348 mWallpaperPersister,
Chuck Liao69630f12020-03-05 19:01:25 +0800349 injector.getPreferences(appContext),
350 injector.getUserEventLogger(appContext),
351 false);
352
Jon Miranda16ea1b12017-12-12 14:52:48 -0800353 mWallpapers = new ArrayList<>();
354 mRandom = new Random();
355 mHandler = new Handler();
356
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700357 // Clear Glide's cache if night-mode changed to ensure thumbnails are reloaded
358 if (savedInstanceState != null && (savedInstanceState.getInt(KEY_NIGHT_MODE)
359 != (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK))) {
360 Glide.get(getContext()).clearMemory();
361 }
362
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700363 CategoryProvider categoryProvider = injector.getCategoryProvider(appContext);
364 categoryProvider.fetchCategories(new CategoryReceiver() {
365 @Override
366 public void onCategoryReceived(Category category) {
367 // Do nothing.
368 }
369
370 @Override
371 public void doneFetchingCategories() {
372 mCategory = (WallpaperCategory) categoryProvider.getCategory(
373 getArguments().getString(ARG_CATEGORY_COLLECTION_ID));
374 if (mCategory == null) {
375 DiskBasedLogger.e(TAG, "Failed to find the category.", getContext());
376
377 // The absence of this category in the CategoryProvider indicates a broken
378 // state, see b/38030129. Hence, finish the activity and return.
Chuck Liaof6b4b192020-08-07 02:31:32 +0800379 getIndividualPickerFragmentHost().moveToPreviousFragment();
380 Toast.makeText(getContext(), R.string.collection_not_exist_msg,
381 Toast.LENGTH_SHORT).show();
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700382 return;
383 }
384 onCategoryLoaded();
385 }
386 }, false);
387 }
388
Chuck Liaof6b4b192020-08-07 02:31:32 +0800389
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700390 protected void onCategoryLoaded() {
Chuck Liaof6b4b192020-08-07 02:31:32 +0800391 getIndividualPickerFragmentHost().setToolbarTitle(mCategory.getTitle());
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700392 mWallpaperRotationInitializer = mCategory.getWallpaperRotationInitializer();
Chuck Liao58e4a1c2020-05-22 11:35:35 +0800393 // Avoids the "rotation" action is not shown correctly
394 // in a rare case : onCategoryLoaded() is called after onBottomActionBarReady().
395 if (isRotationEnabled() && mBottomActionBar != null
396 && !mBottomActionBar.areActionsShown(ROTATION)) {
397 mBottomActionBar.showActions(ROTATION);
398 }
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700399 fetchWallpapers(false);
400
401 if (mCategory.supportsThirdParty()) {
402 mAppStatusListener = (packageName, status) -> {
403 if (status != PackageStatusNotifier.PackageStatus.REMOVED ||
404 mCategory.containsThirdParty(packageName)) {
405 fetchWallpapers(true);
406 }
407 };
408 mPackageStatusNotifier.addListener(mAppStatusListener,
409 WallpaperService.SERVICE_INTERFACE);
410 }
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700411
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700412 maybeSetUpImageGrid();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700413 }
414
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800415 void fetchWallpapers(boolean forceReload) {
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700416 mWallpapers.clear();
Chuck Liaof6b4b192020-08-07 02:31:32 +0800417 mIsWallpapersReceived = false;
418 updateLoading();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800419 mCategory.fetchWallpapers(getActivity().getApplicationContext(), new WallpaperReceiver() {
420 @Override
421 public void onWallpapersReceived(List<WallpaperInfo> wallpapers) {
Chuck Liaof6b4b192020-08-07 02:31:32 +0800422 mIsWallpapersReceived = true;
423 updateLoading();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800424 for (WallpaperInfo wallpaper : wallpapers) {
425 mWallpapers.add(wallpaper);
426 }
427
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700428 // Wallpapers may load after the adapter is initialized, in which case we have
429 // to explicitly notify that the data set has changed.
Jon Miranda16ea1b12017-12-12 14:52:48 -0800430 if (mAdapter != null) {
431 mAdapter.notifyDataSetChanged();
432 }
433
434 if (mWallpapersUiContainer != null) {
435 mWallpapersUiContainer.onWallpapersReady();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700436 } else {
437 if (wallpapers.isEmpty()) {
438 // If there are no more wallpapers and we're on phone, just finish the
439 // Activity.
440 Activity activity = getActivity();
441 if (activity != null
442 && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
443 activity.finish();
444 }
445 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800446 }
447 }
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700448 }, forceReload);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800449 }
450
Chuck Liaof6b4b192020-08-07 02:31:32 +0800451 void updateLoading() {
452 if (mLoading == null) {
453 return;
454 }
455
456 if (mIsWallpapersReceived) {
457 mLoading.hide();
458 } else {
459 mLoading.show();
460 }
461 }
462
Jon Miranda16ea1b12017-12-12 14:52:48 -0800463 @Override
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700464 public void onSaveInstanceState(@NonNull Bundle outState) {
465 super.onSaveInstanceState(outState);
Santiago Etchebehere0ec065c2019-06-13 11:30:21 -0700466 outState.putInt(KEY_NIGHT_MODE,
Santiago Etchebehereb1854472019-06-06 17:44:54 -0700467 getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK);
468 }
469
470 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800471 public View onCreateView(LayoutInflater inflater, ViewGroup container,
472 Bundle savedInstanceState) {
473 View view = inflater.inflate(R.layout.fragment_individual_picker, container, false);
474
Santiago Etchebehere53c63432020-05-07 18:55:35 -0700475 mTileSizePx = SizeCalculator.getIndividualTileSize(getActivity());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800476
477 mImageGrid = (RecyclerView) view.findViewById(R.id.wallpaper_grid);
478 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
479 int gridPaddingPx = getResources().getDimensionPixelSize(R.dimen.grid_padding_desktop);
480 updateImageGridPadding(false /* addExtraBottomSpace */);
481 mImageGrid.setScrollBarSize(gridPaddingPx);
482 }
Chuck Liaoba401232020-03-13 20:11:04 +0800483 mImageGrid.addItemDecoration(new GridPaddingDecoration(
484 getResources().getDimensionPixelSize(R.dimen.grid_padding)));
Wesley.CW Wangdc68fde2020-06-15 19:12:33 +0800485 mImageGrid.setAccessibilityDelegateCompat(
486 new WallpaperPickerRecyclerViewAccessibilityDelegate(
487 mImageGrid, (BottomSheetHost) getParentFragment(), getNumColumns()));
Chuck Liaof6b4b192020-08-07 02:31:32 +0800488 mLoading = view.findViewById(R.id.loading_indicator);
489 updateLoading();
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700490 maybeSetUpImageGrid();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800491 setUpBottomSheet();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800492 return view;
493 }
494
495 @Override
496 public void onClickTryAgain(@Destination int unused) {
497 if (mPendingSetIndividualHolder != null) {
498 mPendingSetIndividualHolder.setWallpaper();
499 }
500 }
501
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800502 void updateImageGridPadding(boolean addExtraBottomSpace) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800503 int gridPaddingPx = getResources().getDimensionPixelSize(R.dimen.grid_padding_desktop);
504 int bottomSheetHeightPx = getResources().getDimensionPixelSize(
505 R.dimen.current_wallpaper_bottom_sheet_layout_height);
506 int paddingBottomPx = addExtraBottomSpace ? bottomSheetHeightPx : 0;
507 // Only left and top may be set in order for the GridMarginDecoration to work properly.
508 mImageGrid.setPadding(
509 gridPaddingPx, gridPaddingPx, 0, paddingBottomPx);
510 }
511
Chuck Liaof6b4b192020-08-07 02:31:32 +0800512 private IndividualPickerFragmentHost getIndividualPickerFragmentHost() {
513 return (IndividualPickerFragmentHost) getParentFragment();
514 }
515
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700516 private void maybeSetUpImageGrid() {
Santiago Etchebehere8648bb82019-08-06 17:09:02 -0700517 // Skip if mImageGrid been initialized yet
518 if (mImageGrid == null) {
519 return;
520 }
521 // Skip if category hasn't loaded yet
522 if (mCategory == null) {
523 return;
524 }
525 // Skip if the adapter was already created
526 if (mAdapter != null) {
527 return;
528 }
Santiago Etchebehere460fbcb2019-08-20 11:47:30 -0700529 setUpImageGrid();
530 }
531
532 /**
533 * Create the adapter and assign it to mImageGrid.
534 * Both mImageGrid and mCategory are guaranteed to not be null when this method is called.
535 */
536 void setUpImageGrid() {
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800537 mAdapter = new IndividualAdapter(mWallpapers);
538 mImageGrid.setAdapter(mAdapter);
539 mImageGrid.setLayoutManager(new GridLayoutManager(getActivity(), getNumColumns()));
540 }
541
Jon Miranda16ea1b12017-12-12 14:52:48 -0800542 /**
543 * Enables and populates the "Currently set" wallpaper BottomSheet.
544 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800545 void setUpBottomSheet() {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800546 mImageGrid.addOnScrollListener(new OnScrollListener() {
547 @Override
548 public void onScrolled(RecyclerView recyclerView, int dx, final int dy) {
549 if (mCurrentWallpaperBottomSheetPresenter == null) {
550 return;
551 }
552
553 if (mCurrentWallpaperBottomSheetExpandedRunnable != null) {
554 mHandler.removeCallbacks(mCurrentWallpaperBottomSheetExpandedRunnable);
555 }
556 mCurrentWallpaperBottomSheetExpandedRunnable = new Runnable() {
557 @Override
558 public void run() {
559 if (dy > 0) {
560 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(false);
561 } else {
562 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
563 }
564 }
565 };
566 mHandler.postDelayed(mCurrentWallpaperBottomSheetExpandedRunnable, 100);
567 }
568 });
569 }
570
chihhangchuang3efb6832020-04-17 02:06:25 +0800571 @Override
572 protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
Chuck Liao342f4ab2020-05-26 18:28:09 +0800573 mBottomActionBar = bottomActionBar;
574 if (isRotationEnabled()) {
575 mBottomActionBar.showActionsOnly(ROTATION);
Ching-Sung Li073812b2020-04-07 21:19:21 +0800576 }
Chuck Liao342f4ab2020-05-26 18:28:09 +0800577 mBottomActionBar.setActionClickListener(ROTATION, unused -> {
578 DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
579 startRotationDialogFragment.setTargetFragment(
580 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
581 startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
582 });
583 mBottomActionBar.setActionClickListener(APPLY, unused -> {
584 mBottomActionBar.disableActions();
585 mWallpaperSetter.requestDestination(getActivity(), getFragmentManager(), this,
586 mSelectedWallpaperInfo instanceof LiveWallpaperInfo);
587 });
588
589 mWallpaperInfoView = (WallpaperInfoView) LayoutInflater.from(getContext())
590 .inflate(R.layout.wallpaper_info_view, /* root= */ null);
591 mBottomActionBar.attachViewToBottomSheetAndBindAction(mWallpaperInfoView, INFORMATION);
592 mBottomActionBar.setActionClickListener(EDIT, unused -> {
593 mWallpaperPersister.setWallpaperInfoInPreview(mSelectedWallpaperInfo);
594 mSelectedWallpaperInfo.showPreview(getActivity(),
595 new PreviewActivity.PreviewActivityIntentFactory(),
596 PREVIEW_WALLPAPER_REQUEST_CODE);
597 });
598 mBottomActionBar.show();
Ching-Sung Li073812b2020-04-07 21:19:21 +0800599 }
600
Jon Miranda16ea1b12017-12-12 14:52:48 -0800601 @Override
602 public void onResume() {
603 super.onResume();
604
Santiago Etchebehere8cad0dd2019-10-17 10:52:39 -0700605 WallpaperPreferences preferences = InjectorProvider.getInjector()
606 .getPreferences(getActivity());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800607 preferences.setLastAppActiveTimestamp(new Date().getTime());
608
609 // Reset Glide memory settings to a "normal" level of usage since it may have been lowered in
610 // PreviewFragment.
611 Glide.get(getActivity()).setMemoryCategory(MemoryCategory.NORMAL);
612
613 // Show the staged 'start rotation' error dialog fragment if there is one that was unable to be
614 // shown earlier when this fragment's hosting activity didn't allow committing fragment
615 // transactions.
616 if (mStagedStartRotationErrorDialogFragment != null) {
617 mStagedStartRotationErrorDialogFragment.show(
618 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
619 mStagedStartRotationErrorDialogFragment = null;
620 }
621
622 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one
623 // that was unable to be shown earlier when this fragment's hosting activity didn't allow
624 // committing fragment transactions.
625 if (mStagedSetWallpaperErrorDialogFragment != null) {
626 mStagedSetWallpaperErrorDialogFragment.show(
627 getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
628 mStagedSetWallpaperErrorDialogFragment = null;
629 }
630
Chuck Liao5a4243b2020-05-20 23:56:39 +0800631 if (shouldShowRotationTile() && mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
632 // Must be resuming from a previously stopped state, so re-schedule the update of the
633 // daily wallpapers tile thumbnail.
634 mUpdateDailyWallpaperThumbRunnable.run();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800635 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800636 }
637
638 @Override
639 public void onStop() {
640 super.onStop();
641 mHandler.removeCallbacks(mUpdateDailyWallpaperThumbRunnable);
642 }
643
644 @Override
645 public void onDestroy() {
646 super.onDestroy();
647 if (mProgressDialog != null) {
648 mProgressDialog.dismiss();
649 }
650 mWallpaperChangedNotifier.unregisterListener(mWallpaperChangedListener);
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700651 if (mAppStatusListener != null) {
652 mPackageStatusNotifier.removeListener(mAppStatusListener);
653 }
Chuck Liao69630f12020-03-05 19:01:25 +0800654 mWallpaperSetter.cleanUp();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800655 }
656
657 @Override
Chihhang Chuang85f099a2020-06-16 18:04:39 +0800658 public void onStartRotationDialogDismiss(@NonNull DialogInterface dialog) {
chihhangchuang8f9da5f2020-06-17 00:32:18 +0800659 // TODO(b/159310028): Refactor fragment layer to make it able to restore from config change.
660 // This is to handle config change with StartRotationDialog popup, the StartRotationDialog
661 // still holds a reference to the destroyed Fragment and is calling
662 // onStartRotationDialogDismissed on that destroyed Fragment.
663 if (mBottomActionBar != null) {
664 mBottomActionBar.deselectAction(ROTATION);
665 }
Chihhang Chuang85f099a2020-06-16 18:04:39 +0800666 }
667
668 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800669 public void retryStartRotation(@NetworkPreference int networkPreference) {
670 startRotation(networkPreference);
671 }
672
chihhangchuang7feb3752020-04-24 02:48:56 +0800673 @Override
674 public boolean onBackPressed() {
675 if (mSelectedWallpaperInfo != null) {
676 onWallpaperSelected(null, 0);
677 return true;
678 }
679 return false;
680 }
681
Jon Miranda16ea1b12017-12-12 14:52:48 -0800682 public void setCurrentWallpaperBottomSheetPresenter(
683 CurrentWallpaperBottomSheetPresenter presenter) {
684 mCurrentWallpaperBottomSheetPresenter = presenter;
685 }
686
687 public void setWallpapersUiContainer(WallpapersUiContainer uiContainer) {
688 mWallpapersUiContainer = uiContainer;
689 }
690
Chuck Liaob3829fb2020-04-01 00:47:50 +0800691 public void setOnWallpaperSelectedListener(
692 WallpaperSelectedListener wallpaperSelectedListener) {
693 mWallpaperSelectedListener = wallpaperSelectedListener;
694 }
695
696 /**
697 * Resizes the layout's height.
698 */
699 public void resizeLayout(int height) {
700 mImageGrid.getLayoutParams().height = height;
701 mImageGrid.requestLayout();
702 }
703
704 /**
705 * Scrolls to the specific item.
706 *
707 * @param position the position of the item
708 */
709 public void scrollToPosition(int position) {
710 ((GridLayoutManager) mImageGrid.getLayoutManager())
711 .scrollToPositionWithOffset(position, /* offset= */ 0);
712 }
713
Jon Miranda16ea1b12017-12-12 14:52:48 -0800714 /**
715 * Enable a test mode of operation -- in which certain UI features are disabled to allow for
716 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog
717 * constantly keeps the UI thread alive and blocks a test forever.
718 *
719 * @param testingMode
720 */
721 void setTestingMode(boolean testingMode) {
722 mTestingMode = testingMode;
723 }
724
Jon Miranda16ea1b12017-12-12 14:52:48 -0800725 @Override
726 public void startRotation(@NetworkPreference final int networkPreference) {
727 if (!isRotationEnabled()) {
728 Log.e(TAG, "Rotation is not enabled for this category " + mCategory.getTitle());
729 return;
730 }
731
732 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
733 // causes Espresso to hang once the dialog is shown.
734 if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE && !mTestingMode) {
735 int themeResId;
736 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
737 themeResId = R.style.ProgressDialogThemePreL;
738 } else {
739 themeResId = R.style.LightDialogTheme;
740 }
741 mProgressDialog = new ProgressDialog(getActivity(), themeResId);
742
743 mProgressDialog.setTitle(PROGRESS_DIALOG_NO_TITLE);
744 mProgressDialog.setMessage(
745 getResources().getString(R.string.start_rotation_progress_message));
746 mProgressDialog.setIndeterminate(PROGRESS_DIALOG_INDETERMINATE);
747 mProgressDialog.show();
748 }
749
750 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
751 mAdapter.mPendingSelectedAdapterPosition = SPECIAL_FIXED_TILE_ADAPTER_POSITION;
752 }
753
754 final Context appContext = getActivity().getApplicationContext();
755
756 mWallpaperRotationInitializer.setFirstWallpaperInRotation(
757 appContext,
758 networkPreference,
759 new Listener() {
760 @Override
761 public void onFirstWallpaperInRotationSet() {
762 if (mProgressDialog != null) {
763 mProgressDialog.dismiss();
764 }
765
766 // The fragment may be detached from its containing activity if the user exits the
767 // app before the first wallpaper image in rotation finishes downloading.
768 Activity activity = getActivity();
769
Jon Miranda16ea1b12017-12-12 14:52:48 -0800770
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700771 if (mWallpaperRotationInitializer.startRotation(appContext)) {
772 if (activity != null
773 && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
774 try {
775 Toast.makeText(getActivity(),
776 R.string.wallpaper_set_successfully_message,
777 Toast.LENGTH_SHORT).show();
778 } catch (NotFoundException e) {
779 Log.e(TAG, "Could not show toast " + e);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800780 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800781
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700782 activity.setResult(Activity.RESULT_OK);
783 activity.finish();
784 } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
785 mAdapter.updateSelectedTile(SPECIAL_FIXED_TILE_ADAPTER_POSITION);
786 }
787 } else { // Failed to start rotation.
788 showStartRotationErrorDialog(networkPreference);
789
790 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
791 DesktopRotationHolder rotationViewHolder =
792 (DesktopRotationHolder)
793 mImageGrid.findViewHolderForAdapterPosition(
794 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
795 rotationViewHolder.setSelectionState(
796 SelectableHolder.SELECTION_STATE_DESELECTED);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800797 }
798 }
799 }
800
801 @Override
802 public void onError() {
803 if (mProgressDialog != null) {
804 mProgressDialog.dismiss();
805 }
806
807 showStartRotationErrorDialog(networkPreference);
808
809 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
810 DesktopRotationHolder rotationViewHolder =
811 (DesktopRotationHolder) mImageGrid.findViewHolderForAdapterPosition(
812 SPECIAL_FIXED_TILE_ADAPTER_POSITION);
813 rotationViewHolder.setSelectionState(SelectableHolder.SELECTION_STATE_DESELECTED);
814 }
815 }
816 });
817 }
818
819 private void showStartRotationErrorDialog(@NetworkPreference int networkPreference) {
Chuck Liaob17d1502020-09-07 21:55:30 +0800820 FragmentTransactionChecker activity = (FragmentTransactionChecker) getActivity();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800821 if (activity != null) {
822 StartRotationErrorDialogFragment startRotationErrorDialogFragment =
823 StartRotationErrorDialogFragment.newInstance(networkPreference);
824 startRotationErrorDialogFragment.setTargetFragment(
825 IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
826
827 if (activity.isSafeToCommitFragmentTransaction()) {
828 startRotationErrorDialogFragment.show(
829 getFragmentManager(), TAG_START_ROTATION_ERROR_DIALOG);
830 } else {
831 mStagedStartRotationErrorDialogFragment = startRotationErrorDialogFragment;
832 }
833 }
834 }
835
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800836 int getNumColumns() {
Ching-Sung Li9df77a32019-07-10 11:45:30 +0800837 Activity activity = getActivity();
Chuck Liaoe2fe0302020-06-29 21:15:35 +0800838 return activity == null ? 1 : SizeCalculator.getNumIndividualColumns(activity);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800839 }
840
841 /**
842 * Returns whether rotation is enabled for this category.
843 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800844 boolean isRotationEnabled() {
Samuel Fufa03bc6ac2019-09-19 12:01:50 -0700845 return mWallpaperRotationInitializer != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800846 }
847
848 @Override
849 public void onCurrentWallpaperRefreshed() {
850 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
851 }
852
Chuck Liao69630f12020-03-05 19:01:25 +0800853 @Override
854 public void onSet(int destination) {
855 if (mSelectedWallpaperInfo == null) {
856 Log.e(TAG, "Unable to set wallpaper since the selected wallpaper info is null");
857 return;
858 }
859
“Chuckffd832c2020-03-22 02:15:58 +0800860 mWallpaperPersister.setWallpaperInfoInPreview(mSelectedWallpaperInfo);
Chuck Liao69630f12020-03-05 19:01:25 +0800861 if (mSelectedWallpaperInfo instanceof LiveWallpaperInfo) {
862 mWallpaperSetter.setCurrentWallpaper(getActivity(), mSelectedWallpaperInfo, null,
863 destination, 0, null, mSetWallpaperCallback);
864 } else {
865 mWallpaperSetter.setCurrentWallpaper(
866 getActivity(), mSelectedWallpaperInfo, destination, mSetWallpaperCallback);
867 }
“Chuck7ef99722020-03-22 04:34:03 +0800868 onWallpaperDestinationSet(destination);
Chuck Liao69630f12020-03-05 19:01:25 +0800869 }
870
871 private WallpaperPersister.SetWallpaperCallback mSetWallpaperCallback =
872 new WallpaperPersister.SetWallpaperCallback() {
873 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800874 public void onSuccess(WallpaperInfo wallpaperInfo) {
chihhangchuang210c9602020-06-02 12:38:14 +0800875 mWallpaperPersister.onLiveWallpaperSet();
Chuck Liao6e52fff2020-04-23 16:11:23 +0800876 Toast.makeText(getActivity(), R.string.wallpaper_set_successfully_message,
877 Toast.LENGTH_SHORT).show();
chihhangchuang210c9602020-06-02 12:38:14 +0800878 getActivity().overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
879 getActivity().finish();
Chuck Liao69630f12020-03-05 19:01:25 +0800880 }
881
882 @Override
883 public void onError(@Nullable Throwable throwable) {
884 Log.e(TAG, "Can't apply the wallpaper.");
885 mBottomActionBar.enableActions();
886 }
887 };
888
889 @Override
890 public void onDialogDismissed(boolean withItemSelected) {
891 if (!withItemSelected) {
892 mBottomActionBar.enableActions();
893 }
894 }
895
Jon Miranda16ea1b12017-12-12 14:52:48 -0800896 /**
897 * Shows a "set wallpaper" error dialog with a failure message and button to try again.
898 */
899 private void showSetWallpaperErrorDialog() {
900 SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance(
901 R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH);
902 dialogFragment.setTargetFragment(this, UNUSED_REQUEST_CODE);
903
904 if (((BaseActivity) getActivity()).isSafeToCommitFragmentTransaction()) {
905 dialogFragment.show(getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
906 } else {
907 mStagedSetWallpaperErrorDialogFragment = dialogFragment;
908 }
909 }
910
Ching-Sung Li073812b2020-04-07 21:19:21 +0800911 void updateBottomActions(boolean hasWallpaperSelected) {
chihhangchuang803ea9a2020-04-21 13:03:10 +0800912 if (hasWallpaperSelected) {
Chuck Liao7dc21572020-05-14 18:37:36 +0800913 mBottomActionBar.showActionsOnly(INFORMATION, EDIT, APPLY);
chihhangchuang803ea9a2020-04-21 13:03:10 +0800914 } else {
chihhangchuang08abb582020-04-27 17:20:31 +0800915 mBottomActionBar.showActionsOnly(ROTATION);
chihhangchuang803ea9a2020-04-21 13:03:10 +0800916 }
Chuck Liao69630f12020-03-05 19:01:25 +0800917 }
918
919 private void updateThumbnail(WallpaperInfo selectedWallpaperInfo) {
Chuck Liaof40063f2020-03-03 18:35:24 +0800920 ThumbnailUpdater thumbnailUpdater = (ThumbnailUpdater) getParentFragment();
Chuck Liao69630f12020-03-05 19:01:25 +0800921 if (thumbnailUpdater == null) {
922 return;
923 }
924
925 if (selectedWallpaperInfo != null) {
926 thumbnailUpdater.updateThumbnail(selectedWallpaperInfo);
927 } else {
928 thumbnailUpdater.restoreThumbnails();
Chuck Liaof40063f2020-03-03 18:35:24 +0800929 }
930 }
931
“Chuck7ef99722020-03-22 04:34:03 +0800932 private void onWallpaperDestinationSet(int destination) {
933 WallpaperDestinationCallback wallpaperDestinationCallback =
934 (WallpaperDestinationCallback) getParentFragment();
935 if (wallpaperDestinationCallback == null) {
936 return;
937 }
938
939 wallpaperDestinationCallback.onDestinationSet(destination);
940 }
941
Ching-Sung Li073812b2020-04-07 21:19:21 +0800942 void onWallpaperSelected(@Nullable WallpaperInfo newSelectedWallpaperInfo,
Chuck Liaob3829fb2020-04-01 00:47:50 +0800943 int position) {
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800944 if (mSelectedWallpaperInfo == newSelectedWallpaperInfo) {
“Chuckffd832c2020-03-22 02:15:58 +0800945 return;
946 }
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800947 // Update current wallpaper.
“Chuckffd832c2020-03-22 02:15:58 +0800948 updateActivatedStatus(mSelectedWallpaperInfo == null
949 ? mAppliedWallpaperInfo : mSelectedWallpaperInfo, false);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800950 // Update new selected wallpaper.
951 updateActivatedStatus(newSelectedWallpaperInfo == null
952 ? mAppliedWallpaperInfo : newSelectedWallpaperInfo, true);
953
954 mSelectedWallpaperInfo = newSelectedWallpaperInfo;
955 updateBottomActions(mSelectedWallpaperInfo != null);
956 updateThumbnail(mSelectedWallpaperInfo);
chihhangchuangde9e8722020-05-02 17:22:13 +0800957 // Populate wallpaper info into view.
chihhangchuang1a29e752020-04-28 18:22:53 +0800958 if (mSelectedWallpaperInfo != null && mWallpaperInfoView != null) {
chihhangchuangc687d912020-05-04 14:33:05 +0800959 WallpaperInfoHelper.loadExploreIntent(
960 getContext(),
961 mSelectedWallpaperInfo,
962 (actionLabel, exploreIntent) ->
963 mWallpaperInfoView.populateWallpaperInfo(
964 mSelectedWallpaperInfo, actionLabel, exploreIntent,
965 v -> onExploreClicked(exploreIntent)));
Chuck Liaob3829fb2020-04-01 00:47:50 +0800966 }
967
968 if (mWallpaperSelectedListener != null) {
969 mWallpaperSelectedListener.onWallpaperSelected(position);
chihhangchuang22aa0cc2020-03-25 19:12:42 +0800970 }
Chuck Liaof40063f2020-03-03 18:35:24 +0800971 }
972
chihhangchuangc687d912020-05-04 14:33:05 +0800973 private void onExploreClicked(Intent exploreIntent) {
974 if (getContext() == null) {
975 return;
976 }
977 Context context = getContext();
978 mUserEventLogger.logActionClicked(mSelectedWallpaperInfo.getCollectionId(context),
979 mSelectedWallpaperInfo.getActionLabelRes(context));
980
981 startActivity(exploreIntent);
982 }
983
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800984 private void updateActivatedStatus(WallpaperInfo wallpaperInfo, boolean isActivated) {
“Chuckffd832c2020-03-22 02:15:58 +0800985 if (wallpaperInfo == null) {
986 return;
987 }
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800988 int index = mWallpapers.indexOf(wallpaperInfo);
Chuck Liao5a4243b2020-05-20 23:56:39 +0800989 index = (shouldShowRotationTile() || mCategory.supportsCustomPhotos())
Chuck Liao6a37a1c2020-03-07 03:39:43 +0800990 ? index + 1 : index;
991 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
992 if (holder != null) {
993 holder.itemView.setActivated(isActivated);
994 } else {
995 // Item is not visible, make sure the item is re-bound when it becomes visible.
996 mAdapter.notifyItemChanged(index);
997 }
998 }
999
“Chuckffd832c2020-03-22 02:15:58 +08001000 private void updateAppliedStatus(WallpaperInfo wallpaperInfo, boolean isApplied) {
1001 if (wallpaperInfo == null) {
1002 return;
1003 }
1004 int index = mWallpapers.indexOf(wallpaperInfo);
Chuck Liao5a4243b2020-05-20 23:56:39 +08001005 index = (shouldShowRotationTile() || mCategory.supportsCustomPhotos())
“Chuckffd832c2020-03-22 02:15:58 +08001006 ? index + 1 : index;
1007 ViewHolder holder = mImageGrid.findViewHolderForAdapterPosition(index);
1008 if (holder != null) {
1009 holder.itemView.findViewById(R.id.check_circle)
1010 .setVisibility(isApplied ? View.VISIBLE : View.GONE);
1011 } else {
1012 // Item is not visible, make sure the item is re-bound when it becomes visible.
1013 mAdapter.notifyItemChanged(index);
1014 }
1015 }
1016
Chuck Liao11f4a762020-04-08 13:24:43 +08001017 private void refreshAppliedWallpaper() {
1018 // Clear the check mark and blue border(if it shows) of the old applied wallpaper.
1019 showCheckMarkAndBorderForAppliedWallpaper(false);
1020
1021 // Update to the new applied wallpaper.
1022 String appliedWallpaperId = getAppliedWallpaperId();
1023 Optional<WallpaperInfo> wallpaperInfoOptional = mWallpapers
1024 .stream()
1025 .filter(wallpaper -> wallpaper.getWallpaperId() != null)
1026 .filter(wallpaper -> wallpaper.getWallpaperId().equals(appliedWallpaperId))
1027 .findFirst();
1028 mAppliedWallpaperInfo = wallpaperInfoOptional.orElse(null);
1029
1030 // Set the check mark and blue border(if user doesn't select) of the new applied wallpaper.
1031 showCheckMarkAndBorderForAppliedWallpaper(true);
1032 }
1033
1034 private String getAppliedWallpaperId() {
1035 WallpaperPreferences prefs =
1036 InjectorProvider.getInjector().getPreferences(getContext());
1037 android.app.WallpaperInfo wallpaperInfo = mWallpaperManager.getWallpaperInfo();
1038 boolean isDestinationBoth =
1039 mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK) < 0;
1040
1041 if (isDestinationBoth || mWallpaperDestination == WallpaperPersister.DEST_HOME_SCREEN) {
1042 return wallpaperInfo != null
1043 ? wallpaperInfo.getServiceName() : prefs.getHomeWallpaperRemoteId();
1044 } else {
1045 return prefs.getLockWallpaperRemoteId();
1046 }
1047 }
1048
1049 private void showCheckMarkAndBorderForAppliedWallpaper(boolean show) {
1050 updateAppliedStatus(mAppliedWallpaperInfo, show);
1051 if (mSelectedWallpaperInfo == null) {
1052 updateActivatedStatus(mAppliedWallpaperInfo, show);
1053 }
1054 }
1055
Chuck Liao5a4243b2020-05-20 23:56:39 +08001056 private boolean shouldShowRotationTile() {
1057 return mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP && isRotationEnabled();
Jon Miranda16ea1b12017-12-12 14:52:48 -08001058 }
1059
1060 /**
1061 * RecyclerView Adapter subclass for the wallpaper tiles in the RecyclerView.
1062 */
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001063 class IndividualAdapter extends RecyclerView.Adapter<ViewHolder> {
1064 static final int ITEM_VIEW_TYPE_ROTATION = 1;
1065 static final int ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER = 2;
1066 static final int ITEM_VIEW_TYPE_MY_PHOTOS = 3;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001067
1068 private final List<WallpaperInfo> mWallpapers;
1069
1070 private int mPendingSelectedAdapterPosition;
1071 private int mSelectedAdapterPosition;
1072
1073 IndividualAdapter(List<WallpaperInfo> wallpapers) {
1074 mWallpapers = wallpapers;
1075 mPendingSelectedAdapterPosition = -1;
1076 mSelectedAdapterPosition = -1;
1077 }
1078
1079 @Override
1080 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
1081 switch (viewType) {
1082 case ITEM_VIEW_TYPE_ROTATION:
1083 return createRotationHolder(parent);
1084 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1085 return createIndividualHolder(parent);
1086 case ITEM_VIEW_TYPE_MY_PHOTOS:
1087 return createMyPhotosHolder(parent);
1088 default:
1089 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1090 return null;
1091 }
1092 }
1093
1094 @Override
1095 public int getItemViewType(int position) {
Chuck Liao5a4243b2020-05-20 23:56:39 +08001096 if (shouldShowRotationTile() && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001097 return ITEM_VIEW_TYPE_ROTATION;
1098 }
1099
1100 // A category cannot have both a "start rotation" tile and a "my photos" tile.
1101 if (mCategory.supportsCustomPhotos()
1102 && !isRotationEnabled()
1103 && position == SPECIAL_FIXED_TILE_ADAPTER_POSITION) {
1104 return ITEM_VIEW_TYPE_MY_PHOTOS;
1105 }
1106
1107 return ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER;
1108 }
1109
1110 @Override
1111 public void onBindViewHolder(ViewHolder holder, int position) {
1112 int viewType = getItemViewType(position);
1113
1114 switch (viewType) {
1115 case ITEM_VIEW_TYPE_ROTATION:
1116 onBindRotationHolder(holder, position);
1117 break;
1118 case ITEM_VIEW_TYPE_INDIVIDUAL_WALLPAPER:
1119 onBindIndividualHolder(holder, position);
1120 break;
1121 case ITEM_VIEW_TYPE_MY_PHOTOS:
1122 ((MyPhotosViewHolder) holder).bind();
1123 break;
1124 default:
1125 Log.e(TAG, "Unsupported viewType " + viewType + " in IndividualAdapter");
1126 }
1127 }
1128
1129 @Override
1130 public int getItemCount() {
Chuck Liao5a4243b2020-05-20 23:56:39 +08001131 return (shouldShowRotationTile() || mCategory.supportsCustomPhotos())
Jon Miranda16ea1b12017-12-12 14:52:48 -08001132 ? mWallpapers.size() + 1
1133 : mWallpapers.size();
1134 }
1135
1136 private ViewHolder createRotationHolder(ViewGroup parent) {
1137 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
Chuck Liao5a4243b2020-05-20 23:56:39 +08001138 View view = layoutInflater.inflate(R.layout.grid_item_rotation_desktop, parent, false);
1139 SelectionAnimator selectionAnimator =
1140 new CheckmarkSelectionAnimator(getActivity(), view);
1141 return new DesktopRotationHolder(getActivity(), mTileSizePx.y, view, selectionAnimator,
1142 IndividualPickerFragment.this);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001143 }
1144
1145 private ViewHolder createIndividualHolder(ViewGroup parent) {
1146 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1147 View view = layoutInflater.inflate(R.layout.grid_item_image, parent, false);
1148
1149 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1150 SelectionAnimator selectionAnimator =
1151 new CheckmarkSelectionAnimator(getActivity(), view);
1152 return new SetIndividualHolder(
1153 getActivity(), mTileSizePx.y, view,
1154 selectionAnimator,
1155 new OnSetListener() {
1156 @Override
1157 public void onPendingWallpaperSet(int adapterPosition) {
1158 // Deselect and hide loading indicator for any previously pending tile.
1159 if (mPendingSelectedAdapterPosition != -1) {
1160 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1161 mPendingSelectedAdapterPosition);
1162 if (oldViewHolder instanceof SelectableHolder) {
1163 ((SelectableHolder) oldViewHolder).setSelectionState(
1164 SelectableHolder.SELECTION_STATE_DESELECTED);
1165 }
1166 }
1167
1168 if (mSelectedAdapterPosition != -1) {
1169 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1170 mSelectedAdapterPosition);
1171 if (oldViewHolder instanceof SelectableHolder) {
1172 ((SelectableHolder) oldViewHolder).setSelectionState(
1173 SelectableHolder.SELECTION_STATE_DESELECTED);
1174 }
1175 }
1176
1177 mPendingSelectedAdapterPosition = adapterPosition;
1178 }
1179
1180 @Override
1181 public void onWallpaperSet(int adapterPosition) {
1182 // No-op -- UI handles a new wallpaper being set by reacting to the
1183 // WallpaperChangedNotifier.
1184 }
1185
1186 @Override
1187 public void onWallpaperSetFailed(SetIndividualHolder holder) {
1188 showSetWallpaperErrorDialog();
1189 mPendingSetIndividualHolder = holder;
1190 }
1191 });
1192 } else { // MOBILE
Chuck Liao3d1a51c2020-02-17 18:29:34 +08001193 return new PreviewIndividualHolder(getActivity(), mTileSizePx.y, view);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001194 }
1195 }
1196
1197 private ViewHolder createMyPhotosHolder(ViewGroup parent) {
1198 LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
1199 View view = layoutInflater.inflate(R.layout.grid_item_my_photos, parent, false);
1200
Santiago Etchebeherefab49612019-01-15 12:22:42 -08001201 return new MyPhotosViewHolder(getActivity(),
1202 ((MyPhotosStarterProvider) getActivity()).getMyPhotosStarter(),
1203 mTileSizePx.y, view);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001204 }
1205
1206 /**
1207 * Marks the tile at the given position as selected with a visual indication. Also updates the
1208 * "currently selected" BottomSheet to reflect the newly selected tile.
1209 */
1210 private void updateSelectedTile(int newlySelectedPosition) {
1211 // Prevent multiple spinners from appearing with a user tapping several tiles in rapid
1212 // succession.
1213 if (mPendingSelectedAdapterPosition == mSelectedAdapterPosition) {
1214 return;
1215 }
1216
1217 if (mCurrentWallpaperBottomSheetPresenter != null) {
1218 mCurrentWallpaperBottomSheetPresenter.refreshCurrentWallpapers(
1219 IndividualPickerFragment.this);
1220
1221 if (mCurrentWallpaperBottomSheetExpandedRunnable != null) {
1222 mHandler.removeCallbacks(mCurrentWallpaperBottomSheetExpandedRunnable);
1223 }
1224 mCurrentWallpaperBottomSheetExpandedRunnable = new Runnable() {
1225 @Override
1226 public void run() {
1227 mCurrentWallpaperBottomSheetPresenter.setCurrentWallpapersExpanded(true);
1228 }
1229 };
1230 mHandler.postDelayed(mCurrentWallpaperBottomSheetExpandedRunnable, 100);
1231 }
1232
1233 // User may have switched to another category, thus detaching this fragment, so check here.
1234 // NOTE: We do this check after updating the current wallpaper BottomSheet so that the update
1235 // still occurs in the UI after the user selects that other category.
1236 if (getActivity() == null) {
1237 return;
1238 }
1239
1240 // Update the newly selected wallpaper ViewHolder and the old one so that if
1241 // selection UI state applies (desktop UI), it is updated.
1242 if (mSelectedAdapterPosition >= 0) {
1243 ViewHolder oldViewHolder = mImageGrid.findViewHolderForAdapterPosition(
1244 mSelectedAdapterPosition);
1245 if (oldViewHolder instanceof SelectableHolder) {
1246 ((SelectableHolder) oldViewHolder).setSelectionState(
1247 SelectableHolder.SELECTION_STATE_DESELECTED);
1248 }
1249 }
1250
1251 // Animate selection of newly selected tile.
1252 ViewHolder newViewHolder = mImageGrid
1253 .findViewHolderForAdapterPosition(newlySelectedPosition);
1254 if (newViewHolder instanceof SelectableHolder) {
1255 ((SelectableHolder) newViewHolder).setSelectionState(
1256 SelectableHolder.SELECTION_STATE_SELECTED);
1257 }
1258
1259 mSelectedAdapterPosition = newlySelectedPosition;
1260
1261 // If the tile was in the last row of the grid, add space below it so the user can scroll down
1262 // and up to see the BottomSheet without it fully overlapping the newly selected tile.
1263 int spanCount = ((GridLayoutManager) mImageGrid.getLayoutManager()).getSpanCount();
1264 int numRows = (int) Math.ceil((float) getItemCount() / spanCount);
1265 int rowOfNewlySelectedTile = newlySelectedPosition / spanCount;
1266 boolean isInLastRow = rowOfNewlySelectedTile == numRows - 1;
1267
1268 updateImageGridPadding(isInLastRow /* addExtraBottomSpace */);
1269 }
1270
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001271 void onBindRotationHolder(ViewHolder holder, int position) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001272 if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
1273 String collectionId = mCategory.getCollectionId();
1274 ((DesktopRotationHolder) holder).bind(collectionId);
1275
1276 if (mWallpaperPreferences.getWallpaperPresentationMode()
1277 == WallpaperPreferences.PRESENTATION_MODE_ROTATING
1278 && collectionId.equals(mWallpaperPreferences.getHomeWallpaperCollectionId())) {
1279 mSelectedAdapterPosition = position;
1280 }
1281
1282 if (!mWasUpdateRunnableRun && !mWallpapers.isEmpty()) {
1283 updateDesktopDailyRotationThumbnail((DesktopRotationHolder) holder);
1284 mWasUpdateRunnableRun = true;
1285 }
1286 }
1287 }
1288
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +08001289 void onBindIndividualHolder(ViewHolder holder, int position) {
Chuck Liao5a4243b2020-05-20 23:56:39 +08001290 int wallpaperIndex = (shouldShowRotationTile() || mCategory.supportsCustomPhotos())
Jon Miranda16ea1b12017-12-12 14:52:48 -08001291 ? position - 1 : position;
1292 WallpaperInfo wallpaper = mWallpapers.get(wallpaperIndex);
1293 ((IndividualHolder) holder).bindWallpaper(wallpaper);
“Chuck7ef99722020-03-22 04:34:03 +08001294 String appliedWallpaperId = getAppliedWallpaperId();
“Chuckffd832c2020-03-22 02:15:58 +08001295 boolean isWallpaperApplied = wallpaper.getWallpaperId().equals(appliedWallpaperId);
1296 boolean isWallpaperSelected = wallpaper.equals(mSelectedWallpaperInfo);
1297 boolean hasUserSelectedWallpaper = mSelectedWallpaperInfo != null;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001298
“Chuckffd832c2020-03-22 02:15:58 +08001299 if (isWallpaperApplied) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001300 mSelectedAdapterPosition = position;
“Chuckffd832c2020-03-22 02:15:58 +08001301 mAppliedWallpaperInfo = wallpaper;
Jon Miranda16ea1b12017-12-12 14:52:48 -08001302 }
Chuck Liaof40063f2020-03-03 18:35:24 +08001303
Chuck Liao342f4ab2020-05-26 18:28:09 +08001304 holder.itemView.setActivated(
1305 (isWallpaperApplied && !hasUserSelectedWallpaper) || isWallpaperSelected);
1306 holder.itemView.findViewById(R.id.check_circle).setVisibility(
1307 isWallpaperApplied ? View.VISIBLE : View.GONE);
Jon Miranda16ea1b12017-12-12 14:52:48 -08001308 }
1309 }
Chuck Liaoba401232020-03-13 20:11:04 +08001310
1311 private class GridPaddingDecoration extends RecyclerView.ItemDecoration {
1312
1313 private int mPadding;
1314
1315 GridPaddingDecoration(int padding) {
1316 mPadding = padding;
1317 }
1318
1319 @Override
1320 public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
1321 RecyclerView.State state) {
1322 int position = parent.getChildAdapterPosition(view);
1323 if (position >= 0) {
1324 outRect.left = mPadding;
1325 outRect.right = mPadding;
1326 }
1327 }
1328 }
Jon Miranda16ea1b12017-12-12 14:52:48 -08001329}