blob: e8f1ab65c484822480502b849b1edff22ba73ede [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;
Chuck Liaof646e052020-09-24 12:24:59 +080019import android.app.AlertDialog;
Jon Miranda16ea1b12017-12-12 14:52:48 -080020import android.app.ProgressDialog;
Jon Miranda16ea1b12017-12-12 14:52:48 -080021import android.content.Context;
22import android.content.Intent;
Jon Miranda16ea1b12017-12-12 14:52:48 -080023import android.graphics.Color;
Santiago Etchebehere35891ea2019-07-26 15:21:42 -070024import android.graphics.Insets;
Jon Miranda16ea1b12017-12-12 14:52:48 -080025import 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;
Santiago Etchebehere635e96f2018-12-04 18:31:34 -080045import androidx.appcompat.widget.Toolbar;
46import androidx.fragment.app.Fragment;
47import androidx.fragment.app.FragmentManager;
48
Jon Miranda16ea1b12017-12-12 14:52:48 -080049import com.android.wallpaper.R;
50import com.android.wallpaper.asset.Asset;
Santiago Etchebehere35891ea2019-07-26 15:21:42 -070051import com.android.wallpaper.compat.BuildCompat;
Jon Miranda16ea1b12017-12-12 14:52:48 -080052import com.android.wallpaper.compat.ButtonDrawableSetterCompat;
Jon Miranda16ea1b12017-12-12 14:52:48 -080053import com.android.wallpaper.config.Flags;
54import com.android.wallpaper.model.Category;
Jon Miranda16ea1b12017-12-12 14:52:48 -080055import com.android.wallpaper.model.ImageWallpaperInfo;
Jon Miranda16ea1b12017-12-12 14:52:48 -080056import com.android.wallpaper.model.WallpaperInfo;
57import com.android.wallpaper.module.CurrentWallpaperInfoFactory;
58import com.android.wallpaper.module.CurrentWallpaperInfoFactory.WallpaperInfoCallback;
59import com.android.wallpaper.module.DailyLoggingAlarmScheduler;
60import com.android.wallpaper.module.ExploreIntentChecker;
61import com.android.wallpaper.module.FormFactorChecker;
Jon Miranda16ea1b12017-12-12 14:52:48 -080062import com.android.wallpaper.module.Injector;
63import com.android.wallpaper.module.InjectorProvider;
64import com.android.wallpaper.module.NetworkStatusNotifier;
65import com.android.wallpaper.module.NetworkStatusNotifier.NetworkStatus;
66import com.android.wallpaper.module.UserEventLogger;
67import com.android.wallpaper.module.UserEventLogger.WallpaperSetFailureReason;
68import com.android.wallpaper.module.WallpaperPersister;
69import com.android.wallpaper.module.WallpaperPersister.Destination;
70import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback;
71import com.android.wallpaper.module.WallpaperPersister.WallpaperPosition;
72import com.android.wallpaper.module.WallpaperPreferences;
73import com.android.wallpaper.module.WallpaperPreferences.PresentationMode;
74import com.android.wallpaper.module.WallpaperRotationRefresher;
75import com.android.wallpaper.module.WallpaperRotationRefresher.Listener;
Santiago Etchebehere635e96f2018-12-04 18:31:34 -080076import com.android.wallpaper.picker.CategoryFragment.CategoryFragmentHost;
Jon Miranda16ea1b12017-12-12 14:52:48 -080077import com.android.wallpaper.picker.WallpaperDisabledFragment.WallpaperSupportLevel;
Jon Miranda16ea1b12017-12-12 14:52:48 -080078import com.android.wallpaper.picker.individual.IndividualPickerFragment;
79import com.android.wallpaper.util.ScreenSizeCalculator;
80import com.android.wallpaper.util.ThrowableAnalyzer;
chihhangchuang3efb6832020-04-17 02:06:25 +080081import com.android.wallpaper.widget.BottomActionBar;
82import com.android.wallpaper.widget.BottomActionBar.BottomActionBarHost;
Jon Miranda16ea1b12017-12-12 14:52:48 -080083
Sunny Goyal8600a3f2018-08-15 12:48:01 -070084import com.google.android.material.bottomsheet.BottomSheetBehavior;
85import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback;
86import com.google.android.material.tabs.TabLayout;
87import com.google.android.material.tabs.TabLayout.OnTabSelectedListener;
88import com.google.android.material.tabs.TabLayout.Tab;
89
Jon Miranda16ea1b12017-12-12 14:52:48 -080090import java.util.List;
91
92/**
93 * Activity allowing users to select a category of wallpapers to choose from.
94 */
95public class TopLevelPickerActivity extends BaseActivity implements WallpapersUiContainer,
96 CurrentWallpaperBottomSheetPresenter, SetWallpaperErrorDialogFragment.Listener,
chihhangchuang3efb6832020-04-17 02:06:25 +080097 MyPhotosStarter, CategoryFragmentHost, BottomActionBarHost {
Jon Miranda16ea1b12017-12-12 14:52:48 -080098
99 private static final String TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT =
100 "toplevel_set_wallpaper_error_dialog";
101
102 private static final String TAG = "TopLevelPicker";
103 private static final String KEY_SELECTED_CATEGORY_TAB = "selected_category_tab";
104
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800105 private WallpaperPickerDelegate mDelegate;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800106 private int mLastSelectedCategoryTabIndex;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800107 private UserEventLogger mUserEventLogger;
108 private NetworkStatusNotifier mNetworkStatusNotifier;
109 private NetworkStatusNotifier.Listener mNetworkStatusListener;
110 private WallpaperPersister mWallpaperPersister;
Kunhung Li166842e2020-05-13 19:19:06 +0800111 private WallpaperPreferences mWallpaperPreferences;
Jon Miranda16ea1b12017-12-12 14:52:48 -0800112 private boolean mWasCustomPhotoWallpaperSet;
113 @WallpaperPosition
114 private int mCustomPhotoWallpaperPosition;
115
116 /**
117 * Progress dialogs for "refresh daily wallpaper" and "set wallpaper" operations.
118 */
119 private ProgressDialog mRefreshWallpaperProgressDialog;
120 private ProgressDialog mSetWallpaperProgressDialog;
121
122 /**
123 * Designates a test mode of operation -- in which certain UI features are disabled to allow for
124 * UI tests to run correctly.
125 */
126 private boolean mTestingMode;
127
128 /**
129 * UI for the "currently set wallpaper" BottomSheet.
130 */
131 private LinearLayout mBottomSheet;
132 private ImageView mCurrentWallpaperImage;
133 private TextView mCurrentWallpaperPresentationMode;
134 private TextView mCurrentWallpaperTitle;
135 private TextView mCurrentWallpaperSubtitle;
136 private Button mCurrentWallpaperExploreButton;
137 private Button mCurrentWallpaperSkipWallpaperButton;
138 private FrameLayout mFragmentContainer;
139 private FrameLayout mLoadingIndicatorContainer;
140 private LinearLayout mWallpaperPositionOptions;
141
Jon Miranda16ea1b12017-12-12 14:52:48 -0800142 /**
143 * Staged error dialog fragments that were unable to be shown when the activity didn't allow
144 * committing fragment transactions.
145 */
146 private SetWallpaperErrorDialogFragment mStagedSetWallpaperErrorDialogFragment;
147
148 /**
149 * A wallpaper pending set to the device--we retain a reference to this in order to facilitate
150 * retry or re-crop operations.
151 */
152 private WallpaperInfo mPendingSetWallpaperInfo;
153
154 private static int getTextColorIdForWallpaperPositionButton(boolean isSelected) {
155 return isSelected ? R.color.accent_color : R.color.material_grey500;
156 }
157
158 @Override
159 protected void onCreate(Bundle savedInstanceState) {
160 super.onCreate(savedInstanceState);
161
Jon Miranda16ea1b12017-12-12 14:52:48 -0800162 mLastSelectedCategoryTabIndex = -1;
163
164 Injector injector = InjectorProvider.getInjector();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800165 mDelegate = new WallpaperPickerDelegate(this, this, injector);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800166 mUserEventLogger = injector.getUserEventLogger(this);
167 mNetworkStatusNotifier = injector.getNetworkStatusNotifier(this);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800168 mWallpaperPersister = injector.getWallpaperPersister(this);
Kunhung Li83f72a82020-06-02 11:05:10 +0800169 mWallpaperPreferences = injector.getPreferences(this);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800170 mWasCustomPhotoWallpaperSet = false;
171
Chuck Liaoe2d35f52020-09-22 21:20:47 +0800172 mDelegate.getCategoryProvider().resetIfNeeded();
173
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800174 @WallpaperSupportLevel int wallpaperSupportLevel = mDelegate.getWallpaperSupportLevel();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800175 if (wallpaperSupportLevel != WallpaperDisabledFragment.SUPPORTED_CAN_SET) {
Chuck Liao8ec38e02020-02-26 20:59:32 +0800176 setContentView(R.layout.activity_top_level_picker);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800177
178 FragmentManager fm = getSupportFragmentManager();
179 WallpaperDisabledFragment wallpaperDisabledFragment =
180 WallpaperDisabledFragment.newInstance(wallpaperSupportLevel);
181 fm.beginTransaction()
182 .add(R.id.fragment_container, wallpaperDisabledFragment)
183 .commit();
184 return;
185 }
186
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800187 if (mDelegate.getFormFactor() == FormFactorChecker.FORM_FACTOR_MOBILE) {
Ching-Sung Li5f689972019-05-20 17:16:57 +0800188 initializeMobile(true /* shouldForceRefresh */);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800189 } else { // DESKTOP
190 initializeDesktop(savedInstanceState);
191 }
192 }
193
194 @Override
195 protected void onResume() {
196 super.onResume();
Hyunyoung Song8077c862019-06-18 01:14:24 -0400197 boolean provisioned = Settings.Global.getInt(getContentResolver(),
198 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
199
200 mUserEventLogger.logResumed(provisioned, true);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800201 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one
202 // that was unable to be shown earlier when this fragment's hosting activity didn't allow
203 // committing fragment transactions.
204 if (mStagedSetWallpaperErrorDialogFragment != null) {
205 mStagedSetWallpaperErrorDialogFragment.show(
206 getSupportFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
207 mStagedSetWallpaperErrorDialogFragment = null;
208 }
209 }
210
211 @Override
Santiago Etchebeherebd536c62019-04-09 15:25:51 -0300212 protected void onStop() {
213 mUserEventLogger.logStopped();
214 super.onStop();
215 }
216
217 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800218 protected void onDestroy() {
219 super.onDestroy();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800220 mDelegate.cleanUp();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800221 if (mNetworkStatusListener != null) {
222 mNetworkStatusNotifier.unregisterListener(mNetworkStatusListener);
223 }
224
225 if (mRefreshWallpaperProgressDialog != null) {
226 mRefreshWallpaperProgressDialog.dismiss();
227 }
228 if (mSetWallpaperProgressDialog != null) {
229 mSetWallpaperProgressDialog.dismiss();
230 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800231 }
232
233 @Override
Chuck Liaob1f1a3a2020-02-17 19:46:14 +0800234 public void onBackPressed() {
Chuck Liaof24418e2020-05-10 02:29:44 +0800235 Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
236 if (fragment instanceof BottomActionBarFragment
237 && ((BottomActionBarFragment) fragment).onBackPressed()) {
238 return;
239 }
240
Chuck Liao8cbe49f2021-03-15 20:28:04 +0800241 if (fragment != null && fragment.getChildFragmentManager().popBackStackImmediate()) {
Chuck Liaob1f1a3a2020-02-17 19:46:14 +0800242 return;
243 }
244 super.onBackPressed();
245 }
246
247 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800248 public void requestCustomPhotoPicker(PermissionChangedListener listener) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800249 mDelegate.requestCustomPhotoPicker(listener);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800250 }
251
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800252 @Override
253 public void requestExternalStoragePermission(PermissionChangedListener listener) {
254 mDelegate.requestExternalStoragePermission(listener);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800255 }
256
257 /**
258 * Returns whether READ_EXTERNAL_STORAGE has been granted for the application.
259 */
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800260 public boolean isReadExternalStoragePermissionGranted() {
261 return mDelegate.isReadExternalStoragePermissionGranted();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800262 }
263
Ching-Sung Li5f689972019-05-20 17:16:57 +0800264 private void initializeMobile(boolean shouldForceRefresh) {
Chuck Liao8ec38e02020-02-26 20:59:32 +0800265 setContentView(R.layout.activity_top_level_picker);
Santiago Etchebehere35891ea2019-07-26 15:21:42 -0700266 getWindow().getDecorView().setSystemUiVisibility(
267 getWindow().getDecorView().getSystemUiVisibility()
268 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
269 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
Chuck Liao829d4d22020-05-07 17:00:10 +0800270 View fragmentContainer = findViewById(R.id.fragment_container);
271 fragmentContainer.setOnApplyWindowInsetsListener((view, windowInsets) -> {
Santiago Etchebehere35891ea2019-07-26 15:21:42 -0700272 view.setPadding(view.getPaddingLeft(), windowInsets.getSystemWindowInsetTop(),
Chuck Liaoe9d79812020-02-20 18:03:55 +0800273 view.getPaddingRight(), view.getPaddingBottom());
Santiago Etchebehere35891ea2019-07-26 15:21:42 -0700274 // Consume only the top inset (status bar), to let other content in the Activity consume
275 // the nav bar (ie, by using "fitSystemWindows")
276 if (BuildCompat.isAtLeastQ()) {
277 WindowInsets.Builder builder = new WindowInsets.Builder(windowInsets);
278 builder.setSystemWindowInsets(Insets.of(windowInsets.getSystemWindowInsetLeft(),
279 0, windowInsets.getStableInsetRight(),
280 windowInsets.getSystemWindowInsetBottom()));
281 return builder.build();
282 } else {
283 return windowInsets.replaceSystemWindowInsets(
284 windowInsets.getSystemWindowInsetLeft(),
285 0, windowInsets.getStableInsetRight(),
286 windowInsets.getSystemWindowInsetBottom());
287 }
288 });
Jon Miranda16ea1b12017-12-12 14:52:48 -0800289
290 // Set toolbar as the action bar.
291 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
292 setSupportActionBar(toolbar);
293
294 FragmentManager fm = getSupportFragmentManager();
295 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
296
Jon Miranda16ea1b12017-12-12 14:52:48 -0800297 if (fragment == null) {
Wesley.CW Wang484cdf32020-09-25 19:18:51 +0800298 // App launch specific logic: log the "app launch source" event.
299 mUserEventLogger.logAppLaunched(getIntent());
Kunhung Li166842e2020-05-13 19:19:06 +0800300 mWallpaperPreferences.incrementAppLaunched();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800301 DailyLoggingAlarmScheduler.setAlarm(getApplicationContext());
302
Santiago Etchebehereaa35e6e2019-01-25 10:30:11 -0800303 CategoryFragment newFragment = CategoryFragment.newInstance(
304 getString(R.string.wallpaper_app_name));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800305 fm.beginTransaction()
306 .add(R.id.fragment_container, newFragment)
307 .commit();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800308 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800309 }
310
311 private void initializeDesktop(Bundle savedInstanceState) {
312 setContentView(R.layout.activity_top_level_desktop);
313
314 mBottomSheet = (LinearLayout) findViewById(R.id.bottom_sheet);
315 mCurrentWallpaperImage = (ImageView) mBottomSheet.findViewById(R.id.current_wallpaper_image);
316 mCurrentWallpaperImage.getLayoutParams().width = getSingleWallpaperImageWidthPx();
317
318 mCurrentWallpaperPresentationMode =
319 (TextView) mBottomSheet.findViewById(R.id.current_wallpaper_presentation_mode);
320 mCurrentWallpaperTitle = (TextView) findViewById(R.id.current_wallpaper_title);
321 mCurrentWallpaperSubtitle = (TextView) findViewById(R.id.current_wallpaper_subtitle);
322 mCurrentWallpaperExploreButton = (Button) findViewById(
323 R.id.current_wallpaper_explore_button);
324 mCurrentWallpaperSkipWallpaperButton = (Button) findViewById(
325 R.id.current_wallpaper_skip_wallpaper_button);
326 mFragmentContainer = (FrameLayout) findViewById(R.id.fragment_container);
327 mLoadingIndicatorContainer = (FrameLayout) findViewById(R.id.loading_indicator_container);
328 mWallpaperPositionOptions = (LinearLayout) findViewById(
329 R.id.desktop_wallpaper_position_options);
330
331 final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
332 tabLayout.addOnTabSelectedListener(new OnTabSelectedListener() {
333 @Override
334 public void onTabSelected(Tab tab) {
335 Category category = (Category) tab.getTag();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800336 showCategoryDesktop(category.getCollectionId());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800337 mLastSelectedCategoryTabIndex = tabLayout.getSelectedTabPosition();
338 }
339
340 @Override
341 public void onTabUnselected(Tab tab) {
342 }
343
344 @Override
345 public void onTabReselected(Tab tab) {
346 Category category = (Category) tab.getTag();
347 // If offline, "My photos" may be the only visible category. In this case we want to allow
348 // re-selection so user can still select a photo as wallpaper while offline.
349 if (!category.isEnumerable()) {
350 onTabSelected(tab);
351 }
352 }
353 });
354
355 FragmentManager fm = getSupportFragmentManager();
356 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
357
358 if (fragment == null) {
Wesley.CW Wang484cdf32020-09-25 19:18:51 +0800359 // App launch specific logic: log the "app launch source" event.
360 mUserEventLogger.logAppLaunched(getIntent());
Kunhung Li166842e2020-05-13 19:19:06 +0800361 mWallpaperPreferences.incrementAppLaunched();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800362 DailyLoggingAlarmScheduler.setAlarm(getApplicationContext());
363 }
364
365 mNetworkStatusListener = new NetworkStatusNotifier.Listener() {
366 @Override
367 public void onNetworkChanged(@NetworkStatus int networkStatus) {
368 initializeDesktopBasedOnNetwork(networkStatus, savedInstanceState);
369 }
370 };
371 // Upon registering a listener, the onNetworkChanged method is immediately called with the
372 // initial network status.
373 mNetworkStatusNotifier.registerListener(mNetworkStatusListener);
374 }
375
376 private void initializeDesktopBasedOnNetwork(@NetworkStatus int networkStatus,
377 Bundle savedInstanceState) {
378 if (networkStatus == NetworkStatusNotifier.NETWORK_CONNECTED) {
379 initializeDesktopOnline(savedInstanceState);
380 } else {
381 initializeDesktopOffline();
382 }
383 }
384
385 private void initializeDesktopOnline(Bundle savedInstanceState) {
386 FragmentManager fm = getSupportFragmentManager();
387 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
388
389 // Require a category refresh if this is the first load of the app or if the app is now
390 // returning online after having been offline.
391 boolean forceCategoryRefresh = fragment == null || fragment instanceof OfflineDesktopFragment;
392
393 if (fragment != null) {
394 fm.beginTransaction()
395 .remove(fragment)
396 .commit();
397 }
398
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800399 mLastSelectedCategoryTabIndex = savedInstanceState != null
Jon Miranda16ea1b12017-12-12 14:52:48 -0800400 ? savedInstanceState.getInt(KEY_SELECTED_CATEGORY_TAB) : -1;
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800401 mDelegate.populateCategories(forceCategoryRefresh);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800402
403 setDesktopLoading(true);
404 setUpBottomSheet();
405 refreshCurrentWallpapers(null /* refreshListener */);
406 }
407
408 private void initializeDesktopOffline() {
409 FragmentManager fm = getSupportFragmentManager();
410 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
411
412 if (fragment != null) {
413 fm.beginTransaction()
414 .remove(fragment)
415 .commit();
416 }
417 OfflineDesktopFragment newFragment = new OfflineDesktopFragment();
418 fm.beginTransaction()
419 .add(R.id.fragment_container, newFragment)
420 .commit();
421
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800422 // Reset the last selected category tab index to ensure the app doesn't try to reselect a
423 // tab for a category not yet repopulated.
Jon Miranda16ea1b12017-12-12 14:52:48 -0800424 mLastSelectedCategoryTabIndex = -1;
425
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800426 mDelegate.populateCategories(true /* forceCategoryRefresh */);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800427
428 setDesktopLoading(false);
429 setCurrentWallpapersExpanded(false);
430 }
431
432 /**
433 * Sets the status of the loading indicator overlay in desktop mode.
434 *
435 * @param loading Whether an indeterminate loading indicator is displayed in place of the main
436 * fragment.
437 */
438 private void setDesktopLoading(boolean loading) {
439 if (loading) {
440 mLoadingIndicatorContainer.setVisibility(View.VISIBLE);
441 mFragmentContainer.setVisibility(View.GONE);
442 } else {
443 mLoadingIndicatorContainer.setVisibility(View.GONE);
444 mFragmentContainer.setVisibility(View.VISIBLE);
445 }
446 }
447
448 /**
449 * Returns the width (in physical px) to use for the "currently set wallpaper" thumbnail.
450 */
451 private int getSingleWallpaperImageWidthPx() {
chihhangchuangc8442a72020-05-07 14:26:32 +0800452 final float screenAspectRatio =
453 ScreenSizeCalculator.getInstance().getScreenAspectRatio(this);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800454
455 int height = getResources().getDimensionPixelSize(
456 R.dimen.current_wallpaper_bottom_sheet_thumb_height);
chihhangchuangc8442a72020-05-07 14:26:32 +0800457 return (int) (height / screenAspectRatio);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800458 }
459
460 /**
461 * Enables and populates the "Currently set" wallpaper BottomSheet.
462 */
463 private void setUpBottomSheet() {
464 mBottomSheet.setVisibility(View.VISIBLE);
465
Jon Miranda16ea1b12017-12-12 14:52:48 -0800466 if (Flags.skipDailyWallpaperButtonEnabled) {
467 // Add "next" icon to the Next Wallpaper button
468 Drawable nextWallpaperButtonDrawable = getResources().getDrawable(
Santiago Etchebehered24506c2018-04-05 17:02:42 -0700469 R.drawable.ic_refresh_18px);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800470
471 // This Drawable's state is shared across the app, so make a copy of it before applying a
472 // color tint as not to affect other clients elsewhere in the app.
473 nextWallpaperButtonDrawable =
474 nextWallpaperButtonDrawable.getConstantState().newDrawable().mutate();
475 // Color the "compass" icon with the accent color.
476 nextWallpaperButtonDrawable.setColorFilter(
477 getResources().getColor(R.color.accent_color), Mode.SRC_IN);
478 ButtonDrawableSetterCompat.setDrawableToButtonStart(
479 mCurrentWallpaperSkipWallpaperButton, nextWallpaperButtonDrawable);
480 }
481
482 final BottomSheetBehavior<LinearLayout> bottomSheetBehavior =
483 BottomSheetBehavior.from(mBottomSheet);
484 bottomSheetBehavior.setBottomSheetCallback(new BottomSheetCallback() {
485 @Override
486 public void onStateChanged(@NonNull View view, int i) {
487 }
488
489 @Override
490 public void onSlide(@NonNull View view, float slideOffset) {
491 float alpha;
492 if (slideOffset >= 0) {
493 alpha = slideOffset;
494 } else {
495 alpha = 1f - slideOffset;
496 }
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800497 LinearLayout bottomSheetContents = findViewById(R.id.bottom_sheet_contents);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800498 bottomSheetContents.setAlpha(alpha);
499 }
500 });
501 }
502
503 /**
504 * Enables a test mode of operation -- in which certain UI features are disabled to allow for
505 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog
506 * constantly keeps the UI thread alive and blocks a test forever.
507 */
508 void setTestingMode(boolean testingMode) {
509 mTestingMode = testingMode;
510 }
511
512 /**
513 * Obtains the {@link WallpaperInfo} object(s) representing the wallpaper(s) currently set to the
514 * device from the {@link CurrentWallpaperInfoFactory} and displays them in the BottomSheet.
515 */
516 @Override
517 public void refreshCurrentWallpapers(@Nullable RefreshListener refreshListener) {
518 final Injector injector = InjectorProvider.getInjector();
519 final Context appContext = getApplicationContext();
520
521 CurrentWallpaperInfoFactory factory = injector.getCurrentWallpaperFactory(this);
522 factory.createCurrentWallpaperInfos(new WallpaperInfoCallback() {
523 @Override
524 public void onWallpaperInfoCreated(
525 final WallpaperInfo homeWallpaper,
526 @Nullable final WallpaperInfo lockWallpaper,
527 @PresentationMode final int presentationMode) {
528
529 if (isDestroyed()) {
530 return;
531 }
532
533 // Fetch the home wallpaper's thumbnail asset asynchronously to work around expensive
534 // method call to WallpaperManager#getWallpaperFile made from the CurrentWallpaperInfoVN
535 // getAsset() method.
536 AssetReceiver assetReceiver = (Asset thumbAsset) -> {
537 if (isDestroyed()) {
538 return;
539 }
540
541 homeWallpaper.getThumbAsset(appContext).loadDrawableWithTransition(
542 TopLevelPickerActivity.this,
543 mCurrentWallpaperImage,
544 200 /* transitionDurationMillis */,
545 () -> {
546 if (refreshListener != null) {
547 refreshListener.onCurrentWallpaperRefreshed();
548 }
549 },
550 Color.TRANSPARENT);
551 };
552 new FetchThumbAssetTask(appContext, homeWallpaper, assetReceiver).executeOnExecutor(
553 AsyncTask.THREAD_POOL_EXECUTOR);
554
555 mCurrentWallpaperPresentationMode.setText(
556 AttributionFormatter.getHumanReadableWallpaperPresentationMode(
557 TopLevelPickerActivity.this, presentationMode));
558
559 List<String> attributions = homeWallpaper.getAttributions(appContext);
560 if (attributions.size() > 0 && attributions.get(0) != null) {
561 mCurrentWallpaperTitle.setText(attributions.get(0));
562 }
563
564 mCurrentWallpaperSubtitle.setText(
565 AttributionFormatter.formatWallpaperSubtitle(appContext, homeWallpaper));
566
567 final String actionUrl = homeWallpaper.getActionUrl(appContext);
568 if (actionUrl != null && !actionUrl.isEmpty()) {
569 Uri exploreUri = Uri.parse(actionUrl);
570
571 ExploreIntentChecker intentChecker = injector.getExploreIntentChecker(appContext);
572 intentChecker.fetchValidActionViewIntent(exploreUri, (@Nullable Intent exploreIntent) -> {
573 if (exploreIntent != null && !isDestroyed()) {
Santiago Etchebehered1bd5092018-04-18 16:03:30 -0700574 // Set the icon for the button
575 Drawable exploreButtonDrawable = getResources().getDrawable(
Santiago Etchebeheree0810d02018-05-10 17:39:40 -0700576 homeWallpaper.getActionIconRes(appContext));
Santiago Etchebehered1bd5092018-04-18 16:03:30 -0700577
578 // This Drawable's state is shared across the app, so make a copy of it
579 // before applying a color tint as not to affect other clients elsewhere
580 // in the app.
581 exploreButtonDrawable = exploreButtonDrawable.getConstantState()
582 .newDrawable().mutate();
583 // Color the "compass" icon with the accent color.
584 exploreButtonDrawable.setColorFilter(
585 getResources().getColor(R.color.accent_color), Mode.SRC_IN);
586
587 ButtonDrawableSetterCompat.setDrawableToButtonStart(
588 mCurrentWallpaperExploreButton, exploreButtonDrawable);
589 mCurrentWallpaperExploreButton.setText(getString(
Santiago Etchebeheree0810d02018-05-10 17:39:40 -0700590 homeWallpaper.getActionLabelRes(appContext)));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800591 mCurrentWallpaperExploreButton.setVisibility(View.VISIBLE);
592 mCurrentWallpaperExploreButton.setOnClickListener(new OnClickListener() {
593 @Override
594 public void onClick(View v) {
Santiago Etchebeherece5613f2018-06-01 13:22:47 -0700595 mUserEventLogger.logActionClicked(
596 homeWallpaper.getCollectionId(appContext),
597 homeWallpaper.getActionLabelRes(appContext));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800598 startActivity(exploreIntent);
599 }
600 });
601 }
602 });
603 } else {
604 mCurrentWallpaperExploreButton.setVisibility(View.GONE);
605 }
606
607 // Hide the wallpaper position options UI if the current home wallpaper is not from
608 // "my photos".
609 String homeCollectionId = homeWallpaper.getCollectionId(TopLevelPickerActivity.this);
610 if (mWallpaperPositionOptions != null
611 && homeCollectionId != null // May be null if app is being used for the first time.
612 && !homeCollectionId.equals(getString(R.string.image_wallpaper_collection_id))) {
613 mWallpaperPositionOptions.setVisibility(View.GONE);
614 }
615
616 boolean showSkipWallpaperButton = Flags.skipDailyWallpaperButtonEnabled
617 && presentationMode == WallpaperPreferences.PRESENTATION_MODE_ROTATING;
618 if (showSkipWallpaperButton) {
619 mCurrentWallpaperSkipWallpaperButton.setVisibility(View.VISIBLE);
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800620 mCurrentWallpaperSkipWallpaperButton.setOnClickListener(
621 v -> refreshDailyWallpaper());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800622 } else {
623 mCurrentWallpaperSkipWallpaperButton.setVisibility(View.GONE);
624 }
625
626 if (refreshListener != null) {
627 refreshListener.onCurrentWallpaperRefreshed();
628 }
629 }
630 }, true /* forceRefresh */);
631 }
632
633 @Override
634 public void onSaveInstanceState(Bundle savedInstanceState) {
635 FormFactorChecker formFactorChecker = InjectorProvider.getInjector().getFormFactorChecker(this);
636 if (formFactorChecker.getFormFactor() == FormFactorChecker.FORM_FACTOR_DESKTOP) {
637 TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
638
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800639 // tabLayout is only present when the main IndividualPickerFragment is present (as
640 // opposed to
Jon Miranda16ea1b12017-12-12 14:52:48 -0800641 // the WallpaperDisabledFragment), so need this null check.
642 if (tabLayout != null) {
643 savedInstanceState.putInt(KEY_SELECTED_CATEGORY_TAB, tabLayout.getSelectedTabPosition());
644 }
645 }
646
647 super.onSaveInstanceState(savedInstanceState);
648 }
649
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800650 @Override
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700651 @Nullable
Chuck Liao8cbe49f2021-03-15 20:28:04 +0800652 public CategorySelectorFragment getCategorySelectorFragment() {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800653 if (mDelegate.getFormFactor() != FormFactorChecker.FORM_FACTOR_MOBILE) {
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700654 return null;
655 }
656 FragmentManager fm = getSupportFragmentManager();
Chuck Liao8cbe49f2021-03-15 20:28:04 +0800657 return ((CategoryFragment) fm.findFragmentById(
658 R.id.fragment_container)).getCategorySelectorFragment();
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700659 }
660
Jon Miranda16ea1b12017-12-12 14:52:48 -0800661 /**
662 * Populates the category tabs on DESKTOP form factor.
663 *
664 * @param selectedTabPosition The position of the tab to show as selected, or -1 if no particular
665 * tab should be selected (in which case: the tab of the category for the currently set
666 * wallpaper will be selected if enumerable; if not, the first enumerable category's tab will
667 * be selected).
668 */
669 private void populateCategoryTabs(int selectedTabPosition) {
670 final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
671 tabLayout.removeAllTabs();
672
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800673 String currentlySetCollectionId = mDelegate.getPreferences().getHomeWallpaperCollectionId();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800674
675 Tab tabToSelect = null;
676 Tab firstEnumerableCategoryTab = null;
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800677 for (int i = 0; i < mDelegate.getCategoryProvider().getSize(); i++) {
678 Category category = mDelegate.getCategoryProvider().getCategory(i);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800679
680 Tab tab = tabLayout.newTab();
681 tab.setText(category.getTitle());
682 tab.setTag(category);
683 tabLayout.addTab(tab, false /* setSelected */);
684
685 if (firstEnumerableCategoryTab == null && category.isEnumerable()) {
686 firstEnumerableCategoryTab = tab;
687 }
688
689 boolean shouldSelectTab = (i == selectedTabPosition)
690 || (selectedTabPosition == -1
691 && tabToSelect == null
692 && category.isEnumerable()
693 && currentlySetCollectionId != null
694 && currentlySetCollectionId.equals(category.getCollectionId()));
695
696 if (shouldSelectTab) {
697 tabToSelect = tab;
698 }
699 }
700
701 // If the above loop did not identify a specific tab to select, then just select the tab for
702 // the first enumerable category.
703 if (tabToSelect == null) {
704 tabToSelect = firstEnumerableCategoryTab;
705 }
706
707 // There may be no enumerable tabs (e.g., offline case), so we need to null-check again.
708 if (tabToSelect != null) {
709 tabToSelect.select();
710 }
711 }
712
713 /**
714 * Refreshes the current wallpaper in a daily wallpaper rotation.
715 */
716 private void refreshDailyWallpaper() {
717 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
718 // causes Espresso to hang once the dialog is shown.
719 if (!mTestingMode) {
720 int themeResId;
721 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
722 themeResId = R.style.ProgressDialogThemePreL;
723 } else {
724 themeResId = R.style.LightDialogTheme;
725 }
726 mRefreshWallpaperProgressDialog = new ProgressDialog(this, themeResId);
727 mRefreshWallpaperProgressDialog.setTitle(null);
728 mRefreshWallpaperProgressDialog.setMessage(
729 getResources().getString(R.string.refreshing_daily_wallpaper_dialog_message));
730 mRefreshWallpaperProgressDialog.setIndeterminate(true);
731 mRefreshWallpaperProgressDialog.show();
732 }
733
734 WallpaperRotationRefresher wallpaperRotationRefresher =
735 InjectorProvider.getInjector().getWallpaperRotationRefresher();
736 wallpaperRotationRefresher.refreshWallpaper(this, new Listener() {
737 @Override
738 public void onRefreshed() {
739 if (isDestroyed()) {
740 return;
741 }
742
743 if (mRefreshWallpaperProgressDialog != null) {
744 mRefreshWallpaperProgressDialog.dismiss();
745 }
746
747 refreshCurrentWallpapers(null /* refreshListener */);
748 }
749
750 @Override
751 public void onError() {
752 if (mRefreshWallpaperProgressDialog != null) {
753 mRefreshWallpaperProgressDialog.dismiss();
754 }
755
756 AlertDialog errorDialog = new AlertDialog.Builder(
757 TopLevelPickerActivity.this, R.style.LightDialogTheme)
758 .setMessage(R.string.refresh_daily_wallpaper_failed_message)
759 .setPositiveButton(android.R.string.ok, null /* onClickListener */)
760 .create();
761 errorDialog.show();
762 }
763 });
764 }
765
766 @Override
767 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
768 super.onActivityResult(requestCode, resultCode, data);
769
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800770 if (requestCode == WallpaperPickerDelegate.SHOW_CATEGORY_REQUEST_CODE
771 && resultCode == Activity.RESULT_OK) {
Santiago Etchebeheree5e05842019-02-13 16:58:07 -0800772 if (mDelegate.getFormFactor() == FormFactorChecker.FORM_FACTOR_DESKTOP) {
773 Uri imageUri = (data == null) ? null : data.getData();
774 if (imageUri != null) {
775 // User selected an image from the system picker, so launch the preview for that
776 // image.
777 ImageWallpaperInfo imageWallpaper = new ImageWallpaperInfo(imageUri);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800778 setCustomPhotoWallpaper(imageWallpaper);
779 return;
780 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800781 }
Santiago Etchebeheree5e05842019-02-13 16:58:07 -0800782 }
783 if (mDelegate.handleActivityResult(requestCode, resultCode, data)) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800784 finishActivityWithResultOk();
785 }
786 }
787
788 /**
789 * Shows the view-only preview activity for the given wallpaper.
790 */
Ching-Sung Lief59efa2020-06-05 22:41:43 +0800791 public void showViewOnlyPreview(WallpaperInfo wallpaperInfo, boolean isViewAsHome) {
792 mDelegate.showViewOnlyPreview(wallpaperInfo, isViewAsHome);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800793 }
794
795 @Override
Chuck Liaoa63f1bf2020-06-11 01:35:42 +0800796 public void show(String collectionId) {
797 mDelegate.show(collectionId);
798 }
799
800 @Override
Chuck Liaoaee30432020-06-23 01:17:05 +0800801 public boolean isNavigationTabsContained() {
802 return false;
803 }
804
805 @Override
Chuck Liaof6b4b192020-08-07 02:31:32 +0800806 public void fetchCategories() {
807 mDelegate.initialize(!mDelegate.getCategoryProvider().isCategoriesFetched());
808 }
809
810 @Override
Chuck Liao3abf15b2020-12-17 22:33:02 +0800811 public void cleanUp() {
812 mDelegate.cleanUp();
813 }
814
815 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800816 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
817 @NonNull int[] grantResults) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800818 mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800819 }
820
Jon Miranda16ea1b12017-12-12 14:52:48 -0800821 private void reselectLastTab() {
822 TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
823
824 // In the offline case, "My photos" could be the only category. Thus we need this check --
825 // to ensure that we don't try to select the "previously selected" category which was -1.
826 if (mLastSelectedCategoryTabIndex > -1) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800827 Tab tabToSelect = tabLayout.getTabAt(
828 mLastSelectedCategoryTabIndex);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800829 if (((Category) tabToSelect.getTag()).isEnumerable()) {
830 tabToSelect.select();
831 }
832 }
833 }
834
Jon Miranda16ea1b12017-12-12 14:52:48 -0800835 private void showCategoryDesktop(String collectionId) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800836 Category category = mDelegate.findCategoryForCollectionId(collectionId);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800837 if (category == null) {
838 return;
839 }
840
841 if (category.isEnumerable()) {
842 // Replace contained IndividualPickerFragment with a new instance for the given category.
843 final FragmentManager fm = getSupportFragmentManager();
844 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
845 if (fragment != null) {
846 fm.beginTransaction()
847 .remove(fragment)
848 .commit();
849 }
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800850 Injector injector = InjectorProvider.getInjector();
851 IndividualPickerFragment newFragment = injector.getIndividualPickerFragment(
852 collectionId);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800853 fm.beginTransaction()
854 .add(R.id.fragment_container, newFragment)
855 .commit();
856 newFragment.setCurrentWallpaperBottomSheetPresenter(this);
857 newFragment.setWallpapersUiContainer(this);
858 } else {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800859 category.show(this, mDelegate.getPickerIntentFactory(),
860 WallpaperPickerDelegate.SHOW_CATEGORY_REQUEST_CODE);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800861
862 // Need to select the tab here in case we are coming back from a "My photos" in which case
863 // the tab would have been set to "My photos" while viewing a regular image category.
864 reselectLastTab();
865 }
866 }
867
868 private void finishActivityWithResultOk() {
869 overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
870 setResult(Activity.RESULT_OK);
871 finish();
872 }
873
Jon Miranda16ea1b12017-12-12 14:52:48 -0800874 @Override
875 public void setCurrentWallpapersExpanded(boolean expanded) {
876 final BottomSheetBehavior<LinearLayout> bottomSheetBehavior =
877 BottomSheetBehavior.from(mBottomSheet);
878 bottomSheetBehavior.setState(
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800879 expanded ? BottomSheetBehavior.STATE_EXPANDED
880 : BottomSheetBehavior.STATE_COLLAPSED);
881 }
882
883 @Override
884 public void doneFetchingCategories() {
885 populateCategoryTabs(mLastSelectedCategoryTabIndex);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800886 }
887
888 @Override
889 public void onWallpapersReady() {
890 setDesktopLoading(false);
891 setCurrentWallpapersExpanded(true);
892 }
893
894 @Override
Santiago Etchebeherefab49612019-01-15 12:22:42 -0800895 public MyPhotosStarter getMyPhotosStarter() {
896 return this;
897 }
898
899 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800900 public void onClickTryAgain(@Destination int unused) {
901 // Retry the set wallpaper operation with the default center-crop setting.
902 if (mPendingSetWallpaperInfo != null) {
903 setCustomPhotoWallpaper(mPendingSetWallpaperInfo);
904 }
905 }
906
907 /**
908 * Sets the provides wallpaper to the device with center-cropped and scaled to fit the device's
909 * default display.
910 */
911 private void setCustomPhotoWallpaper(final WallpaperInfo wallpaper) {
912 // Save this WallpaperInfo so we can retry this operation later if it fails.
913 mPendingSetWallpaperInfo = wallpaper;
914
915 showSettingWallpaperProgressDialog();
916
917 mWallpaperPersister.setIndividualWallpaperWithPosition(this, wallpaper,
918 WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP, new SetWallpaperCallback() {
919 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800920 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800921 dismissSettingWallpaperProgressDialog();
922 refreshCurrentWallpapers(null /* refreshListener */);
923
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800924 mDelegate.getPreferences().setPendingWallpaperSetStatus(
Jon Miranda16ea1b12017-12-12 14:52:48 -0800925 WallpaperPreferences.WALLPAPER_SET_NOT_PENDING);
926 mUserEventLogger.logWallpaperSet(
927 wallpaper.getCollectionId(getApplicationContext()),
928 wallpaper.getWallpaperId());
929 mUserEventLogger.logWallpaperSetResult(UserEventLogger.WALLPAPER_SET_RESULT_SUCCESS);
930
931 // The user may have closed the activity before the set wallpaper operation completed.
932 if (isDestroyed()) {
933 return;
934 }
935
936 // Show the wallpaper crop option selector and bind click event handlers.
937 mWallpaperPositionOptions.setVisibility(View.VISIBLE);
938
939 mWasCustomPhotoWallpaperSet = true;
940 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP;
941
942 initializeWallpaperPositionOptionClickHandlers(wallpaper);
943 }
944
945 @Override
946 public void onError(Throwable throwable) {
947 dismissSettingWallpaperProgressDialog();
948 showSetWallpaperErrorDialog();
949
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800950 mDelegate.getPreferences().setPendingWallpaperSetStatus(
Jon Miranda16ea1b12017-12-12 14:52:48 -0800951 WallpaperPreferences.WALLPAPER_SET_NOT_PENDING);
952 mUserEventLogger.logWallpaperSetResult(
953 UserEventLogger.WALLPAPER_SET_RESULT_FAILURE);
954 @WallpaperSetFailureReason int failureReason = ThrowableAnalyzer.isOOM(throwable)
955 ? UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OOM
956 : UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OTHER;
957 mUserEventLogger.logWallpaperSetFailureReason(failureReason);
958 Log.e(TAG, "Unable to set wallpaper from 'my photos'.");
959 }
960 });
961 }
962
963 /**
964 * Initializes the wallpaper position button click handlers to change the way the provided
965 * wallpaper is set to the device.
966 */
967 private void initializeWallpaperPositionOptionClickHandlers(final WallpaperInfo wallpaperInfo) {
968 Button centerCropOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_center_crop);
969 Button stretchOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_stretched);
970 Button centerOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_center);
971
972 // The "center crop" wallpaper position button is selected by default.
973 setCenterCropWallpaperPositionButtonSelected(centerCropOptionBtn, true /* isSelected */);
974 centerCropOptionBtn.setOnClickListener(new OnClickListener() {
975 @Override
976 public void onClick(View view) {
977 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
978 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP,
979 new SetWallpaperCallback() {
980 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800981 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800982 // The user may have closed the activity before the set wallpaper operation
983 // completed.
984 if (isDestroyed()) {
985 return;
986 }
987
988 refreshCurrentWallpapers(null /* refreshListener */);
989
990 setCenterCropWallpaperPositionButtonSelected(
991 centerCropOptionBtn, true /* isSelected */);
992 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
993 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
994
995 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP;
996 }
997
998 @Override
999 public void onError(@Nullable Throwable throwable) {
1000 // no-op
1001 }
1002 });
1003 }
1004 });
1005
1006 // "Stretch" is not selected by default.
1007 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
1008 stretchOptionBtn.setOnClickListener(new OnClickListener() {
1009 @Override
1010 public void onClick(View view) {
1011 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
1012 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_STRETCH,
1013 new SetWallpaperCallback() {
1014 @Override
“Chuckffd832c2020-03-22 02:15:58 +08001015 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001016 // The user may have closed the activity before the set wallpaper operation
1017 // completed.
1018 if (isDestroyed()) {
1019 return;
1020 }
1021
1022 refreshCurrentWallpapers(null /* refreshListener */);
1023
1024 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, true /* isSelected */);
1025 setCenterCropWallpaperPositionButtonSelected(
1026 centerCropOptionBtn, false /* isSelected */);
1027 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
1028
1029 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_STRETCH;
1030 }
1031
1032 @Override
1033 public void onError(@Nullable Throwable throwable) {
1034 // no-op
1035 }
1036 });
1037 }
1038 });
1039
1040 // "Center" is not selected by default.
1041 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
1042 centerOptionBtn.setOnClickListener(new OnClickListener() {
1043 @Override
1044 public void onClick(View view) {
1045 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
1046 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_CENTER,
1047 new SetWallpaperCallback() {
1048 @Override
“Chuckffd832c2020-03-22 02:15:58 +08001049 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001050 // The user may have closed the activity before the set wallpaper operation
1051 // completed.
1052 if (isDestroyed()) {
1053 return;
1054 }
1055
1056 refreshCurrentWallpapers(null /* refreshListener */);
1057
1058 setCenterWallpaperPositionButtonSelected(centerOptionBtn, true /* isSelected */);
1059 setCenterCropWallpaperPositionButtonSelected(
1060 centerCropOptionBtn, false /* isSelected */);
1061 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
1062
1063 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER;
1064 }
1065
1066 @Override
1067 public void onError(@Nullable Throwable throwable) {
1068 // no-op
1069 }
1070 });
1071 }
1072 });
1073 }
1074
1075 private void setCenterWallpaperPositionButtonSelected(Button button, boolean isSelected) {
1076 int drawableId = isSelected ? R.drawable.center_blue : R.drawable.center_grey;
1077 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
1078 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
1079 }
1080
1081 private void setCenterCropWallpaperPositionButtonSelected(Button button, boolean isSelected) {
1082 int drawableId = isSelected ? R.drawable.center_crop_blue : R.drawable.center_crop_grey;
1083 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
1084 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
1085 }
1086
1087 private void setStretchWallpaperPositionButtonSelected(Button button, boolean isSelected) {
1088 int drawableId = isSelected ? R.drawable.stretch_blue : R.drawable.stretch_grey;
1089 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
1090 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
1091 }
1092
1093 private void showSettingWallpaperProgressDialog() {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -08001094 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which
1095 // therefore causes Espresso to hang once the dialog is shown.
Jon Miranda16ea1b12017-12-12 14:52:48 -08001096 if (!mTestingMode) {
1097 int themeResId;
1098 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
1099 themeResId = R.style.ProgressDialogThemePreL;
1100 } else {
1101 themeResId = R.style.LightDialogTheme;
1102 }
1103 mSetWallpaperProgressDialog = new ProgressDialog(this, themeResId);
1104 mSetWallpaperProgressDialog.setTitle(null);
1105 mSetWallpaperProgressDialog.setMessage(
1106 getResources().getString(R.string.set_wallpaper_progress_message));
1107 mSetWallpaperProgressDialog.setIndeterminate(true);
1108 mSetWallpaperProgressDialog.show();
1109 }
1110 }
1111
1112 private void dismissSettingWallpaperProgressDialog() {
1113 if (mSetWallpaperProgressDialog != null) {
1114 mSetWallpaperProgressDialog.dismiss();
1115 }
1116 }
1117
1118 private void showSetWallpaperErrorDialog() {
1119 SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance(
1120 R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH);
1121
1122 if (isSafeToCommitFragmentTransaction()) {
1123 dialogFragment.show(getSupportFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
1124 } else {
1125 mStagedSetWallpaperErrorDialogFragment = dialogFragment;
1126 }
1127 }
1128
chihhangchuang3efb6832020-04-17 02:06:25 +08001129 @Override
1130 public BottomActionBar getBottomActionBar() {
1131 return findViewById(R.id.bottom_actionbar);
1132 }
1133
Jon Miranda16ea1b12017-12-12 14:52:48 -08001134 private interface AssetReceiver {
1135 void onAssetReceived(Asset asset);
1136 }
1137
1138 /**
1139 * An AsyncTask for asynchronously fetching the thumbnail asset for a given WallpaperInfo.
1140 * Used to work around expensive method call to WallpaperManager#getWallpaperFile made from the
1141 * CurrentWallpaperInfoVN getAsset() method.
1142 */
1143 private static class FetchThumbAssetTask extends AsyncTask<Void, Void, Asset> {
1144 private Context mAppContext;
1145 private WallpaperInfo mWallpaperInfo;
1146 private AssetReceiver mReceiver;
1147
1148 public FetchThumbAssetTask(Context appContext, WallpaperInfo wallpaperInfo,
1149 AssetReceiver receiver) {
1150 mAppContext = appContext;
1151 mWallpaperInfo = wallpaperInfo;
1152 mReceiver = receiver;
1153 }
1154
1155 @Override
1156 protected Asset doInBackground(Void... params) {
1157 return mWallpaperInfo.getThumbAsset(mAppContext);
1158 }
1159
1160 @Override
1161 protected void onPostExecute(Asset thumbAsset) {
1162 mReceiver.onAssetReceived(thumbAsset);
1163 }
1164 }
1165}