• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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  */
16 package com.android.wallpaper.picker;
17 
18 import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
19 import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
20 
21 import static com.android.wallpaper.widget.BottomActionBar.BottomAction.APPLY;
22 import static com.android.wallpaper.widget.BottomActionBar.BottomAction.CUSTOMIZE;
23 import static com.android.wallpaper.widget.BottomActionBar.BottomAction.DELETE;
24 import static com.android.wallpaper.widget.BottomActionBar.BottomAction.EDIT;
25 import static com.android.wallpaper.widget.BottomActionBar.BottomAction.INFORMATION;
26 
27 import android.annotation.SuppressLint;
28 import android.app.Activity;
29 import android.app.AlertDialog;
30 import android.app.WallpaperColors;
31 import android.app.WallpaperInfo;
32 import android.app.WallpaperManager;
33 import android.content.ComponentName;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.pm.ActivityInfo;
37 import android.content.pm.ApplicationInfo;
38 import android.content.pm.PackageManager;
39 import android.content.pm.ServiceInfo;
40 import android.graphics.Color;
41 import android.graphics.Point;
42 import android.net.Uri;
43 import android.os.Build;
44 import android.os.Bundle;
45 import android.os.RemoteException;
46 import android.service.wallpaper.IWallpaperConnection;
47 import android.service.wallpaper.WallpaperService;
48 import android.service.wallpaper.WallpaperSettingsActivity;
49 import android.text.TextUtils;
50 import android.util.Log;
51 import android.view.LayoutInflater;
52 import android.view.MotionEvent;
53 import android.view.SurfaceView;
54 import android.view.View;
55 import android.view.ViewGroup;
56 import android.widget.ImageView;
57 
58 import androidx.annotation.NonNull;
59 import androidx.annotation.Nullable;
60 import androidx.cardview.widget.CardView;
61 import androidx.constraintlayout.widget.ConstraintLayout;
62 import androidx.constraintlayout.widget.ConstraintSet;
63 import androidx.lifecycle.LiveData;
64 import androidx.slice.Slice;
65 import androidx.slice.widget.SliceLiveData;
66 import androidx.slice.widget.SliceView;
67 
68 import com.android.wallpaper.R;
69 import com.android.wallpaper.model.SetWallpaperViewModel;
70 import com.android.wallpaper.model.WallpaperInfo.ColorInfo;
71 import com.android.wallpaper.module.LargeScreenMultiPanesChecker;
72 import com.android.wallpaper.util.FullScreenAnimation;
73 import com.android.wallpaper.util.ResourceUtils;
74 import com.android.wallpaper.util.ScreenSizeCalculator;
75 import com.android.wallpaper.util.SizeCalculator;
76 import com.android.wallpaper.util.WallpaperConnection;
77 import com.android.wallpaper.util.WallpaperSurfaceCallback;
78 import com.android.wallpaper.widget.BottomActionBar;
79 import com.android.wallpaper.widget.BottomActionBar.AccessibilityCallback;
80 import com.android.wallpaper.widget.BottomActionBar.BottomSheetContent;
81 import com.android.wallpaper.widget.LockScreenPreviewer;
82 import com.android.wallpaper.widget.WallpaperColorsLoader;
83 
84 import java.util.Locale;
85 import java.util.concurrent.ExecutionException;
86 import java.util.concurrent.Future;
87 import java.util.concurrent.TimeUnit;
88 import java.util.concurrent.TimeoutException;
89 
90 /**
91  * Fragment which displays the UI for previewing an individual live wallpaper, its attribution
92  * information and settings slices if available.
93  */
94 public class LivePreviewFragment extends PreviewFragment implements
95         WallpaperConnection.WallpaperConnectionListener {
96 
97     public static final String EXTRA_LIVE_WALLPAPER_INFO = "android.live_wallpaper.info";
98     public static final String KEY_ACTION_DELETE_LIVE_WALLPAPER = "action_delete_live_wallpaper";
99 
100     private static final String TAG = "LivePreviewFragment";
101 
102     /**
103      * Instance of {@link WallpaperConnection} used to bind to the live wallpaper service to show
104      * it in this preview fragment.
105      * @see IWallpaperConnection
106      */
107     protected WallpaperConnection mWallpaperConnection;
108     protected CardView mHomePreviewCard;
109     protected SurfaceView mWorkspaceSurface;
110     protected WallpaperSurfaceCallback mWallpaperSurfaceCallback;
111     protected WorkspaceSurfaceHolderCallback mWorkspaceSurfaceCallback;
112     protected ViewGroup mLockPreviewContainer;
113     protected LockScreenPreviewer mLockScreenPreviewer;
114 
115     private Intent mDeleteIntent;
116     private Intent mSettingsIntent;
117     private SliceView mSettingsSliceView;
118     private LiveData<Slice> mSettingsLiveData;
119     private Point mScreenSize;
120     private ViewGroup mPreviewContainer;
121     private TouchForwardingLayout mTouchForwardingLayout;
122     private SurfaceView mWallpaperSurface;
123     private Future<ColorInfo> mColorFuture;
124     private WallpaperColors mWallpaperColors;
125 
126     @Override
onCreate(Bundle savedInstanceState)127     public void onCreate(Bundle savedInstanceState) {
128         super.onCreate(savedInstanceState);
129         android.app.WallpaperInfo info = mWallpaper.getWallpaperComponent();
130         mColorFuture = mWallpaper.computeColorInfo(getContext());
131 
132         String deleteAction = getDeleteAction(info);
133         if (!TextUtils.isEmpty(deleteAction)) {
134             mDeleteIntent = new Intent(deleteAction);
135             mDeleteIntent.setPackage(info.getPackageName());
136             mDeleteIntent.putExtra(EXTRA_LIVE_WALLPAPER_INFO, info);
137         }
138         String settingsActivity = getSettingsActivity(info);
139         if (settingsActivity != null) {
140             mSettingsIntent = new Intent();
141             mSettingsIntent.setComponent(new ComponentName(info.getPackageName(),
142                     settingsActivity));
143             mSettingsIntent.putExtra(WallpaperSettingsActivity.EXTRA_PREVIEW_MODE, true);
144             PackageManager pm = requireContext().getPackageManager();
145             ActivityInfo activityInfo = mSettingsIntent.resolveActivityInfo(pm, 0);
146             if (activityInfo == null) {
147                 Log.i(TAG, "Couldn't find wallpaper settings activity: " + settingsActivity);
148                 mSettingsIntent = null;
149             }
150         }
151     }
152 
153     @Nullable
getSettingsActivity(WallpaperInfo info)154     protected String getSettingsActivity(WallpaperInfo info) {
155         return info.getSettingsActivity();
156     }
157 
getWallpaperIntent(WallpaperInfo info)158     protected Intent getWallpaperIntent(WallpaperInfo info) {
159         return new Intent(WallpaperService.SERVICE_INTERFACE)
160                 .setClassName(info.getPackageName(), info.getServiceName());
161     }
162 
163     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)164     public View onCreateView(LayoutInflater inflater, ViewGroup container,
165             Bundle savedInstanceState) {
166         View view = super.onCreateView(inflater, container, savedInstanceState);
167 
168         Activity activity = requireActivity();
169         mScreenSize = ScreenSizeCalculator.getInstance().getScreenSize(
170                 activity.getWindowManager().getDefaultDisplay());
171         mPreviewContainer = view.findViewById(R.id.container);
172         mTouchForwardingLayout = view.findViewById(R.id.touch_forwarding_layout);
173 
174         // Update preview header color which covers toolbar and status bar area.
175         updatePreviewHeader(view);
176 
177         // Set aspect ratio on the preview card.
178         ConstraintSet set = new ConstraintSet();
179         set.clone((ConstraintLayout) mPreviewContainer);
180         String ratio = String.format(Locale.US, "%d:%d", mScreenSize.x, mScreenSize.y);
181         set.setDimensionRatio(mTouchForwardingLayout.getId(), ratio);
182         set.applyTo((ConstraintLayout) mPreviewContainer);
183 
184         mHomePreviewCard = mPreviewContainer.findViewById(R.id.wallpaper_full_preview_card);
185         mLockPreviewContainer = mPreviewContainer.findViewById(R.id.lock_screen_preview_container);
186         mLockScreenPreviewer = new LockScreenPreviewer(getLifecycle(), getContext(),
187                 mLockPreviewContainer);
188         mLockScreenPreviewer.setDateViewVisibility(!mFullScreenAnimation.isFullScreen());
189         mFullScreenAnimation.setFullScreenStatusListener(
190                 isFullScreen -> {
191                     mLockScreenPreviewer.setDateViewVisibility(!isFullScreen);
192                     if (!isFullScreen) {
193                         mBottomActionBar.focusAccessibilityAction(EDIT);
194                     }
195                 });
196         mWallpaperSurface = mHomePreviewCard.findViewById(R.id.wallpaper_surface);
197         mTouchForwardingLayout.setTargetView(mHomePreviewCard);
198         mTouchForwardingLayout.setForwardingEnabled(true);
199         mWorkspaceSurface = mHomePreviewCard.findViewById(R.id.workspace_surface);
200 
201         mWorkspaceSurfaceCallback = createWorkspaceSurfaceCallback(mWorkspaceSurface);
202         mWallpaperSurfaceCallback = new WallpaperSurfaceCallback(getContext(), mHomePreviewCard,
203                 mWallpaperSurface, mColorFuture,
204                 new WallpaperSurfaceCallback.SurfaceListener() {
205                     @Override
206                     public void onSurfaceCreated() {
207                         previewLiveWallpaper(null);
208                     }
209                 });
210 
211         setUpTabs(view.findViewById(R.id.separated_tabs));
212 
213         view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
214             @Override
215             public void onLayoutChange(View thisView, int left, int top, int right, int bottom,
216                     int oldLeft, int oldTop, int oldRight, int oldBottom) {
217                 mHomePreviewCard.setRadius(SizeCalculator.getPreviewCornerRadius(activity,
218                         mHomePreviewCard.getMeasuredWidth()));
219                 view.removeOnLayoutChangeListener(this);
220             }
221         });
222 
223         return view;
224     }
225 
226     @Override
onViewCreated(@onNull View view, @Nullable Bundle savedInstanceState)227     public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
228         super.onViewCreated(view, savedInstanceState);
229         updateWallpaperSurface();
230         setupCurrentWallpaperPreview();
231         renderWorkspaceSurface();
232     }
233 
updateWallpaperSurface()234     private void updateWallpaperSurface() {
235         mWallpaperSurface.getHolder().addCallback(mWallpaperSurfaceCallback);
236         mWallpaperSurface.setZOrderMediaOverlay(true);
237     }
238 
239     @Override
updateScreenPreview(boolean isHomeSelected)240     protected void updateScreenPreview(boolean isHomeSelected) {
241         mWorkspaceSurface.setVisibility(isHomeSelected ? View.VISIBLE : View.INVISIBLE);
242 
243         mLockPreviewContainer.setVisibility(isHomeSelected ? View.INVISIBLE : View.VISIBLE);
244 
245         mFullScreenAnimation.setIsHomeSelected(isHomeSelected);
246     }
247 
setupCurrentWallpaperPreview()248     private void setupCurrentWallpaperPreview() {
249         mHomePreviewCard.setOnTouchListener((v, ev) -> {
250             if (mWallpaperConnection != null && mWallpaperConnection.getEngine() != null) {
251                 float scaleRatio =
252                         (float) mTouchForwardingLayout.getWidth() / (float) mScreenSize.x;
253                 int action = ev.getActionMasked();
254                 if (action == MotionEvent.ACTION_DOWN) {
255                     mBottomActionBar.collapseBottomSheetIfExpanded();
256                 }
257                 MotionEvent dup = MotionEvent.obtainNoHistory(ev);
258                 dup.setLocation(ev.getX() / scaleRatio, ev.getY() / scaleRatio);
259                 try {
260                     mWallpaperConnection.getEngine().dispatchPointer(dup);
261                     if (action == MotionEvent.ACTION_UP) {
262                         mWallpaperConnection.getEngine().dispatchWallpaperCommand(
263                                 WallpaperManager.COMMAND_TAP,
264                                 (int) ev.getX(), (int) ev.getY(), 0, null);
265                     } else if (action == MotionEvent.ACTION_POINTER_UP) {
266                         int pointerIndex = ev.getActionIndex();
267                         mWallpaperConnection.getEngine().dispatchWallpaperCommand(
268                                 WallpaperManager.COMMAND_SECONDARY_TAP,
269                                 (int) ev.getX(pointerIndex), (int) ev.getY(pointerIndex), 0, null);
270                     }
271                 } catch (RemoteException e) {
272                     Log.e(TAG, "Remote exception of wallpaper connection");
273                 }
274             }
275             return false;
276         });
277     }
278 
279     @Override
onDestroyView()280     public void onDestroyView() {
281         super.onDestroyView();
282         if (mSettingsLiveData != null && mSettingsLiveData.hasObservers()
283                 && mSettingsSliceView != null) {
284             mSettingsLiveData.removeObserver(mSettingsSliceView);
285             mSettingsLiveData = null;
286         }
287         if (mWallpaperConnection != null) {
288             mWallpaperConnection.disconnect();
289             mWallpaperConnection = null;
290         }
291         if (mLockScreenPreviewer != null) {
292             mLockScreenPreviewer.release();
293         }
294         mWorkspaceSurfaceCallback.cleanUp();
295         mWorkspaceSurface.getHolder().removeCallback(mWorkspaceSurfaceCallback);
296         mWallpaperSurfaceCallback.cleanUp();
297         mWallpaperSurface.getHolder().removeCallback(mWallpaperSurfaceCallback);
298     }
299 
previewLiveWallpaper(ImageView thumbnailView)300     protected void previewLiveWallpaper(ImageView thumbnailView) {
301         mWallpaperSurface.post(() -> {
302             Activity activity = getActivity();
303             if (activity == null) {
304                 return;
305             }
306             if (mWallpaperSurfaceCallback.getHomeImageWallpaper() != null) {
307                 mWallpaperSurfaceCallback.setHomeImageWallpaperBlur(true);
308                 ColorInfo colorInfo = getColorInfo();
309                 Integer placeholderColor = colorInfo.getPlaceholderColor();
310                 mWallpaper.getThumbAsset(activity.getApplicationContext())
311                         .loadLowResDrawable(activity,
312                                 mWallpaperSurfaceCallback.getHomeImageWallpaper(),
313                                 placeholderColor != null
314                                         ? placeholderColor
315                                         : ResourceUtils.getColorAttr(activity,
316                                                 android.R.attr.colorBackground),
317                                 mPreviewBitmapTransformation);
318             }
319             setUpLiveWallpaperPreview(mWallpaper);
320         });
321     }
322 
getColorInfo()323     private ColorInfo getColorInfo() {
324         ColorInfo colorInfo = null;
325         try {
326             colorInfo = mColorFuture.get(50, TimeUnit.MILLISECONDS);
327         } catch (InterruptedException | ExecutionException | TimeoutException e) {
328             Log.i(TAG, "Couldn't obtain placeholder color", e);
329         }
330         if (colorInfo == null) {
331             colorInfo = new ColorInfo(new WallpaperColors(Color.valueOf(Color.TRANSPARENT),
332                     /* secondaryColor= */ null, /* tertiaryColor= */ null),
333                     /* placeholderColor= */ null);
334         }
335         return colorInfo;
336     }
337 
setUpLiveWallpaperPreview( com.android.wallpaper.model.WallpaperInfo homeWallpaper)338     protected void setUpLiveWallpaperPreview(
339             com.android.wallpaper.model.WallpaperInfo homeWallpaper) {
340         Activity activity = getActivity();
341         if (activity == null || activity.isFinishing()) {
342             return;
343         }
344         if (mWallpaperConnection != null) {
345             mWallpaperConnection.disconnect();
346         }
347 
348         if (WallpaperConnection.isPreviewAvailable()) {
349             mWallpaperConnection = new WallpaperConnection(
350                     getWallpaperIntent(homeWallpaper.getWallpaperComponent()),
351                     activity,
352                     /* listener= */ this,
353                     mWallpaperSurface);
354 
355             mWallpaperConnection.setVisibility(true);
356         } else {
357             WallpaperColorsLoader.getWallpaperColors(
358                     activity,
359                     homeWallpaper.getThumbAsset(activity),
360                     colors -> onWallpaperColorsChanged(colors, 0));
361         }
362         if (mWallpaperConnection != null && !mWallpaperConnection.connect()) {
363             mWallpaperConnection = null;
364         }
365     }
366 
renderWorkspaceSurface()367     private void renderWorkspaceSurface() {
368         mWorkspaceSurface.setZOrderMediaOverlay(true);
369         mWorkspaceSurface.getHolder().addCallback(mWorkspaceSurfaceCallback);
370     }
371 
372     @Override
onBottomActionBarReady(BottomActionBar bottomActionBar)373     protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
374         super.onBottomActionBarReady(bottomActionBar);
375         Activity activity = getActivity();
376         LargeScreenMultiPanesChecker checker = new LargeScreenMultiPanesChecker();
377         if (activity != null
378                 && (activity.isInMultiWindowMode() || checker.isMultiPanesEnabled(getContext()))) {
379             mBottomActionBar.showActionsOnly(INFORMATION, DELETE, CUSTOMIZE, APPLY);
380         } else {
381             mBottomActionBar.showActionsOnly(INFORMATION, DELETE, EDIT, CUSTOMIZE, APPLY);
382         }
383         mBottomActionBar.setActionClickListener(APPLY,
384                 unused -> onSetWallpaperClicked(null, mWallpaper));
385         mBottomActionBar.bindBottomSheetContentWithAction(
386                 new WallpaperInfoContent(getContext()), INFORMATION);
387 
388         View separatedTabsContainer = getView().findViewById(R.id.separated_tabs_container);
389         // Update target view's accessibility param since it will be blocked by the bottom sheet
390         // when expanded.
391         mBottomActionBar.setAccessibilityCallback(new AccessibilityCallback() {
392             @Override
393             public void onBottomSheetCollapsed() {
394                 mPreviewContainer.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
395                 separatedTabsContainer.setImportantForAccessibility(
396                         IMPORTANT_FOR_ACCESSIBILITY_YES);
397             }
398 
399             @Override
400             public void onBottomSheetExpanded() {
401                 mPreviewContainer.setImportantForAccessibility(
402                         IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
403                 separatedTabsContainer.setImportantForAccessibility(
404                         IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
405             }
406         });
407         final Uri uriSettingsSlice = getSettingsSliceUri(mWallpaper.getWallpaperComponent());
408         if (uriSettingsSlice != null) {
409             mSettingsLiveData = SliceLiveData.fromUri(requireContext(), uriSettingsSlice);
410             mBottomActionBar.bindBottomSheetContentWithAction(
411                     new PreviewCustomizeSettingsContent(getContext()), CUSTOMIZE);
412         } else {
413             if (mSettingsIntent != null) {
414                 mBottomActionBar.setActionClickListener(CUSTOMIZE, listener ->
415                         startActivity(mSettingsIntent));
416             } else {
417                 mBottomActionBar.hideActions(CUSTOMIZE);
418             }
419         }
420 
421         if (TextUtils.isEmpty(getDeleteAction(mWallpaper.getWallpaperComponent()))) {
422             mBottomActionBar.hideActions(DELETE);
423         } else {
424             mBottomActionBar.setActionClickListener(DELETE, listener ->
425                     showDeleteConfirmDialog());
426         }
427         mBottomActionBar.show();
428         // Action buttons are disabled when live wallpaper is not loaded.
429         mBottomActionBar.disableActions();
430         // Enable buttons if loaded, or wait for it.
431         if (isLoaded()) {
432             mBottomActionBar.enableActions();
433         }
434     }
435 
436     @Override
onEngineShown()437     public void onEngineShown() {
438         Activity activity = getActivity();
439         if (activity == null) {
440             return;
441         }
442         mWallpaperSurfaceCallback.getHomeImageWallpaper().animate()
443                 .setStartDelay(250)
444                 .setDuration(250)
445                 .alpha(0f)
446                 .setInterpolator(ALPHA_OUT)
447                 .start();
448 
449         if (mBottomActionBar != null) {
450             mBottomActionBar.enableActions();
451         }
452     }
453 
454     @Override
onWallpaperColorsChanged(WallpaperColors colors, int displayId)455     public void onWallpaperColorsChanged(WallpaperColors colors, int displayId) {
456         mWallpaperColors = colors;
457         mLockScreenPreviewer.setColor(colors);
458 
459         mFullScreenAnimation.setFullScreenTextColor(
460                 colors == null || (colors.getColorHints()
461                         & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0
462                             ? FullScreenAnimation.FullScreenTextColor.LIGHT
463                             : FullScreenAnimation.FullScreenTextColor.DARK);
464     }
465 
466     @Override
isLoaded()467     protected boolean isLoaded() {
468         return mWallpaperConnection != null && mWallpaperConnection.isEngineReady();
469     }
470 
471     @SuppressLint("NewApi") //Already checking with isAtLeastQ
getSettingsSliceUri(android.app.WallpaperInfo info)472     protected Uri getSettingsSliceUri(android.app.WallpaperInfo info) {
473         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
474             return info.getSettingsSliceUri();
475         }
476         return null;
477     }
478 
479     @Override
getLayoutResId()480     protected int getLayoutResId() {
481         return R.layout.fragment_live_preview;
482     }
483 
484     @Override
setCurrentWallpaper(int destination)485     protected void setCurrentWallpaper(int destination) {
486         mWallpaperSetter.setCurrentWallpaper(getActivity(), mWallpaper, null,
487                 destination, 0, null,
488                 mWallpaperColors != null ? mWallpaperColors : getColorInfo().getWallpaperColors(),
489                 SetWallpaperViewModel.getCallback(mViewModelProvider));
490     }
491 
492     @Nullable
getDeleteAction(android.app.WallpaperInfo wallpaperInfo)493     protected String getDeleteAction(android.app.WallpaperInfo wallpaperInfo) {
494         android.app.WallpaperInfo currentInfo =
495                 WallpaperManager.getInstance(requireContext()).getWallpaperInfo();
496         ServiceInfo serviceInfo = wallpaperInfo.getServiceInfo();
497         if (!isPackagePreInstalled(serviceInfo.applicationInfo)) {
498             Log.d(TAG, "This wallpaper is not pre-installed: " + serviceInfo.name);
499             return null;
500         }
501 
502         ServiceInfo currentService = currentInfo == null ? null : currentInfo.getServiceInfo();
503         // A currently set Live wallpaper should not be deleted.
504         if (currentService != null && TextUtils.equals(serviceInfo.name, currentService.name)) {
505             return null;
506         }
507 
508         final Bundle metaData = serviceInfo.metaData;
509         if (metaData != null) {
510             return metaData.getString(KEY_ACTION_DELETE_LIVE_WALLPAPER);
511         }
512         return null;
513     }
514 
515     @Override
onResume()516     public void onResume() {
517         super.onResume();
518         if (mWallpaperConnection != null) {
519             mWallpaperConnection.setVisibility(true);
520         }
521     }
522 
523     @Override
onPause()524     public void onPause() {
525         super.onPause();
526         if (mWallpaperConnection != null) {
527             mWallpaperConnection.setVisibility(false);
528         }
529     }
530 
531     @Override
onStop()532     public void onStop() {
533         super.onStop();
534         if (mWallpaperConnection != null) {
535             mWallpaperConnection.disconnect();
536             mWallpaperConnection = null;
537         }
538     }
539 
showDeleteConfirmDialog()540     private void showDeleteConfirmDialog() {
541         final AlertDialog alertDialog = new AlertDialog.Builder(getContext())
542                 .setMessage(R.string.delete_wallpaper_confirmation)
543                 .setOnDismissListener(dialog -> mBottomActionBar.deselectAction(DELETE))
544                 .setPositiveButton(R.string.delete_live_wallpaper,
545                         (dialog, which) -> deleteLiveWallpaper())
546                 .setNegativeButton(android.R.string.cancel, null /* listener */)
547                 .create();
548         alertDialog.show();
549     }
550 
deleteLiveWallpaper()551     private void deleteLiveWallpaper() {
552         if (mDeleteIntent != null) {
553             requireContext().startService(mDeleteIntent);
554             finishActivity(/* success= */ false);
555         }
556     }
557 
isPackagePreInstalled(ApplicationInfo info)558     private boolean isPackagePreInstalled(ApplicationInfo info) {
559         return info != null && (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
560     }
561 
562     private final class PreviewCustomizeSettingsContent extends BottomSheetContent<View> {
563 
PreviewCustomizeSettingsContent(Context context)564         private PreviewCustomizeSettingsContent(Context context) {
565             super(context);
566         }
567 
568         @Override
getViewId()569         public int getViewId() {
570             return R.layout.preview_customize_settings;
571         }
572 
573         @Override
onViewCreated(View previewPage)574         public void onViewCreated(View previewPage) {
575             mSettingsSliceView = previewPage.findViewById(R.id.settings_slice);
576             mSettingsSliceView.setMode(SliceView.MODE_LARGE);
577             mSettingsSliceView.setScrollable(false);
578             if (mSettingsLiveData != null) {
579                 mSettingsLiveData.observeForever(mSettingsSliceView);
580             }
581         }
582 
583         @Override
onRecreateView(View oldPreviewPage)584         public void onRecreateView(View oldPreviewPage) {
585             super.onRecreateView(oldPreviewPage);
586             if (mSettingsLiveData != null && mSettingsLiveData.hasObservers()
587                     && mSettingsSliceView != null) {
588                 mSettingsLiveData.removeObserver(mSettingsSliceView);
589             }
590         }
591     }
592 }
593