blob: 1d0d8f054cc82902db93a06b4b194c423143d40c [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;
17
Jon Miranda16ea1b12017-12-12 14:52:48 -080018import android.app.Activity;
19import android.app.ProgressDialog;
Jon Miranda16ea1b12017-12-12 14:52:48 -080020import android.content.Context;
21import android.content.Intent;
Jon Miranda16ea1b12017-12-12 14:52:48 -080022import android.graphics.Color;
Santiago Etchebehere35891ea2019-07-26 15:21:42 -070023import android.graphics.Insets;
Jon Miranda16ea1b12017-12-12 14:52:48 -080024import android.graphics.Point;
25import android.graphics.PorterDuff.Mode;
26import android.graphics.drawable.Drawable;
27import android.net.Uri;
28import android.os.AsyncTask;
29import android.os.Build.VERSION;
30import android.os.Build.VERSION_CODES;
31import android.os.Bundle;
Hyunyoung Song8077c862019-06-18 01:14:24 -040032import android.provider.Settings;
Jon Miranda16ea1b12017-12-12 14:52:48 -080033import android.util.Log;
34import android.view.View;
35import android.view.View.OnClickListener;
Santiago Etchebehere35891ea2019-07-26 15:21:42 -070036import android.view.WindowInsets;
Jon Miranda16ea1b12017-12-12 14:52:48 -080037import android.widget.Button;
38import android.widget.FrameLayout;
39import android.widget.ImageView;
40import android.widget.LinearLayout;
41import android.widget.TextView;
42
Santiago Etchebehere635e96f2018-12-04 18:31:34 -080043import androidx.annotation.NonNull;
44import androidx.annotation.Nullable;
45import androidx.appcompat.app.AlertDialog;
46import androidx.appcompat.widget.Toolbar;
47import androidx.fragment.app.Fragment;
48import androidx.fragment.app.FragmentManager;
49
Jon Miranda16ea1b12017-12-12 14:52:48 -080050import com.android.wallpaper.R;
51import com.android.wallpaper.asset.Asset;
Santiago Etchebehere35891ea2019-07-26 15:21:42 -070052import com.android.wallpaper.compat.BuildCompat;
Jon Miranda16ea1b12017-12-12 14:52:48 -080053import com.android.wallpaper.compat.ButtonDrawableSetterCompat;
Jon Miranda16ea1b12017-12-12 14:52:48 -080054import com.android.wallpaper.config.Flags;
55import com.android.wallpaper.model.Category;
Jon Miranda16ea1b12017-12-12 14:52:48 -080056import com.android.wallpaper.model.ImageWallpaperInfo;
Jon Miranda16ea1b12017-12-12 14:52:48 -080057import com.android.wallpaper.model.WallpaperInfo;
58import com.android.wallpaper.module.CurrentWallpaperInfoFactory;
59import com.android.wallpaper.module.CurrentWallpaperInfoFactory.WallpaperInfoCallback;
60import com.android.wallpaper.module.DailyLoggingAlarmScheduler;
61import com.android.wallpaper.module.ExploreIntentChecker;
62import com.android.wallpaper.module.FormFactorChecker;
Jon Miranda16ea1b12017-12-12 14:52:48 -080063import com.android.wallpaper.module.Injector;
64import com.android.wallpaper.module.InjectorProvider;
65import com.android.wallpaper.module.NetworkStatusNotifier;
66import com.android.wallpaper.module.NetworkStatusNotifier.NetworkStatus;
67import com.android.wallpaper.module.UserEventLogger;
68import com.android.wallpaper.module.UserEventLogger.WallpaperSetFailureReason;
69import com.android.wallpaper.module.WallpaperPersister;
70import com.android.wallpaper.module.WallpaperPersister.Destination;
71import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback;
72import com.android.wallpaper.module.WallpaperPersister.WallpaperPosition;
73import com.android.wallpaper.module.WallpaperPreferences;
74import com.android.wallpaper.module.WallpaperPreferences.PresentationMode;
75import com.android.wallpaper.module.WallpaperRotationRefresher;
76import com.android.wallpaper.module.WallpaperRotationRefresher.Listener;
Santiago Etchebehere635e96f2018-12-04 18:31:34 -080077import com.android.wallpaper.picker.CategoryFragment.CategoryFragmentHost;
Jon Miranda16ea1b12017-12-12 14:52:48 -080078import com.android.wallpaper.picker.WallpaperDisabledFragment.WallpaperSupportLevel;
Jon Miranda16ea1b12017-12-12 14:52:48 -080079import com.android.wallpaper.picker.individual.IndividualPickerFragment;
80import com.android.wallpaper.util.ScreenSizeCalculator;
81import com.android.wallpaper.util.ThrowableAnalyzer;
82
Sunny Goyal8600a3f2018-08-15 12:48:01 -070083import com.google.android.material.bottomsheet.BottomSheetBehavior;
84import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback;
85import com.google.android.material.tabs.TabLayout;
86import com.google.android.material.tabs.TabLayout.OnTabSelectedListener;
87import com.google.android.material.tabs.TabLayout.Tab;
88
Jon Miranda16ea1b12017-12-12 14:52:48 -080089import java.util.List;
90
91/**
92 * Activity allowing users to select a category of wallpapers to choose from.
93 */
94public class TopLevelPickerActivity extends BaseActivity implements WallpapersUiContainer,
95 CurrentWallpaperBottomSheetPresenter, SetWallpaperErrorDialogFragment.Listener,
Santiago Etchebeherefab49612019-01-15 12:22:42 -080096 MyPhotosStarter, CategoryFragmentHost {
Jon Miranda16ea1b12017-12-12 14:52:48 -080097
98 private static final String TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT =
99 "toplevel_set_wallpaper_error_dialog";
100
101 private static final String TAG = "TopLevelPicker";
102 private static final String KEY_SELECTED_CATEGORY_TAB = "selected_category_tab";
103
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800104 private WallpaperPickerDelegate mDelegate;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800105 private int mLastSelectedCategoryTabIndex;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800106 private UserEventLogger mUserEventLogger;
107 private NetworkStatusNotifier mNetworkStatusNotifier;
108 private NetworkStatusNotifier.Listener mNetworkStatusListener;
109 private WallpaperPersister mWallpaperPersister;
110 private boolean mWasCustomPhotoWallpaperSet;
111 @WallpaperPosition
112 private int mCustomPhotoWallpaperPosition;
113
114 /**
115 * Progress dialogs for "refresh daily wallpaper" and "set wallpaper" operations.
116 */
117 private ProgressDialog mRefreshWallpaperProgressDialog;
118 private ProgressDialog mSetWallpaperProgressDialog;
119
120 /**
121 * Designates a test mode of operation -- in which certain UI features are disabled to allow for
122 * UI tests to run correctly.
123 */
124 private boolean mTestingMode;
125
126 /**
127 * UI for the "currently set wallpaper" BottomSheet.
128 */
129 private LinearLayout mBottomSheet;
130 private ImageView mCurrentWallpaperImage;
131 private TextView mCurrentWallpaperPresentationMode;
132 private TextView mCurrentWallpaperTitle;
133 private TextView mCurrentWallpaperSubtitle;
134 private Button mCurrentWallpaperExploreButton;
135 private Button mCurrentWallpaperSkipWallpaperButton;
136 private FrameLayout mFragmentContainer;
137 private FrameLayout mLoadingIndicatorContainer;
138 private LinearLayout mWallpaperPositionOptions;
139
Jon Miranda16ea1b12017-12-12 14:52:48 -0800140 /**
141 * Staged error dialog fragments that were unable to be shown when the activity didn't allow
142 * committing fragment transactions.
143 */
144 private SetWallpaperErrorDialogFragment mStagedSetWallpaperErrorDialogFragment;
145
146 /**
147 * A wallpaper pending set to the device--we retain a reference to this in order to facilitate
148 * retry or re-crop operations.
149 */
150 private WallpaperInfo mPendingSetWallpaperInfo;
151
152 private static int getTextColorIdForWallpaperPositionButton(boolean isSelected) {
153 return isSelected ? R.color.accent_color : R.color.material_grey500;
154 }
155
156 @Override
157 protected void onCreate(Bundle savedInstanceState) {
158 super.onCreate(savedInstanceState);
159
Jon Miranda16ea1b12017-12-12 14:52:48 -0800160 mLastSelectedCategoryTabIndex = -1;
161
162 Injector injector = InjectorProvider.getInjector();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800163 mDelegate = new WallpaperPickerDelegate(this, this, injector);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800164 mUserEventLogger = injector.getUserEventLogger(this);
165 mNetworkStatusNotifier = injector.getNetworkStatusNotifier(this);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800166 mWallpaperPersister = injector.getWallpaperPersister(this);
167 mWasCustomPhotoWallpaperSet = false;
168
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800169 @WallpaperSupportLevel int wallpaperSupportLevel = mDelegate.getWallpaperSupportLevel();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800170 if (wallpaperSupportLevel != WallpaperDisabledFragment.SUPPORTED_CAN_SET) {
Chuck Liao8ec38e02020-02-26 20:59:32 +0800171 setContentView(R.layout.activity_top_level_picker);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800172
173 FragmentManager fm = getSupportFragmentManager();
174 WallpaperDisabledFragment wallpaperDisabledFragment =
175 WallpaperDisabledFragment.newInstance(wallpaperSupportLevel);
176 fm.beginTransaction()
177 .add(R.id.fragment_container, wallpaperDisabledFragment)
178 .commit();
179 return;
180 }
181
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800182 if (mDelegate.getFormFactor() == FormFactorChecker.FORM_FACTOR_MOBILE) {
Ching-Sung Li5f689972019-05-20 17:16:57 +0800183 initializeMobile(true /* shouldForceRefresh */);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800184 } else { // DESKTOP
185 initializeDesktop(savedInstanceState);
186 }
187 }
188
189 @Override
190 protected void onResume() {
191 super.onResume();
Hyunyoung Song8077c862019-06-18 01:14:24 -0400192 boolean provisioned = Settings.Global.getInt(getContentResolver(),
193 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
194
195 mUserEventLogger.logResumed(provisioned, true);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800196 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one
197 // that was unable to be shown earlier when this fragment's hosting activity didn't allow
198 // committing fragment transactions.
199 if (mStagedSetWallpaperErrorDialogFragment != null) {
200 mStagedSetWallpaperErrorDialogFragment.show(
201 getSupportFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
202 mStagedSetWallpaperErrorDialogFragment = null;
203 }
204 }
205
206 @Override
Santiago Etchebeherebd536c62019-04-09 15:25:51 -0300207 protected void onStop() {
208 mUserEventLogger.logStopped();
209 super.onStop();
210 }
211
212 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800213 protected void onDestroy() {
214 super.onDestroy();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800215 mDelegate.cleanUp();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800216 if (mNetworkStatusListener != null) {
217 mNetworkStatusNotifier.unregisterListener(mNetworkStatusListener);
218 }
219
220 if (mRefreshWallpaperProgressDialog != null) {
221 mRefreshWallpaperProgressDialog.dismiss();
222 }
223 if (mSetWallpaperProgressDialog != null) {
224 mSetWallpaperProgressDialog.dismiss();
225 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800226 }
227
228 @Override
Chuck Liaob1f1a3a2020-02-17 19:46:14 +0800229 public void onBackPressed() {
230 CategoryFragment categoryFragment = getCategoryFragment();
231 if (categoryFragment != null && categoryFragment.popChildFragment()) {
232 return;
233 }
234 super.onBackPressed();
235 }
236
237 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800238 public void requestCustomPhotoPicker(PermissionChangedListener listener) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800239 mDelegate.requestCustomPhotoPicker(listener);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800240 }
241
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800242 @Override
243 public void requestExternalStoragePermission(PermissionChangedListener listener) {
244 mDelegate.requestExternalStoragePermission(listener);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800245 }
246
247 /**
248 * Returns whether READ_EXTERNAL_STORAGE has been granted for the application.
249 */
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800250 public boolean isReadExternalStoragePermissionGranted() {
251 return mDelegate.isReadExternalStoragePermissionGranted();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800252 }
253
Ching-Sung Li5f689972019-05-20 17:16:57 +0800254 private void initializeMobile(boolean shouldForceRefresh) {
Chuck Liao8ec38e02020-02-26 20:59:32 +0800255 setContentView(R.layout.activity_top_level_picker);
Santiago Etchebehere35891ea2019-07-26 15:21:42 -0700256 getWindow().getDecorView().setSystemUiVisibility(
257 getWindow().getDecorView().getSystemUiVisibility()
258 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
259 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
260 findViewById(R.id.fragment_container)
261 .setOnApplyWindowInsetsListener((view, windowInsets) -> {
262 view.setPadding(view.getPaddingLeft(), windowInsets.getSystemWindowInsetTop(),
Chuck Liaoe9d79812020-02-20 18:03:55 +0800263 view.getPaddingRight(), view.getPaddingBottom());
Santiago Etchebehere35891ea2019-07-26 15:21:42 -0700264 // Consume only the top inset (status bar), to let other content in the Activity consume
265 // the nav bar (ie, by using "fitSystemWindows")
266 if (BuildCompat.isAtLeastQ()) {
267 WindowInsets.Builder builder = new WindowInsets.Builder(windowInsets);
268 builder.setSystemWindowInsets(Insets.of(windowInsets.getSystemWindowInsetLeft(),
269 0, windowInsets.getStableInsetRight(),
270 windowInsets.getSystemWindowInsetBottom()));
271 return builder.build();
272 } else {
273 return windowInsets.replaceSystemWindowInsets(
274 windowInsets.getSystemWindowInsetLeft(),
275 0, windowInsets.getStableInsetRight(),
276 windowInsets.getSystemWindowInsetBottom());
277 }
278 });
Jon Miranda16ea1b12017-12-12 14:52:48 -0800279
280 // Set toolbar as the action bar.
281 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
282 setSupportActionBar(toolbar);
283
284 FragmentManager fm = getSupportFragmentManager();
285 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
286
Jon Miranda16ea1b12017-12-12 14:52:48 -0800287 if (fragment == null) {
288 // App launch specific logic: log the "app launched" event and set up daily logging.
289 mUserEventLogger.logAppLaunched();
290 DailyLoggingAlarmScheduler.setAlarm(getApplicationContext());
291
Santiago Etchebehereaa35e6e2019-01-25 10:30:11 -0800292 CategoryFragment newFragment = CategoryFragment.newInstance(
293 getString(R.string.wallpaper_app_name));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800294 fm.beginTransaction()
295 .add(R.id.fragment_container, newFragment)
296 .commit();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800297 }
298
Ching-Sung Li5f689972019-05-20 17:16:57 +0800299 mDelegate.initialize(shouldForceRefresh);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800300 }
301
302 private void initializeDesktop(Bundle savedInstanceState) {
303 setContentView(R.layout.activity_top_level_desktop);
304
305 mBottomSheet = (LinearLayout) findViewById(R.id.bottom_sheet);
306 mCurrentWallpaperImage = (ImageView) mBottomSheet.findViewById(R.id.current_wallpaper_image);
307 mCurrentWallpaperImage.getLayoutParams().width = getSingleWallpaperImageWidthPx();
308
309 mCurrentWallpaperPresentationMode =
310 (TextView) mBottomSheet.findViewById(R.id.current_wallpaper_presentation_mode);
311 mCurrentWallpaperTitle = (TextView) findViewById(R.id.current_wallpaper_title);
312 mCurrentWallpaperSubtitle = (TextView) findViewById(R.id.current_wallpaper_subtitle);
313 mCurrentWallpaperExploreButton = (Button) findViewById(
314 R.id.current_wallpaper_explore_button);
315 mCurrentWallpaperSkipWallpaperButton = (Button) findViewById(
316 R.id.current_wallpaper_skip_wallpaper_button);
317 mFragmentContainer = (FrameLayout) findViewById(R.id.fragment_container);
318 mLoadingIndicatorContainer = (FrameLayout) findViewById(R.id.loading_indicator_container);
319 mWallpaperPositionOptions = (LinearLayout) findViewById(
320 R.id.desktop_wallpaper_position_options);
321
322 final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
323 tabLayout.addOnTabSelectedListener(new OnTabSelectedListener() {
324 @Override
325 public void onTabSelected(Tab tab) {
326 Category category = (Category) tab.getTag();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800327 showCategoryDesktop(category.getCollectionId());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800328 mLastSelectedCategoryTabIndex = tabLayout.getSelectedTabPosition();
329 }
330
331 @Override
332 public void onTabUnselected(Tab tab) {
333 }
334
335 @Override
336 public void onTabReselected(Tab tab) {
337 Category category = (Category) tab.getTag();
338 // If offline, "My photos" may be the only visible category. In this case we want to allow
339 // re-selection so user can still select a photo as wallpaper while offline.
340 if (!category.isEnumerable()) {
341 onTabSelected(tab);
342 }
343 }
344 });
345
346 FragmentManager fm = getSupportFragmentManager();
347 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
348
349 if (fragment == null) {
350 // App launch specific logic: log the "app launched" event and set up daily logging.
351 mUserEventLogger.logAppLaunched();
352 DailyLoggingAlarmScheduler.setAlarm(getApplicationContext());
353 }
354
355 mNetworkStatusListener = new NetworkStatusNotifier.Listener() {
356 @Override
357 public void onNetworkChanged(@NetworkStatus int networkStatus) {
358 initializeDesktopBasedOnNetwork(networkStatus, savedInstanceState);
359 }
360 };
361 // Upon registering a listener, the onNetworkChanged method is immediately called with the
362 // initial network status.
363 mNetworkStatusNotifier.registerListener(mNetworkStatusListener);
364 }
365
366 private void initializeDesktopBasedOnNetwork(@NetworkStatus int networkStatus,
367 Bundle savedInstanceState) {
368 if (networkStatus == NetworkStatusNotifier.NETWORK_CONNECTED) {
369 initializeDesktopOnline(savedInstanceState);
370 } else {
371 initializeDesktopOffline();
372 }
373 }
374
375 private void initializeDesktopOnline(Bundle savedInstanceState) {
376 FragmentManager fm = getSupportFragmentManager();
377 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
378
379 // Require a category refresh if this is the first load of the app or if the app is now
380 // returning online after having been offline.
381 boolean forceCategoryRefresh = fragment == null || fragment instanceof OfflineDesktopFragment;
382
383 if (fragment != null) {
384 fm.beginTransaction()
385 .remove(fragment)
386 .commit();
387 }
388
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800389 mLastSelectedCategoryTabIndex = savedInstanceState != null
Jon Miranda16ea1b12017-12-12 14:52:48 -0800390 ? savedInstanceState.getInt(KEY_SELECTED_CATEGORY_TAB) : -1;
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800391 mDelegate.populateCategories(forceCategoryRefresh);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800392
393 setDesktopLoading(true);
394 setUpBottomSheet();
395 refreshCurrentWallpapers(null /* refreshListener */);
396 }
397
398 private void initializeDesktopOffline() {
399 FragmentManager fm = getSupportFragmentManager();
400 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
401
402 if (fragment != null) {
403 fm.beginTransaction()
404 .remove(fragment)
405 .commit();
406 }
407 OfflineDesktopFragment newFragment = new OfflineDesktopFragment();
408 fm.beginTransaction()
409 .add(R.id.fragment_container, newFragment)
410 .commit();
411
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800412 // Reset the last selected category tab index to ensure the app doesn't try to reselect a
413 // tab for a category not yet repopulated.
Jon Miranda16ea1b12017-12-12 14:52:48 -0800414 mLastSelectedCategoryTabIndex = -1;
415
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800416 mDelegate.populateCategories(true /* forceCategoryRefresh */);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800417
418 setDesktopLoading(false);
419 setCurrentWallpapersExpanded(false);
420 }
421
422 /**
423 * Sets the status of the loading indicator overlay in desktop mode.
424 *
425 * @param loading Whether an indeterminate loading indicator is displayed in place of the main
426 * fragment.
427 */
428 private void setDesktopLoading(boolean loading) {
429 if (loading) {
430 mLoadingIndicatorContainer.setVisibility(View.VISIBLE);
431 mFragmentContainer.setVisibility(View.GONE);
432 } else {
433 mLoadingIndicatorContainer.setVisibility(View.GONE);
434 mFragmentContainer.setVisibility(View.VISIBLE);
435 }
436 }
437
438 /**
439 * Returns the width (in physical px) to use for the "currently set wallpaper" thumbnail.
440 */
441 private int getSingleWallpaperImageWidthPx() {
442 Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(
443 getWindowManager().getDefaultDisplay());
444
445 int height = getResources().getDimensionPixelSize(
446 R.dimen.current_wallpaper_bottom_sheet_thumb_height);
447 return height * screenSize.x / screenSize.y;
448 }
449
450 /**
451 * Enables and populates the "Currently set" wallpaper BottomSheet.
452 */
453 private void setUpBottomSheet() {
454 mBottomSheet.setVisibility(View.VISIBLE);
455
Jon Miranda16ea1b12017-12-12 14:52:48 -0800456 if (Flags.skipDailyWallpaperButtonEnabled) {
457 // Add "next" icon to the Next Wallpaper button
458 Drawable nextWallpaperButtonDrawable = getResources().getDrawable(
Santiago Etchebehered24506c2018-04-05 17:02:42 -0700459 R.drawable.ic_refresh_18px);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800460
461 // This Drawable's state is shared across the app, so make a copy of it before applying a
462 // color tint as not to affect other clients elsewhere in the app.
463 nextWallpaperButtonDrawable =
464 nextWallpaperButtonDrawable.getConstantState().newDrawable().mutate();
465 // Color the "compass" icon with the accent color.
466 nextWallpaperButtonDrawable.setColorFilter(
467 getResources().getColor(R.color.accent_color), Mode.SRC_IN);
468 ButtonDrawableSetterCompat.setDrawableToButtonStart(
469 mCurrentWallpaperSkipWallpaperButton, nextWallpaperButtonDrawable);
470 }
471
472 final BottomSheetBehavior<LinearLayout> bottomSheetBehavior =
473 BottomSheetBehavior.from(mBottomSheet);
474 bottomSheetBehavior.setBottomSheetCallback(new BottomSheetCallback() {
475 @Override
476 public void onStateChanged(@NonNull View view, int i) {
477 }
478
479 @Override
480 public void onSlide(@NonNull View view, float slideOffset) {
481 float alpha;
482 if (slideOffset >= 0) {
483 alpha = slideOffset;
484 } else {
485 alpha = 1f - slideOffset;
486 }
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800487 LinearLayout bottomSheetContents = findViewById(R.id.bottom_sheet_contents);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800488 bottomSheetContents.setAlpha(alpha);
489 }
490 });
491 }
492
493 /**
494 * Enables a test mode of operation -- in which certain UI features are disabled to allow for
495 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog
496 * constantly keeps the UI thread alive and blocks a test forever.
497 */
498 void setTestingMode(boolean testingMode) {
499 mTestingMode = testingMode;
500 }
501
502 /**
503 * Obtains the {@link WallpaperInfo} object(s) representing the wallpaper(s) currently set to the
504 * device from the {@link CurrentWallpaperInfoFactory} and displays them in the BottomSheet.
505 */
506 @Override
507 public void refreshCurrentWallpapers(@Nullable RefreshListener refreshListener) {
508 final Injector injector = InjectorProvider.getInjector();
509 final Context appContext = getApplicationContext();
510
511 CurrentWallpaperInfoFactory factory = injector.getCurrentWallpaperFactory(this);
512 factory.createCurrentWallpaperInfos(new WallpaperInfoCallback() {
513 @Override
514 public void onWallpaperInfoCreated(
515 final WallpaperInfo homeWallpaper,
516 @Nullable final WallpaperInfo lockWallpaper,
517 @PresentationMode final int presentationMode) {
518
519 if (isDestroyed()) {
520 return;
521 }
522
523 // Fetch the home wallpaper's thumbnail asset asynchronously to work around expensive
524 // method call to WallpaperManager#getWallpaperFile made from the CurrentWallpaperInfoVN
525 // getAsset() method.
526 AssetReceiver assetReceiver = (Asset thumbAsset) -> {
527 if (isDestroyed()) {
528 return;
529 }
530
531 homeWallpaper.getThumbAsset(appContext).loadDrawableWithTransition(
532 TopLevelPickerActivity.this,
533 mCurrentWallpaperImage,
534 200 /* transitionDurationMillis */,
535 () -> {
536 if (refreshListener != null) {
537 refreshListener.onCurrentWallpaperRefreshed();
538 }
539 },
540 Color.TRANSPARENT);
541 };
542 new FetchThumbAssetTask(appContext, homeWallpaper, assetReceiver).executeOnExecutor(
543 AsyncTask.THREAD_POOL_EXECUTOR);
544
545 mCurrentWallpaperPresentationMode.setText(
546 AttributionFormatter.getHumanReadableWallpaperPresentationMode(
547 TopLevelPickerActivity.this, presentationMode));
548
549 List<String> attributions = homeWallpaper.getAttributions(appContext);
550 if (attributions.size() > 0 && attributions.get(0) != null) {
551 mCurrentWallpaperTitle.setText(attributions.get(0));
552 }
553
554 mCurrentWallpaperSubtitle.setText(
555 AttributionFormatter.formatWallpaperSubtitle(appContext, homeWallpaper));
556
557 final String actionUrl = homeWallpaper.getActionUrl(appContext);
558 if (actionUrl != null && !actionUrl.isEmpty()) {
559 Uri exploreUri = Uri.parse(actionUrl);
560
561 ExploreIntentChecker intentChecker = injector.getExploreIntentChecker(appContext);
562 intentChecker.fetchValidActionViewIntent(exploreUri, (@Nullable Intent exploreIntent) -> {
563 if (exploreIntent != null && !isDestroyed()) {
Santiago Etchebehered1bd5092018-04-18 16:03:30 -0700564 // Set the icon for the button
565 Drawable exploreButtonDrawable = getResources().getDrawable(
Santiago Etchebeheree0810d02018-05-10 17:39:40 -0700566 homeWallpaper.getActionIconRes(appContext));
Santiago Etchebehered1bd5092018-04-18 16:03:30 -0700567
568 // This Drawable's state is shared across the app, so make a copy of it
569 // before applying a color tint as not to affect other clients elsewhere
570 // in the app.
571 exploreButtonDrawable = exploreButtonDrawable.getConstantState()
572 .newDrawable().mutate();
573 // Color the "compass" icon with the accent color.
574 exploreButtonDrawable.setColorFilter(
575 getResources().getColor(R.color.accent_color), Mode.SRC_IN);
576
577 ButtonDrawableSetterCompat.setDrawableToButtonStart(
578 mCurrentWallpaperExploreButton, exploreButtonDrawable);
579 mCurrentWallpaperExploreButton.setText(getString(
Santiago Etchebeheree0810d02018-05-10 17:39:40 -0700580 homeWallpaper.getActionLabelRes(appContext)));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800581 mCurrentWallpaperExploreButton.setVisibility(View.VISIBLE);
582 mCurrentWallpaperExploreButton.setOnClickListener(new OnClickListener() {
583 @Override
584 public void onClick(View v) {
Santiago Etchebeherece5613f2018-06-01 13:22:47 -0700585 mUserEventLogger.logActionClicked(
586 homeWallpaper.getCollectionId(appContext),
587 homeWallpaper.getActionLabelRes(appContext));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800588 startActivity(exploreIntent);
589 }
590 });
591 }
592 });
593 } else {
594 mCurrentWallpaperExploreButton.setVisibility(View.GONE);
595 }
596
597 // Hide the wallpaper position options UI if the current home wallpaper is not from
598 // "my photos".
599 String homeCollectionId = homeWallpaper.getCollectionId(TopLevelPickerActivity.this);
600 if (mWallpaperPositionOptions != null
601 && homeCollectionId != null // May be null if app is being used for the first time.
602 && !homeCollectionId.equals(getString(R.string.image_wallpaper_collection_id))) {
603 mWallpaperPositionOptions.setVisibility(View.GONE);
604 }
605
606 boolean showSkipWallpaperButton = Flags.skipDailyWallpaperButtonEnabled
607 && presentationMode == WallpaperPreferences.PRESENTATION_MODE_ROTATING;
608 if (showSkipWallpaperButton) {
609 mCurrentWallpaperSkipWallpaperButton.setVisibility(View.VISIBLE);
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800610 mCurrentWallpaperSkipWallpaperButton.setOnClickListener(
611 v -> refreshDailyWallpaper());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800612 } else {
613 mCurrentWallpaperSkipWallpaperButton.setVisibility(View.GONE);
614 }
615
616 if (refreshListener != null) {
617 refreshListener.onCurrentWallpaperRefreshed();
618 }
619 }
620 }, true /* forceRefresh */);
621 }
622
623 @Override
624 public void onSaveInstanceState(Bundle savedInstanceState) {
625 FormFactorChecker formFactorChecker = InjectorProvider.getInjector().getFormFactorChecker(this);
626 if (formFactorChecker.getFormFactor() == FormFactorChecker.FORM_FACTOR_DESKTOP) {
627 TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
628
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800629 // tabLayout is only present when the main IndividualPickerFragment is present (as
630 // opposed to
Jon Miranda16ea1b12017-12-12 14:52:48 -0800631 // the WallpaperDisabledFragment), so need this null check.
632 if (tabLayout != null) {
633 savedInstanceState.putInt(KEY_SELECTED_CATEGORY_TAB, tabLayout.getSelectedTabPosition());
634 }
635 }
636
637 super.onSaveInstanceState(savedInstanceState);
638 }
639
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800640 @Override
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700641 @Nullable
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800642 public CategoryFragment getCategoryFragment() {
643 if (mDelegate.getFormFactor() != FormFactorChecker.FORM_FACTOR_MOBILE) {
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700644 return null;
645 }
646 FragmentManager fm = getSupportFragmentManager();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800647 return (CategoryFragment) fm.findFragmentById(R.id.fragment_container);
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700648 }
649
Jon Miranda16ea1b12017-12-12 14:52:48 -0800650 /**
651 * Populates the category tabs on DESKTOP form factor.
652 *
653 * @param selectedTabPosition The position of the tab to show as selected, or -1 if no particular
654 * tab should be selected (in which case: the tab of the category for the currently set
655 * wallpaper will be selected if enumerable; if not, the first enumerable category's tab will
656 * be selected).
657 */
658 private void populateCategoryTabs(int selectedTabPosition) {
659 final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
660 tabLayout.removeAllTabs();
661
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800662 String currentlySetCollectionId = mDelegate.getPreferences().getHomeWallpaperCollectionId();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800663
664 Tab tabToSelect = null;
665 Tab firstEnumerableCategoryTab = null;
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800666 for (int i = 0; i < mDelegate.getCategoryProvider().getSize(); i++) {
667 Category category = mDelegate.getCategoryProvider().getCategory(i);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800668
669 Tab tab = tabLayout.newTab();
670 tab.setText(category.getTitle());
671 tab.setTag(category);
672 tabLayout.addTab(tab, false /* setSelected */);
673
674 if (firstEnumerableCategoryTab == null && category.isEnumerable()) {
675 firstEnumerableCategoryTab = tab;
676 }
677
678 boolean shouldSelectTab = (i == selectedTabPosition)
679 || (selectedTabPosition == -1
680 && tabToSelect == null
681 && category.isEnumerable()
682 && currentlySetCollectionId != null
683 && currentlySetCollectionId.equals(category.getCollectionId()));
684
685 if (shouldSelectTab) {
686 tabToSelect = tab;
687 }
688 }
689
690 // If the above loop did not identify a specific tab to select, then just select the tab for
691 // the first enumerable category.
692 if (tabToSelect == null) {
693 tabToSelect = firstEnumerableCategoryTab;
694 }
695
696 // There may be no enumerable tabs (e.g., offline case), so we need to null-check again.
697 if (tabToSelect != null) {
698 tabToSelect.select();
699 }
700 }
701
702 /**
703 * Refreshes the current wallpaper in a daily wallpaper rotation.
704 */
705 private void refreshDailyWallpaper() {
706 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
707 // causes Espresso to hang once the dialog is shown.
708 if (!mTestingMode) {
709 int themeResId;
710 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
711 themeResId = R.style.ProgressDialogThemePreL;
712 } else {
713 themeResId = R.style.LightDialogTheme;
714 }
715 mRefreshWallpaperProgressDialog = new ProgressDialog(this, themeResId);
716 mRefreshWallpaperProgressDialog.setTitle(null);
717 mRefreshWallpaperProgressDialog.setMessage(
718 getResources().getString(R.string.refreshing_daily_wallpaper_dialog_message));
719 mRefreshWallpaperProgressDialog.setIndeterminate(true);
720 mRefreshWallpaperProgressDialog.show();
721 }
722
723 WallpaperRotationRefresher wallpaperRotationRefresher =
724 InjectorProvider.getInjector().getWallpaperRotationRefresher();
725 wallpaperRotationRefresher.refreshWallpaper(this, new Listener() {
726 @Override
727 public void onRefreshed() {
728 if (isDestroyed()) {
729 return;
730 }
731
732 if (mRefreshWallpaperProgressDialog != null) {
733 mRefreshWallpaperProgressDialog.dismiss();
734 }
735
736 refreshCurrentWallpapers(null /* refreshListener */);
737 }
738
739 @Override
740 public void onError() {
741 if (mRefreshWallpaperProgressDialog != null) {
742 mRefreshWallpaperProgressDialog.dismiss();
743 }
744
745 AlertDialog errorDialog = new AlertDialog.Builder(
746 TopLevelPickerActivity.this, R.style.LightDialogTheme)
747 .setMessage(R.string.refresh_daily_wallpaper_failed_message)
748 .setPositiveButton(android.R.string.ok, null /* onClickListener */)
749 .create();
750 errorDialog.show();
751 }
752 });
753 }
754
755 @Override
756 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
757 super.onActivityResult(requestCode, resultCode, data);
758
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800759 if (requestCode == WallpaperPickerDelegate.SHOW_CATEGORY_REQUEST_CODE
760 && resultCode == Activity.RESULT_OK) {
Santiago Etchebeheree5e05842019-02-13 16:58:07 -0800761 if (mDelegate.getFormFactor() == FormFactorChecker.FORM_FACTOR_DESKTOP) {
762 Uri imageUri = (data == null) ? null : data.getData();
763 if (imageUri != null) {
764 // User selected an image from the system picker, so launch the preview for that
765 // image.
766 ImageWallpaperInfo imageWallpaper = new ImageWallpaperInfo(imageUri);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800767 setCustomPhotoWallpaper(imageWallpaper);
768 return;
769 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800770 }
Santiago Etchebeheree5e05842019-02-13 16:58:07 -0800771 }
772 if (mDelegate.handleActivityResult(requestCode, resultCode, data)) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800773 finishActivityWithResultOk();
774 }
775 }
776
777 /**
778 * Shows the view-only preview activity for the given wallpaper.
779 */
780 public void showViewOnlyPreview(WallpaperInfo wallpaperInfo) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800781 mDelegate.showViewOnlyPreview(wallpaperInfo);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800782 }
783
784 @Override
785 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
786 @NonNull int[] grantResults) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800787 mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800788 }
789
Jon Miranda16ea1b12017-12-12 14:52:48 -0800790 private void reselectLastTab() {
791 TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
792
793 // In the offline case, "My photos" could be the only category. Thus we need this check --
794 // to ensure that we don't try to select the "previously selected" category which was -1.
795 if (mLastSelectedCategoryTabIndex > -1) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800796 Tab tabToSelect = tabLayout.getTabAt(
797 mLastSelectedCategoryTabIndex);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800798 if (((Category) tabToSelect.getTag()).isEnumerable()) {
799 tabToSelect.select();
800 }
801 }
802 }
803
Jon Miranda16ea1b12017-12-12 14:52:48 -0800804 private void showCategoryDesktop(String collectionId) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800805 Category category = mDelegate.findCategoryForCollectionId(collectionId);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800806 if (category == null) {
807 return;
808 }
809
810 if (category.isEnumerable()) {
811 // Replace contained IndividualPickerFragment with a new instance for the given category.
812 final FragmentManager fm = getSupportFragmentManager();
813 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
814 if (fragment != null) {
815 fm.beginTransaction()
816 .remove(fragment)
817 .commit();
818 }
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800819 Injector injector = InjectorProvider.getInjector();
820 IndividualPickerFragment newFragment = injector.getIndividualPickerFragment(
821 collectionId);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800822 fm.beginTransaction()
823 .add(R.id.fragment_container, newFragment)
824 .commit();
825 newFragment.setCurrentWallpaperBottomSheetPresenter(this);
826 newFragment.setWallpapersUiContainer(this);
827 } else {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800828 category.show(this, mDelegate.getPickerIntentFactory(),
829 WallpaperPickerDelegate.SHOW_CATEGORY_REQUEST_CODE);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800830
831 // Need to select the tab here in case we are coming back from a "My photos" in which case
832 // the tab would have been set to "My photos" while viewing a regular image category.
833 reselectLastTab();
834 }
835 }
836
837 private void finishActivityWithResultOk() {
838 overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
839 setResult(Activity.RESULT_OK);
840 finish();
841 }
842
Jon Miranda16ea1b12017-12-12 14:52:48 -0800843 @Override
844 public void setCurrentWallpapersExpanded(boolean expanded) {
845 final BottomSheetBehavior<LinearLayout> bottomSheetBehavior =
846 BottomSheetBehavior.from(mBottomSheet);
847 bottomSheetBehavior.setState(
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800848 expanded ? BottomSheetBehavior.STATE_EXPANDED
849 : BottomSheetBehavior.STATE_COLLAPSED);
850 }
851
852 @Override
853 public void doneFetchingCategories() {
854 populateCategoryTabs(mLastSelectedCategoryTabIndex);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800855 }
856
857 @Override
858 public void onWallpapersReady() {
859 setDesktopLoading(false);
860 setCurrentWallpapersExpanded(true);
861 }
862
863 @Override
Santiago Etchebeherefab49612019-01-15 12:22:42 -0800864 public MyPhotosStarter getMyPhotosStarter() {
865 return this;
866 }
867
868 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800869 public void onClickTryAgain(@Destination int unused) {
870 // Retry the set wallpaper operation with the default center-crop setting.
871 if (mPendingSetWallpaperInfo != null) {
872 setCustomPhotoWallpaper(mPendingSetWallpaperInfo);
873 }
874 }
875
876 /**
877 * Sets the provides wallpaper to the device with center-cropped and scaled to fit the device's
878 * default display.
879 */
880 private void setCustomPhotoWallpaper(final WallpaperInfo wallpaper) {
881 // Save this WallpaperInfo so we can retry this operation later if it fails.
882 mPendingSetWallpaperInfo = wallpaper;
883
884 showSettingWallpaperProgressDialog();
885
886 mWallpaperPersister.setIndividualWallpaperWithPosition(this, wallpaper,
887 WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP, new SetWallpaperCallback() {
888 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800889 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800890 dismissSettingWallpaperProgressDialog();
891 refreshCurrentWallpapers(null /* refreshListener */);
892
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800893 mDelegate.getPreferences().setPendingWallpaperSetStatus(
Jon Miranda16ea1b12017-12-12 14:52:48 -0800894 WallpaperPreferences.WALLPAPER_SET_NOT_PENDING);
895 mUserEventLogger.logWallpaperSet(
896 wallpaper.getCollectionId(getApplicationContext()),
897 wallpaper.getWallpaperId());
898 mUserEventLogger.logWallpaperSetResult(UserEventLogger.WALLPAPER_SET_RESULT_SUCCESS);
899
900 // The user may have closed the activity before the set wallpaper operation completed.
901 if (isDestroyed()) {
902 return;
903 }
904
905 // Show the wallpaper crop option selector and bind click event handlers.
906 mWallpaperPositionOptions.setVisibility(View.VISIBLE);
907
908 mWasCustomPhotoWallpaperSet = true;
909 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP;
910
911 initializeWallpaperPositionOptionClickHandlers(wallpaper);
912 }
913
914 @Override
915 public void onError(Throwable throwable) {
916 dismissSettingWallpaperProgressDialog();
917 showSetWallpaperErrorDialog();
918
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800919 mDelegate.getPreferences().setPendingWallpaperSetStatus(
Jon Miranda16ea1b12017-12-12 14:52:48 -0800920 WallpaperPreferences.WALLPAPER_SET_NOT_PENDING);
921 mUserEventLogger.logWallpaperSetResult(
922 UserEventLogger.WALLPAPER_SET_RESULT_FAILURE);
923 @WallpaperSetFailureReason int failureReason = ThrowableAnalyzer.isOOM(throwable)
924 ? UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OOM
925 : UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OTHER;
926 mUserEventLogger.logWallpaperSetFailureReason(failureReason);
927 Log.e(TAG, "Unable to set wallpaper from 'my photos'.");
928 }
929 });
930 }
931
932 /**
933 * Initializes the wallpaper position button click handlers to change the way the provided
934 * wallpaper is set to the device.
935 */
936 private void initializeWallpaperPositionOptionClickHandlers(final WallpaperInfo wallpaperInfo) {
937 Button centerCropOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_center_crop);
938 Button stretchOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_stretched);
939 Button centerOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_center);
940
941 // The "center crop" wallpaper position button is selected by default.
942 setCenterCropWallpaperPositionButtonSelected(centerCropOptionBtn, true /* isSelected */);
943 centerCropOptionBtn.setOnClickListener(new OnClickListener() {
944 @Override
945 public void onClick(View view) {
946 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
947 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP,
948 new SetWallpaperCallback() {
949 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800950 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800951 // The user may have closed the activity before the set wallpaper operation
952 // completed.
953 if (isDestroyed()) {
954 return;
955 }
956
957 refreshCurrentWallpapers(null /* refreshListener */);
958
959 setCenterCropWallpaperPositionButtonSelected(
960 centerCropOptionBtn, true /* isSelected */);
961 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
962 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
963
964 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP;
965 }
966
967 @Override
968 public void onError(@Nullable Throwable throwable) {
969 // no-op
970 }
971 });
972 }
973 });
974
975 // "Stretch" is not selected by default.
976 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
977 stretchOptionBtn.setOnClickListener(new OnClickListener() {
978 @Override
979 public void onClick(View view) {
980 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
981 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_STRETCH,
982 new SetWallpaperCallback() {
983 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800984 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800985 // The user may have closed the activity before the set wallpaper operation
986 // completed.
987 if (isDestroyed()) {
988 return;
989 }
990
991 refreshCurrentWallpapers(null /* refreshListener */);
992
993 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, true /* isSelected */);
994 setCenterCropWallpaperPositionButtonSelected(
995 centerCropOptionBtn, false /* isSelected */);
996 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
997
998 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_STRETCH;
999 }
1000
1001 @Override
1002 public void onError(@Nullable Throwable throwable) {
1003 // no-op
1004 }
1005 });
1006 }
1007 });
1008
1009 // "Center" is not selected by default.
1010 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
1011 centerOptionBtn.setOnClickListener(new OnClickListener() {
1012 @Override
1013 public void onClick(View view) {
1014 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
1015 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_CENTER,
1016 new SetWallpaperCallback() {
1017 @Override
“Chuckffd832c2020-03-22 02:15:58 +08001018 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001019 // The user may have closed the activity before the set wallpaper operation
1020 // completed.
1021 if (isDestroyed()) {
1022 return;
1023 }
1024
1025 refreshCurrentWallpapers(null /* refreshListener */);
1026
1027 setCenterWallpaperPositionButtonSelected(centerOptionBtn, true /* isSelected */);
1028 setCenterCropWallpaperPositionButtonSelected(
1029 centerCropOptionBtn, false /* isSelected */);
1030 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
1031
1032 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER;
1033 }
1034
1035 @Override
1036 public void onError(@Nullable Throwable throwable) {
1037 // no-op
1038 }
1039 });
1040 }
1041 });
1042 }
1043
1044 private void setCenterWallpaperPositionButtonSelected(Button button, boolean isSelected) {
1045 int drawableId = isSelected ? R.drawable.center_blue : R.drawable.center_grey;
1046 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
1047 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
1048 }
1049
1050 private void setCenterCropWallpaperPositionButtonSelected(Button button, boolean isSelected) {
1051 int drawableId = isSelected ? R.drawable.center_crop_blue : R.drawable.center_crop_grey;
1052 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
1053 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
1054 }
1055
1056 private void setStretchWallpaperPositionButtonSelected(Button button, boolean isSelected) {
1057 int drawableId = isSelected ? R.drawable.stretch_blue : R.drawable.stretch_grey;
1058 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
1059 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
1060 }
1061
1062 private void showSettingWallpaperProgressDialog() {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -08001063 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which
1064 // therefore causes Espresso to hang once the dialog is shown.
Jon Miranda16ea1b12017-12-12 14:52:48 -08001065 if (!mTestingMode) {
1066 int themeResId;
1067 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
1068 themeResId = R.style.ProgressDialogThemePreL;
1069 } else {
1070 themeResId = R.style.LightDialogTheme;
1071 }
1072 mSetWallpaperProgressDialog = new ProgressDialog(this, themeResId);
1073 mSetWallpaperProgressDialog.setTitle(null);
1074 mSetWallpaperProgressDialog.setMessage(
1075 getResources().getString(R.string.set_wallpaper_progress_message));
1076 mSetWallpaperProgressDialog.setIndeterminate(true);
1077 mSetWallpaperProgressDialog.show();
1078 }
1079 }
1080
1081 private void dismissSettingWallpaperProgressDialog() {
1082 if (mSetWallpaperProgressDialog != null) {
1083 mSetWallpaperProgressDialog.dismiss();
1084 }
1085 }
1086
1087 private void showSetWallpaperErrorDialog() {
1088 SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance(
1089 R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH);
1090
1091 if (isSafeToCommitFragmentTransaction()) {
1092 dialogFragment.show(getSupportFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
1093 } else {
1094 mStagedSetWallpaperErrorDialogFragment = dialogFragment;
1095 }
1096 }
1097
1098 private interface AssetReceiver {
1099 void onAssetReceived(Asset asset);
1100 }
1101
1102 /**
1103 * An AsyncTask for asynchronously fetching the thumbnail asset for a given WallpaperInfo.
1104 * Used to work around expensive method call to WallpaperManager#getWallpaperFile made from the
1105 * CurrentWallpaperInfoVN getAsset() method.
1106 */
1107 private static class FetchThumbAssetTask extends AsyncTask<Void, Void, Asset> {
1108 private Context mAppContext;
1109 private WallpaperInfo mWallpaperInfo;
1110 private AssetReceiver mReceiver;
1111
1112 public FetchThumbAssetTask(Context appContext, WallpaperInfo wallpaperInfo,
1113 AssetReceiver receiver) {
1114 mAppContext = appContext;
1115 mWallpaperInfo = wallpaperInfo;
1116 mReceiver = receiver;
1117 }
1118
1119 @Override
1120 protected Asset doInBackground(Void... params) {
1121 return mWallpaperInfo.getThumbAsset(mAppContext);
1122 }
1123
1124 @Override
1125 protected void onPostExecute(Asset thumbAsset) {
1126 mReceiver.onAssetReceived(thumbAsset);
1127 }
1128 }
1129}