blob: 624e0d3a870046a16d10742f0b9c14ecbbb21233 [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.PorterDuff.Mode;
25import android.graphics.drawable.Drawable;
26import android.net.Uri;
27import android.os.AsyncTask;
28import android.os.Build.VERSION;
29import android.os.Build.VERSION_CODES;
30import android.os.Bundle;
Hyunyoung Song8077c862019-06-18 01:14:24 -040031import android.provider.Settings;
Jon Miranda16ea1b12017-12-12 14:52:48 -080032import android.util.Log;
33import android.view.View;
34import android.view.View.OnClickListener;
Santiago Etchebehere35891ea2019-07-26 15:21:42 -070035import android.view.WindowInsets;
Jon Miranda16ea1b12017-12-12 14:52:48 -080036import android.widget.Button;
37import android.widget.FrameLayout;
38import android.widget.ImageView;
39import android.widget.LinearLayout;
40import android.widget.TextView;
41
Santiago Etchebehere635e96f2018-12-04 18:31:34 -080042import androidx.annotation.NonNull;
43import androidx.annotation.Nullable;
44import androidx.appcompat.app.AlertDialog;
45import 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
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800172 @WallpaperSupportLevel int wallpaperSupportLevel = mDelegate.getWallpaperSupportLevel();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800173 if (wallpaperSupportLevel != WallpaperDisabledFragment.SUPPORTED_CAN_SET) {
Chuck Liao8ec38e02020-02-26 20:59:32 +0800174 setContentView(R.layout.activity_top_level_picker);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800175
176 FragmentManager fm = getSupportFragmentManager();
177 WallpaperDisabledFragment wallpaperDisabledFragment =
178 WallpaperDisabledFragment.newInstance(wallpaperSupportLevel);
179 fm.beginTransaction()
180 .add(R.id.fragment_container, wallpaperDisabledFragment)
181 .commit();
182 return;
183 }
184
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800185 if (mDelegate.getFormFactor() == FormFactorChecker.FORM_FACTOR_MOBILE) {
Ching-Sung Li5f689972019-05-20 17:16:57 +0800186 initializeMobile(true /* shouldForceRefresh */);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800187 } else { // DESKTOP
188 initializeDesktop(savedInstanceState);
189 }
190 }
191
192 @Override
193 protected void onResume() {
194 super.onResume();
Hyunyoung Song8077c862019-06-18 01:14:24 -0400195 boolean provisioned = Settings.Global.getInt(getContentResolver(),
196 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
197
198 mUserEventLogger.logResumed(provisioned, true);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800199 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one
200 // that was unable to be shown earlier when this fragment's hosting activity didn't allow
201 // committing fragment transactions.
202 if (mStagedSetWallpaperErrorDialogFragment != null) {
203 mStagedSetWallpaperErrorDialogFragment.show(
204 getSupportFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
205 mStagedSetWallpaperErrorDialogFragment = null;
206 }
207 }
208
209 @Override
Santiago Etchebeherebd536c62019-04-09 15:25:51 -0300210 protected void onStop() {
211 mUserEventLogger.logStopped();
212 super.onStop();
213 }
214
215 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800216 protected void onDestroy() {
217 super.onDestroy();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800218 mDelegate.cleanUp();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800219 if (mNetworkStatusListener != null) {
220 mNetworkStatusNotifier.unregisterListener(mNetworkStatusListener);
221 }
222
223 if (mRefreshWallpaperProgressDialog != null) {
224 mRefreshWallpaperProgressDialog.dismiss();
225 }
226 if (mSetWallpaperProgressDialog != null) {
227 mSetWallpaperProgressDialog.dismiss();
228 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800229 }
230
231 @Override
Chuck Liaob1f1a3a2020-02-17 19:46:14 +0800232 public void onBackPressed() {
Chuck Liaof24418e2020-05-10 02:29:44 +0800233 Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
234 if (fragment instanceof BottomActionBarFragment
235 && ((BottomActionBarFragment) fragment).onBackPressed()) {
236 return;
237 }
238
Chuck Liaob1f1a3a2020-02-17 19:46:14 +0800239 CategoryFragment categoryFragment = getCategoryFragment();
240 if (categoryFragment != null && categoryFragment.popChildFragment()) {
241 return;
242 }
243 super.onBackPressed();
244 }
245
246 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800247 public void requestCustomPhotoPicker(PermissionChangedListener listener) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800248 mDelegate.requestCustomPhotoPicker(listener);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800249 }
250
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800251 @Override
252 public void requestExternalStoragePermission(PermissionChangedListener listener) {
253 mDelegate.requestExternalStoragePermission(listener);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800254 }
255
256 /**
257 * Returns whether READ_EXTERNAL_STORAGE has been granted for the application.
258 */
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800259 public boolean isReadExternalStoragePermissionGranted() {
260 return mDelegate.isReadExternalStoragePermissionGranted();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800261 }
262
Ching-Sung Li5f689972019-05-20 17:16:57 +0800263 private void initializeMobile(boolean shouldForceRefresh) {
Chuck Liao8ec38e02020-02-26 20:59:32 +0800264 setContentView(R.layout.activity_top_level_picker);
Santiago Etchebehere35891ea2019-07-26 15:21:42 -0700265 getWindow().getDecorView().setSystemUiVisibility(
266 getWindow().getDecorView().getSystemUiVisibility()
267 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
268 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
Chuck Liao829d4d22020-05-07 17:00:10 +0800269 View fragmentContainer = findViewById(R.id.fragment_container);
270 fragmentContainer.setOnApplyWindowInsetsListener((view, windowInsets) -> {
Santiago Etchebehere35891ea2019-07-26 15:21:42 -0700271 view.setPadding(view.getPaddingLeft(), windowInsets.getSystemWindowInsetTop(),
Chuck Liaoe9d79812020-02-20 18:03:55 +0800272 view.getPaddingRight(), view.getPaddingBottom());
Santiago Etchebehere35891ea2019-07-26 15:21:42 -0700273 // Consume only the top inset (status bar), to let other content in the Activity consume
274 // the nav bar (ie, by using "fitSystemWindows")
275 if (BuildCompat.isAtLeastQ()) {
276 WindowInsets.Builder builder = new WindowInsets.Builder(windowInsets);
277 builder.setSystemWindowInsets(Insets.of(windowInsets.getSystemWindowInsetLeft(),
278 0, windowInsets.getStableInsetRight(),
279 windowInsets.getSystemWindowInsetBottom()));
280 return builder.build();
281 } else {
282 return windowInsets.replaceSystemWindowInsets(
283 windowInsets.getSystemWindowInsetLeft(),
284 0, windowInsets.getStableInsetRight(),
285 windowInsets.getSystemWindowInsetBottom());
286 }
287 });
Jon Miranda16ea1b12017-12-12 14:52:48 -0800288
Chuck Liao829d4d22020-05-07 17:00:10 +0800289 FrameLayout.LayoutParams layoutParams =
290 (FrameLayout.LayoutParams) fragmentContainer.getLayoutParams();
291 int bottomActionBarHeight = getResources()
292 .getDimensionPixelSize(R.dimen.bottom_navbar_height);
293 BottomActionBar bottomActionBar = findViewById(R.id.bottom_actionbar);
294 bottomActionBar.addVisibilityChangeListener(isVisible -> {
295 if (layoutParams != null) {
296 layoutParams.bottomMargin = isVisible ? bottomActionBarHeight : 0;
297 }
298 });
299
Jon Miranda16ea1b12017-12-12 14:52:48 -0800300 // Set toolbar as the action bar.
301 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
302 setSupportActionBar(toolbar);
303
304 FragmentManager fm = getSupportFragmentManager();
305 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
306
Jon Miranda16ea1b12017-12-12 14:52:48 -0800307 if (fragment == null) {
308 // App launch specific logic: log the "app launched" event and set up daily logging.
309 mUserEventLogger.logAppLaunched();
Kunhung Li166842e2020-05-13 19:19:06 +0800310 mWallpaperPreferences.incrementAppLaunched();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800311 DailyLoggingAlarmScheduler.setAlarm(getApplicationContext());
312
Santiago Etchebehereaa35e6e2019-01-25 10:30:11 -0800313 CategoryFragment newFragment = CategoryFragment.newInstance(
314 getString(R.string.wallpaper_app_name));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800315 fm.beginTransaction()
316 .add(R.id.fragment_container, newFragment)
317 .commit();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800318 }
319
Ching-Sung Li5f689972019-05-20 17:16:57 +0800320 mDelegate.initialize(shouldForceRefresh);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800321 }
322
323 private void initializeDesktop(Bundle savedInstanceState) {
324 setContentView(R.layout.activity_top_level_desktop);
325
326 mBottomSheet = (LinearLayout) findViewById(R.id.bottom_sheet);
327 mCurrentWallpaperImage = (ImageView) mBottomSheet.findViewById(R.id.current_wallpaper_image);
328 mCurrentWallpaperImage.getLayoutParams().width = getSingleWallpaperImageWidthPx();
329
330 mCurrentWallpaperPresentationMode =
331 (TextView) mBottomSheet.findViewById(R.id.current_wallpaper_presentation_mode);
332 mCurrentWallpaperTitle = (TextView) findViewById(R.id.current_wallpaper_title);
333 mCurrentWallpaperSubtitle = (TextView) findViewById(R.id.current_wallpaper_subtitle);
334 mCurrentWallpaperExploreButton = (Button) findViewById(
335 R.id.current_wallpaper_explore_button);
336 mCurrentWallpaperSkipWallpaperButton = (Button) findViewById(
337 R.id.current_wallpaper_skip_wallpaper_button);
338 mFragmentContainer = (FrameLayout) findViewById(R.id.fragment_container);
339 mLoadingIndicatorContainer = (FrameLayout) findViewById(R.id.loading_indicator_container);
340 mWallpaperPositionOptions = (LinearLayout) findViewById(
341 R.id.desktop_wallpaper_position_options);
342
343 final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
344 tabLayout.addOnTabSelectedListener(new OnTabSelectedListener() {
345 @Override
346 public void onTabSelected(Tab tab) {
347 Category category = (Category) tab.getTag();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800348 showCategoryDesktop(category.getCollectionId());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800349 mLastSelectedCategoryTabIndex = tabLayout.getSelectedTabPosition();
350 }
351
352 @Override
353 public void onTabUnselected(Tab tab) {
354 }
355
356 @Override
357 public void onTabReselected(Tab tab) {
358 Category category = (Category) tab.getTag();
359 // If offline, "My photos" may be the only visible category. In this case we want to allow
360 // re-selection so user can still select a photo as wallpaper while offline.
361 if (!category.isEnumerable()) {
362 onTabSelected(tab);
363 }
364 }
365 });
366
367 FragmentManager fm = getSupportFragmentManager();
368 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
369
370 if (fragment == null) {
371 // App launch specific logic: log the "app launched" event and set up daily logging.
372 mUserEventLogger.logAppLaunched();
Kunhung Li166842e2020-05-13 19:19:06 +0800373 mWallpaperPreferences.incrementAppLaunched();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800374 DailyLoggingAlarmScheduler.setAlarm(getApplicationContext());
375 }
376
377 mNetworkStatusListener = new NetworkStatusNotifier.Listener() {
378 @Override
379 public void onNetworkChanged(@NetworkStatus int networkStatus) {
380 initializeDesktopBasedOnNetwork(networkStatus, savedInstanceState);
381 }
382 };
383 // Upon registering a listener, the onNetworkChanged method is immediately called with the
384 // initial network status.
385 mNetworkStatusNotifier.registerListener(mNetworkStatusListener);
386 }
387
388 private void initializeDesktopBasedOnNetwork(@NetworkStatus int networkStatus,
389 Bundle savedInstanceState) {
390 if (networkStatus == NetworkStatusNotifier.NETWORK_CONNECTED) {
391 initializeDesktopOnline(savedInstanceState);
392 } else {
393 initializeDesktopOffline();
394 }
395 }
396
397 private void initializeDesktopOnline(Bundle savedInstanceState) {
398 FragmentManager fm = getSupportFragmentManager();
399 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
400
401 // Require a category refresh if this is the first load of the app or if the app is now
402 // returning online after having been offline.
403 boolean forceCategoryRefresh = fragment == null || fragment instanceof OfflineDesktopFragment;
404
405 if (fragment != null) {
406 fm.beginTransaction()
407 .remove(fragment)
408 .commit();
409 }
410
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800411 mLastSelectedCategoryTabIndex = savedInstanceState != null
Jon Miranda16ea1b12017-12-12 14:52:48 -0800412 ? savedInstanceState.getInt(KEY_SELECTED_CATEGORY_TAB) : -1;
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800413 mDelegate.populateCategories(forceCategoryRefresh);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800414
415 setDesktopLoading(true);
416 setUpBottomSheet();
417 refreshCurrentWallpapers(null /* refreshListener */);
418 }
419
420 private void initializeDesktopOffline() {
421 FragmentManager fm = getSupportFragmentManager();
422 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
423
424 if (fragment != null) {
425 fm.beginTransaction()
426 .remove(fragment)
427 .commit();
428 }
429 OfflineDesktopFragment newFragment = new OfflineDesktopFragment();
430 fm.beginTransaction()
431 .add(R.id.fragment_container, newFragment)
432 .commit();
433
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800434 // Reset the last selected category tab index to ensure the app doesn't try to reselect a
435 // tab for a category not yet repopulated.
Jon Miranda16ea1b12017-12-12 14:52:48 -0800436 mLastSelectedCategoryTabIndex = -1;
437
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800438 mDelegate.populateCategories(true /* forceCategoryRefresh */);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800439
440 setDesktopLoading(false);
441 setCurrentWallpapersExpanded(false);
442 }
443
444 /**
445 * Sets the status of the loading indicator overlay in desktop mode.
446 *
447 * @param loading Whether an indeterminate loading indicator is displayed in place of the main
448 * fragment.
449 */
450 private void setDesktopLoading(boolean loading) {
451 if (loading) {
452 mLoadingIndicatorContainer.setVisibility(View.VISIBLE);
453 mFragmentContainer.setVisibility(View.GONE);
454 } else {
455 mLoadingIndicatorContainer.setVisibility(View.GONE);
456 mFragmentContainer.setVisibility(View.VISIBLE);
457 }
458 }
459
460 /**
461 * Returns the width (in physical px) to use for the "currently set wallpaper" thumbnail.
462 */
463 private int getSingleWallpaperImageWidthPx() {
chihhangchuangc8442a72020-05-07 14:26:32 +0800464 final float screenAspectRatio =
465 ScreenSizeCalculator.getInstance().getScreenAspectRatio(this);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800466
467 int height = getResources().getDimensionPixelSize(
468 R.dimen.current_wallpaper_bottom_sheet_thumb_height);
chihhangchuangc8442a72020-05-07 14:26:32 +0800469 return (int) (height / screenAspectRatio);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800470 }
471
472 /**
473 * Enables and populates the "Currently set" wallpaper BottomSheet.
474 */
475 private void setUpBottomSheet() {
476 mBottomSheet.setVisibility(View.VISIBLE);
477
Jon Miranda16ea1b12017-12-12 14:52:48 -0800478 if (Flags.skipDailyWallpaperButtonEnabled) {
479 // Add "next" icon to the Next Wallpaper button
480 Drawable nextWallpaperButtonDrawable = getResources().getDrawable(
Santiago Etchebehered24506c2018-04-05 17:02:42 -0700481 R.drawable.ic_refresh_18px);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800482
483 // This Drawable's state is shared across the app, so make a copy of it before applying a
484 // color tint as not to affect other clients elsewhere in the app.
485 nextWallpaperButtonDrawable =
486 nextWallpaperButtonDrawable.getConstantState().newDrawable().mutate();
487 // Color the "compass" icon with the accent color.
488 nextWallpaperButtonDrawable.setColorFilter(
489 getResources().getColor(R.color.accent_color), Mode.SRC_IN);
490 ButtonDrawableSetterCompat.setDrawableToButtonStart(
491 mCurrentWallpaperSkipWallpaperButton, nextWallpaperButtonDrawable);
492 }
493
494 final BottomSheetBehavior<LinearLayout> bottomSheetBehavior =
495 BottomSheetBehavior.from(mBottomSheet);
496 bottomSheetBehavior.setBottomSheetCallback(new BottomSheetCallback() {
497 @Override
498 public void onStateChanged(@NonNull View view, int i) {
499 }
500
501 @Override
502 public void onSlide(@NonNull View view, float slideOffset) {
503 float alpha;
504 if (slideOffset >= 0) {
505 alpha = slideOffset;
506 } else {
507 alpha = 1f - slideOffset;
508 }
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800509 LinearLayout bottomSheetContents = findViewById(R.id.bottom_sheet_contents);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800510 bottomSheetContents.setAlpha(alpha);
511 }
512 });
513 }
514
515 /**
516 * Enables a test mode of operation -- in which certain UI features are disabled to allow for
517 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog
518 * constantly keeps the UI thread alive and blocks a test forever.
519 */
520 void setTestingMode(boolean testingMode) {
521 mTestingMode = testingMode;
522 }
523
524 /**
525 * Obtains the {@link WallpaperInfo} object(s) representing the wallpaper(s) currently set to the
526 * device from the {@link CurrentWallpaperInfoFactory} and displays them in the BottomSheet.
527 */
528 @Override
529 public void refreshCurrentWallpapers(@Nullable RefreshListener refreshListener) {
530 final Injector injector = InjectorProvider.getInjector();
531 final Context appContext = getApplicationContext();
532
533 CurrentWallpaperInfoFactory factory = injector.getCurrentWallpaperFactory(this);
534 factory.createCurrentWallpaperInfos(new WallpaperInfoCallback() {
535 @Override
536 public void onWallpaperInfoCreated(
537 final WallpaperInfo homeWallpaper,
538 @Nullable final WallpaperInfo lockWallpaper,
539 @PresentationMode final int presentationMode) {
540
541 if (isDestroyed()) {
542 return;
543 }
544
545 // Fetch the home wallpaper's thumbnail asset asynchronously to work around expensive
546 // method call to WallpaperManager#getWallpaperFile made from the CurrentWallpaperInfoVN
547 // getAsset() method.
548 AssetReceiver assetReceiver = (Asset thumbAsset) -> {
549 if (isDestroyed()) {
550 return;
551 }
552
553 homeWallpaper.getThumbAsset(appContext).loadDrawableWithTransition(
554 TopLevelPickerActivity.this,
555 mCurrentWallpaperImage,
556 200 /* transitionDurationMillis */,
557 () -> {
558 if (refreshListener != null) {
559 refreshListener.onCurrentWallpaperRefreshed();
560 }
561 },
562 Color.TRANSPARENT);
563 };
564 new FetchThumbAssetTask(appContext, homeWallpaper, assetReceiver).executeOnExecutor(
565 AsyncTask.THREAD_POOL_EXECUTOR);
566
567 mCurrentWallpaperPresentationMode.setText(
568 AttributionFormatter.getHumanReadableWallpaperPresentationMode(
569 TopLevelPickerActivity.this, presentationMode));
570
571 List<String> attributions = homeWallpaper.getAttributions(appContext);
572 if (attributions.size() > 0 && attributions.get(0) != null) {
573 mCurrentWallpaperTitle.setText(attributions.get(0));
574 }
575
576 mCurrentWallpaperSubtitle.setText(
577 AttributionFormatter.formatWallpaperSubtitle(appContext, homeWallpaper));
578
579 final String actionUrl = homeWallpaper.getActionUrl(appContext);
580 if (actionUrl != null && !actionUrl.isEmpty()) {
581 Uri exploreUri = Uri.parse(actionUrl);
582
583 ExploreIntentChecker intentChecker = injector.getExploreIntentChecker(appContext);
584 intentChecker.fetchValidActionViewIntent(exploreUri, (@Nullable Intent exploreIntent) -> {
585 if (exploreIntent != null && !isDestroyed()) {
Santiago Etchebehered1bd5092018-04-18 16:03:30 -0700586 // Set the icon for the button
587 Drawable exploreButtonDrawable = getResources().getDrawable(
Santiago Etchebeheree0810d02018-05-10 17:39:40 -0700588 homeWallpaper.getActionIconRes(appContext));
Santiago Etchebehered1bd5092018-04-18 16:03:30 -0700589
590 // This Drawable's state is shared across the app, so make a copy of it
591 // before applying a color tint as not to affect other clients elsewhere
592 // in the app.
593 exploreButtonDrawable = exploreButtonDrawable.getConstantState()
594 .newDrawable().mutate();
595 // Color the "compass" icon with the accent color.
596 exploreButtonDrawable.setColorFilter(
597 getResources().getColor(R.color.accent_color), Mode.SRC_IN);
598
599 ButtonDrawableSetterCompat.setDrawableToButtonStart(
600 mCurrentWallpaperExploreButton, exploreButtonDrawable);
601 mCurrentWallpaperExploreButton.setText(getString(
Santiago Etchebeheree0810d02018-05-10 17:39:40 -0700602 homeWallpaper.getActionLabelRes(appContext)));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800603 mCurrentWallpaperExploreButton.setVisibility(View.VISIBLE);
604 mCurrentWallpaperExploreButton.setOnClickListener(new OnClickListener() {
605 @Override
606 public void onClick(View v) {
Santiago Etchebeherece5613f2018-06-01 13:22:47 -0700607 mUserEventLogger.logActionClicked(
608 homeWallpaper.getCollectionId(appContext),
609 homeWallpaper.getActionLabelRes(appContext));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800610 startActivity(exploreIntent);
611 }
612 });
613 }
614 });
615 } else {
616 mCurrentWallpaperExploreButton.setVisibility(View.GONE);
617 }
618
619 // Hide the wallpaper position options UI if the current home wallpaper is not from
620 // "my photos".
621 String homeCollectionId = homeWallpaper.getCollectionId(TopLevelPickerActivity.this);
622 if (mWallpaperPositionOptions != null
623 && homeCollectionId != null // May be null if app is being used for the first time.
624 && !homeCollectionId.equals(getString(R.string.image_wallpaper_collection_id))) {
625 mWallpaperPositionOptions.setVisibility(View.GONE);
626 }
627
628 boolean showSkipWallpaperButton = Flags.skipDailyWallpaperButtonEnabled
629 && presentationMode == WallpaperPreferences.PRESENTATION_MODE_ROTATING;
630 if (showSkipWallpaperButton) {
631 mCurrentWallpaperSkipWallpaperButton.setVisibility(View.VISIBLE);
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800632 mCurrentWallpaperSkipWallpaperButton.setOnClickListener(
633 v -> refreshDailyWallpaper());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800634 } else {
635 mCurrentWallpaperSkipWallpaperButton.setVisibility(View.GONE);
636 }
637
638 if (refreshListener != null) {
639 refreshListener.onCurrentWallpaperRefreshed();
640 }
641 }
642 }, true /* forceRefresh */);
643 }
644
645 @Override
646 public void onSaveInstanceState(Bundle savedInstanceState) {
647 FormFactorChecker formFactorChecker = InjectorProvider.getInjector().getFormFactorChecker(this);
648 if (formFactorChecker.getFormFactor() == FormFactorChecker.FORM_FACTOR_DESKTOP) {
649 TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
650
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800651 // tabLayout is only present when the main IndividualPickerFragment is present (as
652 // opposed to
Jon Miranda16ea1b12017-12-12 14:52:48 -0800653 // the WallpaperDisabledFragment), so need this null check.
654 if (tabLayout != null) {
655 savedInstanceState.putInt(KEY_SELECTED_CATEGORY_TAB, tabLayout.getSelectedTabPosition());
656 }
657 }
658
659 super.onSaveInstanceState(savedInstanceState);
660 }
661
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800662 @Override
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700663 @Nullable
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800664 public CategoryFragment getCategoryFragment() {
665 if (mDelegate.getFormFactor() != FormFactorChecker.FORM_FACTOR_MOBILE) {
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700666 return null;
667 }
668 FragmentManager fm = getSupportFragmentManager();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800669 return (CategoryFragment) fm.findFragmentById(R.id.fragment_container);
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700670 }
671
Jon Miranda16ea1b12017-12-12 14:52:48 -0800672 /**
673 * Populates the category tabs on DESKTOP form factor.
674 *
675 * @param selectedTabPosition The position of the tab to show as selected, or -1 if no particular
676 * tab should be selected (in which case: the tab of the category for the currently set
677 * wallpaper will be selected if enumerable; if not, the first enumerable category's tab will
678 * be selected).
679 */
680 private void populateCategoryTabs(int selectedTabPosition) {
681 final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
682 tabLayout.removeAllTabs();
683
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800684 String currentlySetCollectionId = mDelegate.getPreferences().getHomeWallpaperCollectionId();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800685
686 Tab tabToSelect = null;
687 Tab firstEnumerableCategoryTab = null;
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800688 for (int i = 0; i < mDelegate.getCategoryProvider().getSize(); i++) {
689 Category category = mDelegate.getCategoryProvider().getCategory(i);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800690
691 Tab tab = tabLayout.newTab();
692 tab.setText(category.getTitle());
693 tab.setTag(category);
694 tabLayout.addTab(tab, false /* setSelected */);
695
696 if (firstEnumerableCategoryTab == null && category.isEnumerable()) {
697 firstEnumerableCategoryTab = tab;
698 }
699
700 boolean shouldSelectTab = (i == selectedTabPosition)
701 || (selectedTabPosition == -1
702 && tabToSelect == null
703 && category.isEnumerable()
704 && currentlySetCollectionId != null
705 && currentlySetCollectionId.equals(category.getCollectionId()));
706
707 if (shouldSelectTab) {
708 tabToSelect = tab;
709 }
710 }
711
712 // If the above loop did not identify a specific tab to select, then just select the tab for
713 // the first enumerable category.
714 if (tabToSelect == null) {
715 tabToSelect = firstEnumerableCategoryTab;
716 }
717
718 // There may be no enumerable tabs (e.g., offline case), so we need to null-check again.
719 if (tabToSelect != null) {
720 tabToSelect.select();
721 }
722 }
723
724 /**
725 * Refreshes the current wallpaper in a daily wallpaper rotation.
726 */
727 private void refreshDailyWallpaper() {
728 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
729 // causes Espresso to hang once the dialog is shown.
730 if (!mTestingMode) {
731 int themeResId;
732 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
733 themeResId = R.style.ProgressDialogThemePreL;
734 } else {
735 themeResId = R.style.LightDialogTheme;
736 }
737 mRefreshWallpaperProgressDialog = new ProgressDialog(this, themeResId);
738 mRefreshWallpaperProgressDialog.setTitle(null);
739 mRefreshWallpaperProgressDialog.setMessage(
740 getResources().getString(R.string.refreshing_daily_wallpaper_dialog_message));
741 mRefreshWallpaperProgressDialog.setIndeterminate(true);
742 mRefreshWallpaperProgressDialog.show();
743 }
744
745 WallpaperRotationRefresher wallpaperRotationRefresher =
746 InjectorProvider.getInjector().getWallpaperRotationRefresher();
747 wallpaperRotationRefresher.refreshWallpaper(this, new Listener() {
748 @Override
749 public void onRefreshed() {
750 if (isDestroyed()) {
751 return;
752 }
753
754 if (mRefreshWallpaperProgressDialog != null) {
755 mRefreshWallpaperProgressDialog.dismiss();
756 }
757
758 refreshCurrentWallpapers(null /* refreshListener */);
759 }
760
761 @Override
762 public void onError() {
763 if (mRefreshWallpaperProgressDialog != null) {
764 mRefreshWallpaperProgressDialog.dismiss();
765 }
766
767 AlertDialog errorDialog = new AlertDialog.Builder(
768 TopLevelPickerActivity.this, R.style.LightDialogTheme)
769 .setMessage(R.string.refresh_daily_wallpaper_failed_message)
770 .setPositiveButton(android.R.string.ok, null /* onClickListener */)
771 .create();
772 errorDialog.show();
773 }
774 });
775 }
776
777 @Override
778 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
779 super.onActivityResult(requestCode, resultCode, data);
780
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800781 if (requestCode == WallpaperPickerDelegate.SHOW_CATEGORY_REQUEST_CODE
782 && resultCode == Activity.RESULT_OK) {
Santiago Etchebeheree5e05842019-02-13 16:58:07 -0800783 if (mDelegate.getFormFactor() == FormFactorChecker.FORM_FACTOR_DESKTOP) {
784 Uri imageUri = (data == null) ? null : data.getData();
785 if (imageUri != null) {
786 // User selected an image from the system picker, so launch the preview for that
787 // image.
788 ImageWallpaperInfo imageWallpaper = new ImageWallpaperInfo(imageUri);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800789 setCustomPhotoWallpaper(imageWallpaper);
790 return;
791 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800792 }
Santiago Etchebeheree5e05842019-02-13 16:58:07 -0800793 }
794 if (mDelegate.handleActivityResult(requestCode, resultCode, data)) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800795 finishActivityWithResultOk();
796 }
797 }
798
799 /**
800 * Shows the view-only preview activity for the given wallpaper.
801 */
802 public void showViewOnlyPreview(WallpaperInfo wallpaperInfo) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800803 mDelegate.showViewOnlyPreview(wallpaperInfo);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800804 }
805
806 @Override
807 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
808 @NonNull int[] grantResults) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800809 mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800810 }
811
Jon Miranda16ea1b12017-12-12 14:52:48 -0800812 private void reselectLastTab() {
813 TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
814
815 // In the offline case, "My photos" could be the only category. Thus we need this check --
816 // to ensure that we don't try to select the "previously selected" category which was -1.
817 if (mLastSelectedCategoryTabIndex > -1) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800818 Tab tabToSelect = tabLayout.getTabAt(
819 mLastSelectedCategoryTabIndex);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800820 if (((Category) tabToSelect.getTag()).isEnumerable()) {
821 tabToSelect.select();
822 }
823 }
824 }
825
Jon Miranda16ea1b12017-12-12 14:52:48 -0800826 private void showCategoryDesktop(String collectionId) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800827 Category category = mDelegate.findCategoryForCollectionId(collectionId);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800828 if (category == null) {
829 return;
830 }
831
832 if (category.isEnumerable()) {
833 // Replace contained IndividualPickerFragment with a new instance for the given category.
834 final FragmentManager fm = getSupportFragmentManager();
835 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
836 if (fragment != null) {
837 fm.beginTransaction()
838 .remove(fragment)
839 .commit();
840 }
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800841 Injector injector = InjectorProvider.getInjector();
842 IndividualPickerFragment newFragment = injector.getIndividualPickerFragment(
843 collectionId);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800844 fm.beginTransaction()
845 .add(R.id.fragment_container, newFragment)
846 .commit();
847 newFragment.setCurrentWallpaperBottomSheetPresenter(this);
848 newFragment.setWallpapersUiContainer(this);
849 } else {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800850 category.show(this, mDelegate.getPickerIntentFactory(),
851 WallpaperPickerDelegate.SHOW_CATEGORY_REQUEST_CODE);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800852
853 // Need to select the tab here in case we are coming back from a "My photos" in which case
854 // the tab would have been set to "My photos" while viewing a regular image category.
855 reselectLastTab();
856 }
857 }
858
859 private void finishActivityWithResultOk() {
860 overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
861 setResult(Activity.RESULT_OK);
862 finish();
863 }
864
Jon Miranda16ea1b12017-12-12 14:52:48 -0800865 @Override
866 public void setCurrentWallpapersExpanded(boolean expanded) {
867 final BottomSheetBehavior<LinearLayout> bottomSheetBehavior =
868 BottomSheetBehavior.from(mBottomSheet);
869 bottomSheetBehavior.setState(
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800870 expanded ? BottomSheetBehavior.STATE_EXPANDED
871 : BottomSheetBehavior.STATE_COLLAPSED);
872 }
873
874 @Override
875 public void doneFetchingCategories() {
876 populateCategoryTabs(mLastSelectedCategoryTabIndex);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800877 }
878
879 @Override
880 public void onWallpapersReady() {
881 setDesktopLoading(false);
882 setCurrentWallpapersExpanded(true);
883 }
884
885 @Override
Santiago Etchebeherefab49612019-01-15 12:22:42 -0800886 public MyPhotosStarter getMyPhotosStarter() {
887 return this;
888 }
889
890 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800891 public void onClickTryAgain(@Destination int unused) {
892 // Retry the set wallpaper operation with the default center-crop setting.
893 if (mPendingSetWallpaperInfo != null) {
894 setCustomPhotoWallpaper(mPendingSetWallpaperInfo);
895 }
896 }
897
898 /**
899 * Sets the provides wallpaper to the device with center-cropped and scaled to fit the device's
900 * default display.
901 */
902 private void setCustomPhotoWallpaper(final WallpaperInfo wallpaper) {
903 // Save this WallpaperInfo so we can retry this operation later if it fails.
904 mPendingSetWallpaperInfo = wallpaper;
905
906 showSettingWallpaperProgressDialog();
907
908 mWallpaperPersister.setIndividualWallpaperWithPosition(this, wallpaper,
909 WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP, new SetWallpaperCallback() {
910 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800911 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800912 dismissSettingWallpaperProgressDialog();
913 refreshCurrentWallpapers(null /* refreshListener */);
914
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800915 mDelegate.getPreferences().setPendingWallpaperSetStatus(
Jon Miranda16ea1b12017-12-12 14:52:48 -0800916 WallpaperPreferences.WALLPAPER_SET_NOT_PENDING);
917 mUserEventLogger.logWallpaperSet(
918 wallpaper.getCollectionId(getApplicationContext()),
919 wallpaper.getWallpaperId());
920 mUserEventLogger.logWallpaperSetResult(UserEventLogger.WALLPAPER_SET_RESULT_SUCCESS);
921
922 // The user may have closed the activity before the set wallpaper operation completed.
923 if (isDestroyed()) {
924 return;
925 }
926
927 // Show the wallpaper crop option selector and bind click event handlers.
928 mWallpaperPositionOptions.setVisibility(View.VISIBLE);
929
930 mWasCustomPhotoWallpaperSet = true;
931 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP;
932
933 initializeWallpaperPositionOptionClickHandlers(wallpaper);
934 }
935
936 @Override
937 public void onError(Throwable throwable) {
938 dismissSettingWallpaperProgressDialog();
939 showSetWallpaperErrorDialog();
940
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800941 mDelegate.getPreferences().setPendingWallpaperSetStatus(
Jon Miranda16ea1b12017-12-12 14:52:48 -0800942 WallpaperPreferences.WALLPAPER_SET_NOT_PENDING);
943 mUserEventLogger.logWallpaperSetResult(
944 UserEventLogger.WALLPAPER_SET_RESULT_FAILURE);
945 @WallpaperSetFailureReason int failureReason = ThrowableAnalyzer.isOOM(throwable)
946 ? UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OOM
947 : UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OTHER;
948 mUserEventLogger.logWallpaperSetFailureReason(failureReason);
949 Log.e(TAG, "Unable to set wallpaper from 'my photos'.");
950 }
951 });
952 }
953
954 /**
955 * Initializes the wallpaper position button click handlers to change the way the provided
956 * wallpaper is set to the device.
957 */
958 private void initializeWallpaperPositionOptionClickHandlers(final WallpaperInfo wallpaperInfo) {
959 Button centerCropOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_center_crop);
960 Button stretchOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_stretched);
961 Button centerOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_center);
962
963 // The "center crop" wallpaper position button is selected by default.
964 setCenterCropWallpaperPositionButtonSelected(centerCropOptionBtn, true /* isSelected */);
965 centerCropOptionBtn.setOnClickListener(new OnClickListener() {
966 @Override
967 public void onClick(View view) {
968 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
969 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP,
970 new SetWallpaperCallback() {
971 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800972 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800973 // The user may have closed the activity before the set wallpaper operation
974 // completed.
975 if (isDestroyed()) {
976 return;
977 }
978
979 refreshCurrentWallpapers(null /* refreshListener */);
980
981 setCenterCropWallpaperPositionButtonSelected(
982 centerCropOptionBtn, true /* isSelected */);
983 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
984 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
985
986 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP;
987 }
988
989 @Override
990 public void onError(@Nullable Throwable throwable) {
991 // no-op
992 }
993 });
994 }
995 });
996
997 // "Stretch" is not selected by default.
998 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
999 stretchOptionBtn.setOnClickListener(new OnClickListener() {
1000 @Override
1001 public void onClick(View view) {
1002 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
1003 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_STRETCH,
1004 new SetWallpaperCallback() {
1005 @Override
“Chuckffd832c2020-03-22 02:15:58 +08001006 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001007 // The user may have closed the activity before the set wallpaper operation
1008 // completed.
1009 if (isDestroyed()) {
1010 return;
1011 }
1012
1013 refreshCurrentWallpapers(null /* refreshListener */);
1014
1015 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, true /* isSelected */);
1016 setCenterCropWallpaperPositionButtonSelected(
1017 centerCropOptionBtn, false /* isSelected */);
1018 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
1019
1020 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_STRETCH;
1021 }
1022
1023 @Override
1024 public void onError(@Nullable Throwable throwable) {
1025 // no-op
1026 }
1027 });
1028 }
1029 });
1030
1031 // "Center" is not selected by default.
1032 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
1033 centerOptionBtn.setOnClickListener(new OnClickListener() {
1034 @Override
1035 public void onClick(View view) {
1036 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
1037 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_CENTER,
1038 new SetWallpaperCallback() {
1039 @Override
“Chuckffd832c2020-03-22 02:15:58 +08001040 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001041 // The user may have closed the activity before the set wallpaper operation
1042 // completed.
1043 if (isDestroyed()) {
1044 return;
1045 }
1046
1047 refreshCurrentWallpapers(null /* refreshListener */);
1048
1049 setCenterWallpaperPositionButtonSelected(centerOptionBtn, true /* isSelected */);
1050 setCenterCropWallpaperPositionButtonSelected(
1051 centerCropOptionBtn, false /* isSelected */);
1052 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
1053
1054 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER;
1055 }
1056
1057 @Override
1058 public void onError(@Nullable Throwable throwable) {
1059 // no-op
1060 }
1061 });
1062 }
1063 });
1064 }
1065
1066 private void setCenterWallpaperPositionButtonSelected(Button button, boolean isSelected) {
1067 int drawableId = isSelected ? R.drawable.center_blue : R.drawable.center_grey;
1068 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
1069 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
1070 }
1071
1072 private void setCenterCropWallpaperPositionButtonSelected(Button button, boolean isSelected) {
1073 int drawableId = isSelected ? R.drawable.center_crop_blue : R.drawable.center_crop_grey;
1074 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
1075 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
1076 }
1077
1078 private void setStretchWallpaperPositionButtonSelected(Button button, boolean isSelected) {
1079 int drawableId = isSelected ? R.drawable.stretch_blue : R.drawable.stretch_grey;
1080 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
1081 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
1082 }
1083
1084 private void showSettingWallpaperProgressDialog() {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -08001085 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which
1086 // therefore causes Espresso to hang once the dialog is shown.
Jon Miranda16ea1b12017-12-12 14:52:48 -08001087 if (!mTestingMode) {
1088 int themeResId;
1089 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
1090 themeResId = R.style.ProgressDialogThemePreL;
1091 } else {
1092 themeResId = R.style.LightDialogTheme;
1093 }
1094 mSetWallpaperProgressDialog = new ProgressDialog(this, themeResId);
1095 mSetWallpaperProgressDialog.setTitle(null);
1096 mSetWallpaperProgressDialog.setMessage(
1097 getResources().getString(R.string.set_wallpaper_progress_message));
1098 mSetWallpaperProgressDialog.setIndeterminate(true);
1099 mSetWallpaperProgressDialog.show();
1100 }
1101 }
1102
1103 private void dismissSettingWallpaperProgressDialog() {
1104 if (mSetWallpaperProgressDialog != null) {
1105 mSetWallpaperProgressDialog.dismiss();
1106 }
1107 }
1108
1109 private void showSetWallpaperErrorDialog() {
1110 SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance(
1111 R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH);
1112
1113 if (isSafeToCommitFragmentTransaction()) {
1114 dialogFragment.show(getSupportFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
1115 } else {
1116 mStagedSetWallpaperErrorDialogFragment = dialogFragment;
1117 }
1118 }
1119
chihhangchuang3efb6832020-04-17 02:06:25 +08001120 @Override
1121 public BottomActionBar getBottomActionBar() {
1122 return findViewById(R.id.bottom_actionbar);
1123 }
1124
Jon Miranda16ea1b12017-12-12 14:52:48 -08001125 private interface AssetReceiver {
1126 void onAssetReceived(Asset asset);
1127 }
1128
1129 /**
1130 * An AsyncTask for asynchronously fetching the thumbnail asset for a given WallpaperInfo.
1131 * Used to work around expensive method call to WallpaperManager#getWallpaperFile made from the
1132 * CurrentWallpaperInfoVN getAsset() method.
1133 */
1134 private static class FetchThumbAssetTask extends AsyncTask<Void, Void, Asset> {
1135 private Context mAppContext;
1136 private WallpaperInfo mWallpaperInfo;
1137 private AssetReceiver mReceiver;
1138
1139 public FetchThumbAssetTask(Context appContext, WallpaperInfo wallpaperInfo,
1140 AssetReceiver receiver) {
1141 mAppContext = appContext;
1142 mWallpaperInfo = wallpaperInfo;
1143 mReceiver = receiver;
1144 }
1145
1146 @Override
1147 protected Asset doInBackground(Void... params) {
1148 return mWallpaperInfo.getThumbAsset(mAppContext);
1149 }
1150
1151 @Override
1152 protected void onPostExecute(Asset thumbAsset) {
1153 mReceiver.onAssetReceived(thumbAsset);
1154 }
1155 }
1156}