blob: 482b77e7eddb629a3d97188aaf013aef426cbdd3 [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;
111 private boolean mWasCustomPhotoWallpaperSet;
112 @WallpaperPosition
113 private int mCustomPhotoWallpaperPosition;
114
115 /**
116 * Progress dialogs for "refresh daily wallpaper" and "set wallpaper" operations.
117 */
118 private ProgressDialog mRefreshWallpaperProgressDialog;
119 private ProgressDialog mSetWallpaperProgressDialog;
120
121 /**
122 * Designates a test mode of operation -- in which certain UI features are disabled to allow for
123 * UI tests to run correctly.
124 */
125 private boolean mTestingMode;
126
127 /**
128 * UI for the "currently set wallpaper" BottomSheet.
129 */
130 private LinearLayout mBottomSheet;
131 private ImageView mCurrentWallpaperImage;
132 private TextView mCurrentWallpaperPresentationMode;
133 private TextView mCurrentWallpaperTitle;
134 private TextView mCurrentWallpaperSubtitle;
135 private Button mCurrentWallpaperExploreButton;
136 private Button mCurrentWallpaperSkipWallpaperButton;
137 private FrameLayout mFragmentContainer;
138 private FrameLayout mLoadingIndicatorContainer;
139 private LinearLayout mWallpaperPositionOptions;
140
Jon Miranda16ea1b12017-12-12 14:52:48 -0800141 /**
142 * Staged error dialog fragments that were unable to be shown when the activity didn't allow
143 * committing fragment transactions.
144 */
145 private SetWallpaperErrorDialogFragment mStagedSetWallpaperErrorDialogFragment;
146
147 /**
148 * A wallpaper pending set to the device--we retain a reference to this in order to facilitate
149 * retry or re-crop operations.
150 */
151 private WallpaperInfo mPendingSetWallpaperInfo;
152
153 private static int getTextColorIdForWallpaperPositionButton(boolean isSelected) {
154 return isSelected ? R.color.accent_color : R.color.material_grey500;
155 }
156
157 @Override
158 protected void onCreate(Bundle savedInstanceState) {
159 super.onCreate(savedInstanceState);
160
Jon Miranda16ea1b12017-12-12 14:52:48 -0800161 mLastSelectedCategoryTabIndex = -1;
162
163 Injector injector = InjectorProvider.getInjector();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800164 mDelegate = new WallpaperPickerDelegate(this, this, injector);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800165 mUserEventLogger = injector.getUserEventLogger(this);
166 mNetworkStatusNotifier = injector.getNetworkStatusNotifier(this);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800167 mWallpaperPersister = injector.getWallpaperPersister(this);
168 mWasCustomPhotoWallpaperSet = false;
169
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800170 @WallpaperSupportLevel int wallpaperSupportLevel = mDelegate.getWallpaperSupportLevel();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800171 if (wallpaperSupportLevel != WallpaperDisabledFragment.SUPPORTED_CAN_SET) {
Chuck Liao8ec38e02020-02-26 20:59:32 +0800172 setContentView(R.layout.activity_top_level_picker);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800173
174 FragmentManager fm = getSupportFragmentManager();
175 WallpaperDisabledFragment wallpaperDisabledFragment =
176 WallpaperDisabledFragment.newInstance(wallpaperSupportLevel);
177 fm.beginTransaction()
178 .add(R.id.fragment_container, wallpaperDisabledFragment)
179 .commit();
180 return;
181 }
182
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800183 if (mDelegate.getFormFactor() == FormFactorChecker.FORM_FACTOR_MOBILE) {
Ching-Sung Li5f689972019-05-20 17:16:57 +0800184 initializeMobile(true /* shouldForceRefresh */);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800185 } else { // DESKTOP
186 initializeDesktop(savedInstanceState);
187 }
188 }
189
190 @Override
191 protected void onResume() {
192 super.onResume();
Hyunyoung Song8077c862019-06-18 01:14:24 -0400193 boolean provisioned = Settings.Global.getInt(getContentResolver(),
194 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
195
196 mUserEventLogger.logResumed(provisioned, true);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800197 // Show the staged 'load wallpaper' or 'set wallpaper' error dialog fragments if there is one
198 // that was unable to be shown earlier when this fragment's hosting activity didn't allow
199 // committing fragment transactions.
200 if (mStagedSetWallpaperErrorDialogFragment != null) {
201 mStagedSetWallpaperErrorDialogFragment.show(
202 getSupportFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
203 mStagedSetWallpaperErrorDialogFragment = null;
204 }
205 }
206
207 @Override
Santiago Etchebeherebd536c62019-04-09 15:25:51 -0300208 protected void onStop() {
209 mUserEventLogger.logStopped();
210 super.onStop();
211 }
212
213 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800214 protected void onDestroy() {
215 super.onDestroy();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800216 mDelegate.cleanUp();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800217 if (mNetworkStatusListener != null) {
218 mNetworkStatusNotifier.unregisterListener(mNetworkStatusListener);
219 }
220
221 if (mRefreshWallpaperProgressDialog != null) {
222 mRefreshWallpaperProgressDialog.dismiss();
223 }
224 if (mSetWallpaperProgressDialog != null) {
225 mSetWallpaperProgressDialog.dismiss();
226 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800227 }
228
229 @Override
Chuck Liaob1f1a3a2020-02-17 19:46:14 +0800230 public void onBackPressed() {
Chuck Liaof24418e2020-05-10 02:29:44 +0800231 Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
232 if (fragment instanceof BottomActionBarFragment
233 && ((BottomActionBarFragment) fragment).onBackPressed()) {
234 return;
235 }
236
Chuck Liaob1f1a3a2020-02-17 19:46:14 +0800237 CategoryFragment categoryFragment = getCategoryFragment();
238 if (categoryFragment != null && categoryFragment.popChildFragment()) {
239 return;
240 }
241 super.onBackPressed();
242 }
243
244 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800245 public void requestCustomPhotoPicker(PermissionChangedListener listener) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800246 mDelegate.requestCustomPhotoPicker(listener);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800247 }
248
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800249 @Override
250 public void requestExternalStoragePermission(PermissionChangedListener listener) {
251 mDelegate.requestExternalStoragePermission(listener);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800252 }
253
254 /**
255 * Returns whether READ_EXTERNAL_STORAGE has been granted for the application.
256 */
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800257 public boolean isReadExternalStoragePermissionGranted() {
258 return mDelegate.isReadExternalStoragePermissionGranted();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800259 }
260
Ching-Sung Li5f689972019-05-20 17:16:57 +0800261 private void initializeMobile(boolean shouldForceRefresh) {
Chuck Liao8ec38e02020-02-26 20:59:32 +0800262 setContentView(R.layout.activity_top_level_picker);
Santiago Etchebehere35891ea2019-07-26 15:21:42 -0700263 getWindow().getDecorView().setSystemUiVisibility(
264 getWindow().getDecorView().getSystemUiVisibility()
265 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
266 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
Chuck Liao829d4d22020-05-07 17:00:10 +0800267 View fragmentContainer = findViewById(R.id.fragment_container);
268 fragmentContainer.setOnApplyWindowInsetsListener((view, windowInsets) -> {
Santiago Etchebehere35891ea2019-07-26 15:21:42 -0700269 view.setPadding(view.getPaddingLeft(), windowInsets.getSystemWindowInsetTop(),
Chuck Liaoe9d79812020-02-20 18:03:55 +0800270 view.getPaddingRight(), view.getPaddingBottom());
Santiago Etchebehere35891ea2019-07-26 15:21:42 -0700271 // Consume only the top inset (status bar), to let other content in the Activity consume
272 // the nav bar (ie, by using "fitSystemWindows")
273 if (BuildCompat.isAtLeastQ()) {
274 WindowInsets.Builder builder = new WindowInsets.Builder(windowInsets);
275 builder.setSystemWindowInsets(Insets.of(windowInsets.getSystemWindowInsetLeft(),
276 0, windowInsets.getStableInsetRight(),
277 windowInsets.getSystemWindowInsetBottom()));
278 return builder.build();
279 } else {
280 return windowInsets.replaceSystemWindowInsets(
281 windowInsets.getSystemWindowInsetLeft(),
282 0, windowInsets.getStableInsetRight(),
283 windowInsets.getSystemWindowInsetBottom());
284 }
285 });
Jon Miranda16ea1b12017-12-12 14:52:48 -0800286
Chuck Liao829d4d22020-05-07 17:00:10 +0800287 FrameLayout.LayoutParams layoutParams =
288 (FrameLayout.LayoutParams) fragmentContainer.getLayoutParams();
289 int bottomActionBarHeight = getResources()
290 .getDimensionPixelSize(R.dimen.bottom_navbar_height);
291 BottomActionBar bottomActionBar = findViewById(R.id.bottom_actionbar);
292 bottomActionBar.addVisibilityChangeListener(isVisible -> {
293 if (layoutParams != null) {
294 layoutParams.bottomMargin = isVisible ? bottomActionBarHeight : 0;
295 }
296 });
297
Jon Miranda16ea1b12017-12-12 14:52:48 -0800298 // Set toolbar as the action bar.
299 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
300 setSupportActionBar(toolbar);
301
302 FragmentManager fm = getSupportFragmentManager();
303 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
304
Jon Miranda16ea1b12017-12-12 14:52:48 -0800305 if (fragment == null) {
306 // App launch specific logic: log the "app launched" event and set up daily logging.
307 mUserEventLogger.logAppLaunched();
308 DailyLoggingAlarmScheduler.setAlarm(getApplicationContext());
309
Santiago Etchebehereaa35e6e2019-01-25 10:30:11 -0800310 CategoryFragment newFragment = CategoryFragment.newInstance(
311 getString(R.string.wallpaper_app_name));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800312 fm.beginTransaction()
313 .add(R.id.fragment_container, newFragment)
314 .commit();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800315 }
316
Ching-Sung Li5f689972019-05-20 17:16:57 +0800317 mDelegate.initialize(shouldForceRefresh);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800318 }
319
320 private void initializeDesktop(Bundle savedInstanceState) {
321 setContentView(R.layout.activity_top_level_desktop);
322
323 mBottomSheet = (LinearLayout) findViewById(R.id.bottom_sheet);
324 mCurrentWallpaperImage = (ImageView) mBottomSheet.findViewById(R.id.current_wallpaper_image);
325 mCurrentWallpaperImage.getLayoutParams().width = getSingleWallpaperImageWidthPx();
326
327 mCurrentWallpaperPresentationMode =
328 (TextView) mBottomSheet.findViewById(R.id.current_wallpaper_presentation_mode);
329 mCurrentWallpaperTitle = (TextView) findViewById(R.id.current_wallpaper_title);
330 mCurrentWallpaperSubtitle = (TextView) findViewById(R.id.current_wallpaper_subtitle);
331 mCurrentWallpaperExploreButton = (Button) findViewById(
332 R.id.current_wallpaper_explore_button);
333 mCurrentWallpaperSkipWallpaperButton = (Button) findViewById(
334 R.id.current_wallpaper_skip_wallpaper_button);
335 mFragmentContainer = (FrameLayout) findViewById(R.id.fragment_container);
336 mLoadingIndicatorContainer = (FrameLayout) findViewById(R.id.loading_indicator_container);
337 mWallpaperPositionOptions = (LinearLayout) findViewById(
338 R.id.desktop_wallpaper_position_options);
339
340 final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
341 tabLayout.addOnTabSelectedListener(new OnTabSelectedListener() {
342 @Override
343 public void onTabSelected(Tab tab) {
344 Category category = (Category) tab.getTag();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800345 showCategoryDesktop(category.getCollectionId());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800346 mLastSelectedCategoryTabIndex = tabLayout.getSelectedTabPosition();
347 }
348
349 @Override
350 public void onTabUnselected(Tab tab) {
351 }
352
353 @Override
354 public void onTabReselected(Tab tab) {
355 Category category = (Category) tab.getTag();
356 // If offline, "My photos" may be the only visible category. In this case we want to allow
357 // re-selection so user can still select a photo as wallpaper while offline.
358 if (!category.isEnumerable()) {
359 onTabSelected(tab);
360 }
361 }
362 });
363
364 FragmentManager fm = getSupportFragmentManager();
365 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
366
367 if (fragment == null) {
368 // App launch specific logic: log the "app launched" event and set up daily logging.
369 mUserEventLogger.logAppLaunched();
370 DailyLoggingAlarmScheduler.setAlarm(getApplicationContext());
371 }
372
373 mNetworkStatusListener = new NetworkStatusNotifier.Listener() {
374 @Override
375 public void onNetworkChanged(@NetworkStatus int networkStatus) {
376 initializeDesktopBasedOnNetwork(networkStatus, savedInstanceState);
377 }
378 };
379 // Upon registering a listener, the onNetworkChanged method is immediately called with the
380 // initial network status.
381 mNetworkStatusNotifier.registerListener(mNetworkStatusListener);
382 }
383
384 private void initializeDesktopBasedOnNetwork(@NetworkStatus int networkStatus,
385 Bundle savedInstanceState) {
386 if (networkStatus == NetworkStatusNotifier.NETWORK_CONNECTED) {
387 initializeDesktopOnline(savedInstanceState);
388 } else {
389 initializeDesktopOffline();
390 }
391 }
392
393 private void initializeDesktopOnline(Bundle savedInstanceState) {
394 FragmentManager fm = getSupportFragmentManager();
395 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
396
397 // Require a category refresh if this is the first load of the app or if the app is now
398 // returning online after having been offline.
399 boolean forceCategoryRefresh = fragment == null || fragment instanceof OfflineDesktopFragment;
400
401 if (fragment != null) {
402 fm.beginTransaction()
403 .remove(fragment)
404 .commit();
405 }
406
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800407 mLastSelectedCategoryTabIndex = savedInstanceState != null
Jon Miranda16ea1b12017-12-12 14:52:48 -0800408 ? savedInstanceState.getInt(KEY_SELECTED_CATEGORY_TAB) : -1;
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800409 mDelegate.populateCategories(forceCategoryRefresh);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800410
411 setDesktopLoading(true);
412 setUpBottomSheet();
413 refreshCurrentWallpapers(null /* refreshListener */);
414 }
415
416 private void initializeDesktopOffline() {
417 FragmentManager fm = getSupportFragmentManager();
418 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
419
420 if (fragment != null) {
421 fm.beginTransaction()
422 .remove(fragment)
423 .commit();
424 }
425 OfflineDesktopFragment newFragment = new OfflineDesktopFragment();
426 fm.beginTransaction()
427 .add(R.id.fragment_container, newFragment)
428 .commit();
429
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800430 // Reset the last selected category tab index to ensure the app doesn't try to reselect a
431 // tab for a category not yet repopulated.
Jon Miranda16ea1b12017-12-12 14:52:48 -0800432 mLastSelectedCategoryTabIndex = -1;
433
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800434 mDelegate.populateCategories(true /* forceCategoryRefresh */);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800435
436 setDesktopLoading(false);
437 setCurrentWallpapersExpanded(false);
438 }
439
440 /**
441 * Sets the status of the loading indicator overlay in desktop mode.
442 *
443 * @param loading Whether an indeterminate loading indicator is displayed in place of the main
444 * fragment.
445 */
446 private void setDesktopLoading(boolean loading) {
447 if (loading) {
448 mLoadingIndicatorContainer.setVisibility(View.VISIBLE);
449 mFragmentContainer.setVisibility(View.GONE);
450 } else {
451 mLoadingIndicatorContainer.setVisibility(View.GONE);
452 mFragmentContainer.setVisibility(View.VISIBLE);
453 }
454 }
455
456 /**
457 * Returns the width (in physical px) to use for the "currently set wallpaper" thumbnail.
458 */
459 private int getSingleWallpaperImageWidthPx() {
chihhangchuangc8442a72020-05-07 14:26:32 +0800460 final float screenAspectRatio =
461 ScreenSizeCalculator.getInstance().getScreenAspectRatio(this);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800462
463 int height = getResources().getDimensionPixelSize(
464 R.dimen.current_wallpaper_bottom_sheet_thumb_height);
chihhangchuangc8442a72020-05-07 14:26:32 +0800465 return (int) (height / screenAspectRatio);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800466 }
467
468 /**
469 * Enables and populates the "Currently set" wallpaper BottomSheet.
470 */
471 private void setUpBottomSheet() {
472 mBottomSheet.setVisibility(View.VISIBLE);
473
Jon Miranda16ea1b12017-12-12 14:52:48 -0800474 if (Flags.skipDailyWallpaperButtonEnabled) {
475 // Add "next" icon to the Next Wallpaper button
476 Drawable nextWallpaperButtonDrawable = getResources().getDrawable(
Santiago Etchebehered24506c2018-04-05 17:02:42 -0700477 R.drawable.ic_refresh_18px);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800478
479 // This Drawable's state is shared across the app, so make a copy of it before applying a
480 // color tint as not to affect other clients elsewhere in the app.
481 nextWallpaperButtonDrawable =
482 nextWallpaperButtonDrawable.getConstantState().newDrawable().mutate();
483 // Color the "compass" icon with the accent color.
484 nextWallpaperButtonDrawable.setColorFilter(
485 getResources().getColor(R.color.accent_color), Mode.SRC_IN);
486 ButtonDrawableSetterCompat.setDrawableToButtonStart(
487 mCurrentWallpaperSkipWallpaperButton, nextWallpaperButtonDrawable);
488 }
489
490 final BottomSheetBehavior<LinearLayout> bottomSheetBehavior =
491 BottomSheetBehavior.from(mBottomSheet);
492 bottomSheetBehavior.setBottomSheetCallback(new BottomSheetCallback() {
493 @Override
494 public void onStateChanged(@NonNull View view, int i) {
495 }
496
497 @Override
498 public void onSlide(@NonNull View view, float slideOffset) {
499 float alpha;
500 if (slideOffset >= 0) {
501 alpha = slideOffset;
502 } else {
503 alpha = 1f - slideOffset;
504 }
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800505 LinearLayout bottomSheetContents = findViewById(R.id.bottom_sheet_contents);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800506 bottomSheetContents.setAlpha(alpha);
507 }
508 });
509 }
510
511 /**
512 * Enables a test mode of operation -- in which certain UI features are disabled to allow for
513 * UI tests to run correctly. Works around issue in ProgressDialog currently where the dialog
514 * constantly keeps the UI thread alive and blocks a test forever.
515 */
516 void setTestingMode(boolean testingMode) {
517 mTestingMode = testingMode;
518 }
519
520 /**
521 * Obtains the {@link WallpaperInfo} object(s) representing the wallpaper(s) currently set to the
522 * device from the {@link CurrentWallpaperInfoFactory} and displays them in the BottomSheet.
523 */
524 @Override
525 public void refreshCurrentWallpapers(@Nullable RefreshListener refreshListener) {
526 final Injector injector = InjectorProvider.getInjector();
527 final Context appContext = getApplicationContext();
528
529 CurrentWallpaperInfoFactory factory = injector.getCurrentWallpaperFactory(this);
530 factory.createCurrentWallpaperInfos(new WallpaperInfoCallback() {
531 @Override
532 public void onWallpaperInfoCreated(
533 final WallpaperInfo homeWallpaper,
534 @Nullable final WallpaperInfo lockWallpaper,
535 @PresentationMode final int presentationMode) {
536
537 if (isDestroyed()) {
538 return;
539 }
540
541 // Fetch the home wallpaper's thumbnail asset asynchronously to work around expensive
542 // method call to WallpaperManager#getWallpaperFile made from the CurrentWallpaperInfoVN
543 // getAsset() method.
544 AssetReceiver assetReceiver = (Asset thumbAsset) -> {
545 if (isDestroyed()) {
546 return;
547 }
548
549 homeWallpaper.getThumbAsset(appContext).loadDrawableWithTransition(
550 TopLevelPickerActivity.this,
551 mCurrentWallpaperImage,
552 200 /* transitionDurationMillis */,
553 () -> {
554 if (refreshListener != null) {
555 refreshListener.onCurrentWallpaperRefreshed();
556 }
557 },
558 Color.TRANSPARENT);
559 };
560 new FetchThumbAssetTask(appContext, homeWallpaper, assetReceiver).executeOnExecutor(
561 AsyncTask.THREAD_POOL_EXECUTOR);
562
563 mCurrentWallpaperPresentationMode.setText(
564 AttributionFormatter.getHumanReadableWallpaperPresentationMode(
565 TopLevelPickerActivity.this, presentationMode));
566
567 List<String> attributions = homeWallpaper.getAttributions(appContext);
568 if (attributions.size() > 0 && attributions.get(0) != null) {
569 mCurrentWallpaperTitle.setText(attributions.get(0));
570 }
571
572 mCurrentWallpaperSubtitle.setText(
573 AttributionFormatter.formatWallpaperSubtitle(appContext, homeWallpaper));
574
575 final String actionUrl = homeWallpaper.getActionUrl(appContext);
576 if (actionUrl != null && !actionUrl.isEmpty()) {
577 Uri exploreUri = Uri.parse(actionUrl);
578
579 ExploreIntentChecker intentChecker = injector.getExploreIntentChecker(appContext);
580 intentChecker.fetchValidActionViewIntent(exploreUri, (@Nullable Intent exploreIntent) -> {
581 if (exploreIntent != null && !isDestroyed()) {
Santiago Etchebehered1bd5092018-04-18 16:03:30 -0700582 // Set the icon for the button
583 Drawable exploreButtonDrawable = getResources().getDrawable(
Santiago Etchebeheree0810d02018-05-10 17:39:40 -0700584 homeWallpaper.getActionIconRes(appContext));
Santiago Etchebehered1bd5092018-04-18 16:03:30 -0700585
586 // This Drawable's state is shared across the app, so make a copy of it
587 // before applying a color tint as not to affect other clients elsewhere
588 // in the app.
589 exploreButtonDrawable = exploreButtonDrawable.getConstantState()
590 .newDrawable().mutate();
591 // Color the "compass" icon with the accent color.
592 exploreButtonDrawable.setColorFilter(
593 getResources().getColor(R.color.accent_color), Mode.SRC_IN);
594
595 ButtonDrawableSetterCompat.setDrawableToButtonStart(
596 mCurrentWallpaperExploreButton, exploreButtonDrawable);
597 mCurrentWallpaperExploreButton.setText(getString(
Santiago Etchebeheree0810d02018-05-10 17:39:40 -0700598 homeWallpaper.getActionLabelRes(appContext)));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800599 mCurrentWallpaperExploreButton.setVisibility(View.VISIBLE);
600 mCurrentWallpaperExploreButton.setOnClickListener(new OnClickListener() {
601 @Override
602 public void onClick(View v) {
Santiago Etchebeherece5613f2018-06-01 13:22:47 -0700603 mUserEventLogger.logActionClicked(
604 homeWallpaper.getCollectionId(appContext),
605 homeWallpaper.getActionLabelRes(appContext));
Jon Miranda16ea1b12017-12-12 14:52:48 -0800606 startActivity(exploreIntent);
607 }
608 });
609 }
610 });
611 } else {
612 mCurrentWallpaperExploreButton.setVisibility(View.GONE);
613 }
614
615 // Hide the wallpaper position options UI if the current home wallpaper is not from
616 // "my photos".
617 String homeCollectionId = homeWallpaper.getCollectionId(TopLevelPickerActivity.this);
618 if (mWallpaperPositionOptions != null
619 && homeCollectionId != null // May be null if app is being used for the first time.
620 && !homeCollectionId.equals(getString(R.string.image_wallpaper_collection_id))) {
621 mWallpaperPositionOptions.setVisibility(View.GONE);
622 }
623
624 boolean showSkipWallpaperButton = Flags.skipDailyWallpaperButtonEnabled
625 && presentationMode == WallpaperPreferences.PRESENTATION_MODE_ROTATING;
626 if (showSkipWallpaperButton) {
627 mCurrentWallpaperSkipWallpaperButton.setVisibility(View.VISIBLE);
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800628 mCurrentWallpaperSkipWallpaperButton.setOnClickListener(
629 v -> refreshDailyWallpaper());
Jon Miranda16ea1b12017-12-12 14:52:48 -0800630 } else {
631 mCurrentWallpaperSkipWallpaperButton.setVisibility(View.GONE);
632 }
633
634 if (refreshListener != null) {
635 refreshListener.onCurrentWallpaperRefreshed();
636 }
637 }
638 }, true /* forceRefresh */);
639 }
640
641 @Override
642 public void onSaveInstanceState(Bundle savedInstanceState) {
643 FormFactorChecker formFactorChecker = InjectorProvider.getInjector().getFormFactorChecker(this);
644 if (formFactorChecker.getFormFactor() == FormFactorChecker.FORM_FACTOR_DESKTOP) {
645 TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
646
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800647 // tabLayout is only present when the main IndividualPickerFragment is present (as
648 // opposed to
Jon Miranda16ea1b12017-12-12 14:52:48 -0800649 // the WallpaperDisabledFragment), so need this null check.
650 if (tabLayout != null) {
651 savedInstanceState.putInt(KEY_SELECTED_CATEGORY_TAB, tabLayout.getSelectedTabPosition());
652 }
653 }
654
655 super.onSaveInstanceState(savedInstanceState);
656 }
657
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800658 @Override
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700659 @Nullable
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800660 public CategoryFragment getCategoryFragment() {
661 if (mDelegate.getFormFactor() != FormFactorChecker.FORM_FACTOR_MOBILE) {
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700662 return null;
663 }
664 FragmentManager fm = getSupportFragmentManager();
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800665 return (CategoryFragment) fm.findFragmentById(R.id.fragment_container);
Santiago Etchebehere1ee76a22018-05-15 15:02:24 -0700666 }
667
Jon Miranda16ea1b12017-12-12 14:52:48 -0800668 /**
669 * Populates the category tabs on DESKTOP form factor.
670 *
671 * @param selectedTabPosition The position of the tab to show as selected, or -1 if no particular
672 * tab should be selected (in which case: the tab of the category for the currently set
673 * wallpaper will be selected if enumerable; if not, the first enumerable category's tab will
674 * be selected).
675 */
676 private void populateCategoryTabs(int selectedTabPosition) {
677 final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
678 tabLayout.removeAllTabs();
679
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800680 String currentlySetCollectionId = mDelegate.getPreferences().getHomeWallpaperCollectionId();
Jon Miranda16ea1b12017-12-12 14:52:48 -0800681
682 Tab tabToSelect = null;
683 Tab firstEnumerableCategoryTab = null;
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800684 for (int i = 0; i < mDelegate.getCategoryProvider().getSize(); i++) {
685 Category category = mDelegate.getCategoryProvider().getCategory(i);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800686
687 Tab tab = tabLayout.newTab();
688 tab.setText(category.getTitle());
689 tab.setTag(category);
690 tabLayout.addTab(tab, false /* setSelected */);
691
692 if (firstEnumerableCategoryTab == null && category.isEnumerable()) {
693 firstEnumerableCategoryTab = tab;
694 }
695
696 boolean shouldSelectTab = (i == selectedTabPosition)
697 || (selectedTabPosition == -1
698 && tabToSelect == null
699 && category.isEnumerable()
700 && currentlySetCollectionId != null
701 && currentlySetCollectionId.equals(category.getCollectionId()));
702
703 if (shouldSelectTab) {
704 tabToSelect = tab;
705 }
706 }
707
708 // If the above loop did not identify a specific tab to select, then just select the tab for
709 // the first enumerable category.
710 if (tabToSelect == null) {
711 tabToSelect = firstEnumerableCategoryTab;
712 }
713
714 // There may be no enumerable tabs (e.g., offline case), so we need to null-check again.
715 if (tabToSelect != null) {
716 tabToSelect.select();
717 }
718 }
719
720 /**
721 * Refreshes the current wallpaper in a daily wallpaper rotation.
722 */
723 private void refreshDailyWallpaper() {
724 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which therefore
725 // causes Espresso to hang once the dialog is shown.
726 if (!mTestingMode) {
727 int themeResId;
728 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
729 themeResId = R.style.ProgressDialogThemePreL;
730 } else {
731 themeResId = R.style.LightDialogTheme;
732 }
733 mRefreshWallpaperProgressDialog = new ProgressDialog(this, themeResId);
734 mRefreshWallpaperProgressDialog.setTitle(null);
735 mRefreshWallpaperProgressDialog.setMessage(
736 getResources().getString(R.string.refreshing_daily_wallpaper_dialog_message));
737 mRefreshWallpaperProgressDialog.setIndeterminate(true);
738 mRefreshWallpaperProgressDialog.show();
739 }
740
741 WallpaperRotationRefresher wallpaperRotationRefresher =
742 InjectorProvider.getInjector().getWallpaperRotationRefresher();
743 wallpaperRotationRefresher.refreshWallpaper(this, new Listener() {
744 @Override
745 public void onRefreshed() {
746 if (isDestroyed()) {
747 return;
748 }
749
750 if (mRefreshWallpaperProgressDialog != null) {
751 mRefreshWallpaperProgressDialog.dismiss();
752 }
753
754 refreshCurrentWallpapers(null /* refreshListener */);
755 }
756
757 @Override
758 public void onError() {
759 if (mRefreshWallpaperProgressDialog != null) {
760 mRefreshWallpaperProgressDialog.dismiss();
761 }
762
763 AlertDialog errorDialog = new AlertDialog.Builder(
764 TopLevelPickerActivity.this, R.style.LightDialogTheme)
765 .setMessage(R.string.refresh_daily_wallpaper_failed_message)
766 .setPositiveButton(android.R.string.ok, null /* onClickListener */)
767 .create();
768 errorDialog.show();
769 }
770 });
771 }
772
773 @Override
774 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
775 super.onActivityResult(requestCode, resultCode, data);
776
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800777 if (requestCode == WallpaperPickerDelegate.SHOW_CATEGORY_REQUEST_CODE
778 && resultCode == Activity.RESULT_OK) {
Santiago Etchebeheree5e05842019-02-13 16:58:07 -0800779 if (mDelegate.getFormFactor() == FormFactorChecker.FORM_FACTOR_DESKTOP) {
780 Uri imageUri = (data == null) ? null : data.getData();
781 if (imageUri != null) {
782 // User selected an image from the system picker, so launch the preview for that
783 // image.
784 ImageWallpaperInfo imageWallpaper = new ImageWallpaperInfo(imageUri);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800785 setCustomPhotoWallpaper(imageWallpaper);
786 return;
787 }
Jon Miranda16ea1b12017-12-12 14:52:48 -0800788 }
Santiago Etchebeheree5e05842019-02-13 16:58:07 -0800789 }
790 if (mDelegate.handleActivityResult(requestCode, resultCode, data)) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800791 finishActivityWithResultOk();
792 }
793 }
794
795 /**
796 * Shows the view-only preview activity for the given wallpaper.
797 */
798 public void showViewOnlyPreview(WallpaperInfo wallpaperInfo) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800799 mDelegate.showViewOnlyPreview(wallpaperInfo);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800800 }
801
802 @Override
803 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
804 @NonNull int[] grantResults) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800805 mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800806 }
807
Jon Miranda16ea1b12017-12-12 14:52:48 -0800808 private void reselectLastTab() {
809 TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
810
811 // In the offline case, "My photos" could be the only category. Thus we need this check --
812 // to ensure that we don't try to select the "previously selected" category which was -1.
813 if (mLastSelectedCategoryTabIndex > -1) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800814 Tab tabToSelect = tabLayout.getTabAt(
815 mLastSelectedCategoryTabIndex);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800816 if (((Category) tabToSelect.getTag()).isEnumerable()) {
817 tabToSelect.select();
818 }
819 }
820 }
821
Jon Miranda16ea1b12017-12-12 14:52:48 -0800822 private void showCategoryDesktop(String collectionId) {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800823 Category category = mDelegate.findCategoryForCollectionId(collectionId);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800824 if (category == null) {
825 return;
826 }
827
828 if (category.isEnumerable()) {
829 // Replace contained IndividualPickerFragment with a new instance for the given category.
830 final FragmentManager fm = getSupportFragmentManager();
831 Fragment fragment = fm.findFragmentById(R.id.fragment_container);
832 if (fragment != null) {
833 fm.beginTransaction()
834 .remove(fragment)
835 .commit();
836 }
Ching-Sung Li31fbe5e2019-01-23 19:36:24 +0800837 Injector injector = InjectorProvider.getInjector();
838 IndividualPickerFragment newFragment = injector.getIndividualPickerFragment(
839 collectionId);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800840 fm.beginTransaction()
841 .add(R.id.fragment_container, newFragment)
842 .commit();
843 newFragment.setCurrentWallpaperBottomSheetPresenter(this);
844 newFragment.setWallpapersUiContainer(this);
845 } else {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800846 category.show(this, mDelegate.getPickerIntentFactory(),
847 WallpaperPickerDelegate.SHOW_CATEGORY_REQUEST_CODE);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800848
849 // Need to select the tab here in case we are coming back from a "My photos" in which case
850 // the tab would have been set to "My photos" while viewing a regular image category.
851 reselectLastTab();
852 }
853 }
854
855 private void finishActivityWithResultOk() {
856 overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
857 setResult(Activity.RESULT_OK);
858 finish();
859 }
860
Jon Miranda16ea1b12017-12-12 14:52:48 -0800861 @Override
862 public void setCurrentWallpapersExpanded(boolean expanded) {
863 final BottomSheetBehavior<LinearLayout> bottomSheetBehavior =
864 BottomSheetBehavior.from(mBottomSheet);
865 bottomSheetBehavior.setState(
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800866 expanded ? BottomSheetBehavior.STATE_EXPANDED
867 : BottomSheetBehavior.STATE_COLLAPSED);
868 }
869
870 @Override
871 public void doneFetchingCategories() {
872 populateCategoryTabs(mLastSelectedCategoryTabIndex);
Jon Miranda16ea1b12017-12-12 14:52:48 -0800873 }
874
875 @Override
876 public void onWallpapersReady() {
877 setDesktopLoading(false);
878 setCurrentWallpapersExpanded(true);
879 }
880
881 @Override
Santiago Etchebeherefab49612019-01-15 12:22:42 -0800882 public MyPhotosStarter getMyPhotosStarter() {
883 return this;
884 }
885
886 @Override
Jon Miranda16ea1b12017-12-12 14:52:48 -0800887 public void onClickTryAgain(@Destination int unused) {
888 // Retry the set wallpaper operation with the default center-crop setting.
889 if (mPendingSetWallpaperInfo != null) {
890 setCustomPhotoWallpaper(mPendingSetWallpaperInfo);
891 }
892 }
893
894 /**
895 * Sets the provides wallpaper to the device with center-cropped and scaled to fit the device's
896 * default display.
897 */
898 private void setCustomPhotoWallpaper(final WallpaperInfo wallpaper) {
899 // Save this WallpaperInfo so we can retry this operation later if it fails.
900 mPendingSetWallpaperInfo = wallpaper;
901
902 showSettingWallpaperProgressDialog();
903
904 mWallpaperPersister.setIndividualWallpaperWithPosition(this, wallpaper,
905 WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP, new SetWallpaperCallback() {
906 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800907 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800908 dismissSettingWallpaperProgressDialog();
909 refreshCurrentWallpapers(null /* refreshListener */);
910
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800911 mDelegate.getPreferences().setPendingWallpaperSetStatus(
Jon Miranda16ea1b12017-12-12 14:52:48 -0800912 WallpaperPreferences.WALLPAPER_SET_NOT_PENDING);
913 mUserEventLogger.logWallpaperSet(
914 wallpaper.getCollectionId(getApplicationContext()),
915 wallpaper.getWallpaperId());
916 mUserEventLogger.logWallpaperSetResult(UserEventLogger.WALLPAPER_SET_RESULT_SUCCESS);
917
918 // The user may have closed the activity before the set wallpaper operation completed.
919 if (isDestroyed()) {
920 return;
921 }
922
923 // Show the wallpaper crop option selector and bind click event handlers.
924 mWallpaperPositionOptions.setVisibility(View.VISIBLE);
925
926 mWasCustomPhotoWallpaperSet = true;
927 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP;
928
929 initializeWallpaperPositionOptionClickHandlers(wallpaper);
930 }
931
932 @Override
933 public void onError(Throwable throwable) {
934 dismissSettingWallpaperProgressDialog();
935 showSetWallpaperErrorDialog();
936
Santiago Etchebehere635e96f2018-12-04 18:31:34 -0800937 mDelegate.getPreferences().setPendingWallpaperSetStatus(
Jon Miranda16ea1b12017-12-12 14:52:48 -0800938 WallpaperPreferences.WALLPAPER_SET_NOT_PENDING);
939 mUserEventLogger.logWallpaperSetResult(
940 UserEventLogger.WALLPAPER_SET_RESULT_FAILURE);
941 @WallpaperSetFailureReason int failureReason = ThrowableAnalyzer.isOOM(throwable)
942 ? UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OOM
943 : UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OTHER;
944 mUserEventLogger.logWallpaperSetFailureReason(failureReason);
945 Log.e(TAG, "Unable to set wallpaper from 'my photos'.");
946 }
947 });
948 }
949
950 /**
951 * Initializes the wallpaper position button click handlers to change the way the provided
952 * wallpaper is set to the device.
953 */
954 private void initializeWallpaperPositionOptionClickHandlers(final WallpaperInfo wallpaperInfo) {
955 Button centerCropOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_center_crop);
956 Button stretchOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_stretched);
957 Button centerOptionBtn = (Button) findViewById(R.id.wallpaper_position_option_center);
958
959 // The "center crop" wallpaper position button is selected by default.
960 setCenterCropWallpaperPositionButtonSelected(centerCropOptionBtn, true /* isSelected */);
961 centerCropOptionBtn.setOnClickListener(new OnClickListener() {
962 @Override
963 public void onClick(View view) {
964 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
965 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP,
966 new SetWallpaperCallback() {
967 @Override
“Chuckffd832c2020-03-22 02:15:58 +0800968 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -0800969 // The user may have closed the activity before the set wallpaper operation
970 // completed.
971 if (isDestroyed()) {
972 return;
973 }
974
975 refreshCurrentWallpapers(null /* refreshListener */);
976
977 setCenterCropWallpaperPositionButtonSelected(
978 centerCropOptionBtn, true /* isSelected */);
979 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
980 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
981
982 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER_CROP;
983 }
984
985 @Override
986 public void onError(@Nullable Throwable throwable) {
987 // no-op
988 }
989 });
990 }
991 });
992
993 // "Stretch" is not selected by default.
994 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
995 stretchOptionBtn.setOnClickListener(new OnClickListener() {
996 @Override
997 public void onClick(View view) {
998 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
999 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_STRETCH,
1000 new SetWallpaperCallback() {
1001 @Override
“Chuckffd832c2020-03-22 02:15:58 +08001002 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001003 // The user may have closed the activity before the set wallpaper operation
1004 // completed.
1005 if (isDestroyed()) {
1006 return;
1007 }
1008
1009 refreshCurrentWallpapers(null /* refreshListener */);
1010
1011 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, true /* isSelected */);
1012 setCenterCropWallpaperPositionButtonSelected(
1013 centerCropOptionBtn, false /* isSelected */);
1014 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
1015
1016 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_STRETCH;
1017 }
1018
1019 @Override
1020 public void onError(@Nullable Throwable throwable) {
1021 // no-op
1022 }
1023 });
1024 }
1025 });
1026
1027 // "Center" is not selected by default.
1028 setCenterWallpaperPositionButtonSelected(centerOptionBtn, false /* isSelected */);
1029 centerOptionBtn.setOnClickListener(new OnClickListener() {
1030 @Override
1031 public void onClick(View view) {
1032 mWallpaperPersister.setIndividualWallpaperWithPosition(TopLevelPickerActivity.this,
1033 wallpaperInfo, WallpaperPersister.WALLPAPER_POSITION_CENTER,
1034 new SetWallpaperCallback() {
1035 @Override
“Chuckffd832c2020-03-22 02:15:58 +08001036 public void onSuccess(WallpaperInfo wallpaperInfo) {
Jon Miranda16ea1b12017-12-12 14:52:48 -08001037 // The user may have closed the activity before the set wallpaper operation
1038 // completed.
1039 if (isDestroyed()) {
1040 return;
1041 }
1042
1043 refreshCurrentWallpapers(null /* refreshListener */);
1044
1045 setCenterWallpaperPositionButtonSelected(centerOptionBtn, true /* isSelected */);
1046 setCenterCropWallpaperPositionButtonSelected(
1047 centerCropOptionBtn, false /* isSelected */);
1048 setStretchWallpaperPositionButtonSelected(stretchOptionBtn, false /* isSelected */);
1049
1050 mCustomPhotoWallpaperPosition = WallpaperPersister.WALLPAPER_POSITION_CENTER;
1051 }
1052
1053 @Override
1054 public void onError(@Nullable Throwable throwable) {
1055 // no-op
1056 }
1057 });
1058 }
1059 });
1060 }
1061
1062 private void setCenterWallpaperPositionButtonSelected(Button button, boolean isSelected) {
1063 int drawableId = isSelected ? R.drawable.center_blue : R.drawable.center_grey;
1064 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
1065 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
1066 }
1067
1068 private void setCenterCropWallpaperPositionButtonSelected(Button button, boolean isSelected) {
1069 int drawableId = isSelected ? R.drawable.center_crop_blue : R.drawable.center_crop_grey;
1070 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
1071 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
1072 }
1073
1074 private void setStretchWallpaperPositionButtonSelected(Button button, boolean isSelected) {
1075 int drawableId = isSelected ? R.drawable.stretch_blue : R.drawable.stretch_grey;
1076 ButtonDrawableSetterCompat.setDrawableToButtonStart(button, getDrawable(drawableId));
1077 button.setTextColor(getColor(getTextColorIdForWallpaperPositionButton(isSelected)));
1078 }
1079
1080 private void showSettingWallpaperProgressDialog() {
Santiago Etchebehere635e96f2018-12-04 18:31:34 -08001081 // ProgressDialog endlessly updates the UI thread, keeping it from going idle which
1082 // therefore causes Espresso to hang once the dialog is shown.
Jon Miranda16ea1b12017-12-12 14:52:48 -08001083 if (!mTestingMode) {
1084 int themeResId;
1085 if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
1086 themeResId = R.style.ProgressDialogThemePreL;
1087 } else {
1088 themeResId = R.style.LightDialogTheme;
1089 }
1090 mSetWallpaperProgressDialog = new ProgressDialog(this, themeResId);
1091 mSetWallpaperProgressDialog.setTitle(null);
1092 mSetWallpaperProgressDialog.setMessage(
1093 getResources().getString(R.string.set_wallpaper_progress_message));
1094 mSetWallpaperProgressDialog.setIndeterminate(true);
1095 mSetWallpaperProgressDialog.show();
1096 }
1097 }
1098
1099 private void dismissSettingWallpaperProgressDialog() {
1100 if (mSetWallpaperProgressDialog != null) {
1101 mSetWallpaperProgressDialog.dismiss();
1102 }
1103 }
1104
1105 private void showSetWallpaperErrorDialog() {
1106 SetWallpaperErrorDialogFragment dialogFragment = SetWallpaperErrorDialogFragment.newInstance(
1107 R.string.set_wallpaper_error_message, WallpaperPersister.DEST_BOTH);
1108
1109 if (isSafeToCommitFragmentTransaction()) {
1110 dialogFragment.show(getSupportFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
1111 } else {
1112 mStagedSetWallpaperErrorDialogFragment = dialogFragment;
1113 }
1114 }
1115
chihhangchuang3efb6832020-04-17 02:06:25 +08001116 @Override
1117 public BottomActionBar getBottomActionBar() {
1118 return findViewById(R.id.bottom_actionbar);
1119 }
1120
Jon Miranda16ea1b12017-12-12 14:52:48 -08001121 private interface AssetReceiver {
1122 void onAssetReceived(Asset asset);
1123 }
1124
1125 /**
1126 * An AsyncTask for asynchronously fetching the thumbnail asset for a given WallpaperInfo.
1127 * Used to work around expensive method call to WallpaperManager#getWallpaperFile made from the
1128 * CurrentWallpaperInfoVN getAsset() method.
1129 */
1130 private static class FetchThumbAssetTask extends AsyncTask<Void, Void, Asset> {
1131 private Context mAppContext;
1132 private WallpaperInfo mWallpaperInfo;
1133 private AssetReceiver mReceiver;
1134
1135 public FetchThumbAssetTask(Context appContext, WallpaperInfo wallpaperInfo,
1136 AssetReceiver receiver) {
1137 mAppContext = appContext;
1138 mWallpaperInfo = wallpaperInfo;
1139 mReceiver = receiver;
1140 }
1141
1142 @Override
1143 protected Asset doInBackground(Void... params) {
1144 return mWallpaperInfo.getThumbAsset(mAppContext);
1145 }
1146
1147 @Override
1148 protected void onPostExecute(Asset thumbAsset) {
1149 mReceiver.onAssetReceived(thumbAsset);
1150 }
1151 }
1152}