• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.quickstep.util;
17 
18 import android.app.WallpaperManager;
19 import android.os.IBinder;
20 import android.util.FloatProperty;
21 import android.view.AttachedSurfaceControl;
22 import android.view.SurfaceControl;
23 
24 import com.android.launcher3.Launcher;
25 import com.android.launcher3.R;
26 import com.android.launcher3.Utilities;
27 import com.android.launcher3.util.MultiPropertyFactory;
28 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
29 import com.android.systemui.shared.system.BlurUtils;
30 
31 /**
32  * Utility class for applying depth effect
33  */
34 public class BaseDepthController {
35 
36     private static final FloatProperty<BaseDepthController> DEPTH =
37             new FloatProperty<BaseDepthController>("depth") {
38                 @Override
39                 public void setValue(BaseDepthController depthController, float depth) {
40                     depthController.setDepth(depth);
41                 }
42 
43                 @Override
44                 public Float get(BaseDepthController depthController) {
45                     return depthController.mDepth;
46                 }
47             };
48 
49     private static final int DEPTH_INDEX_STATE_TRANSITION = 0;
50     private static final int DEPTH_INDEX_WIDGET = 1;
51     private static final int DEPTH_INDEX_COUNT = 2;
52 
53     protected final Launcher mLauncher;
54     /** Property to set the depth for state transition. */
55     public final MultiProperty stateDepth;
56     /** Property to set the depth for widget picker. */
57     public final MultiProperty widgetDepth;
58 
59     /**
60      * Blur radius when completely zoomed out, in pixels.
61      */
62     protected final int mMaxBlurRadius;
63     protected final WallpaperManager mWallpaperManager;
64     protected boolean mCrossWindowBlursEnabled;
65 
66     /**
67      * Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in.
68      * @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float)
69      */
70     private float mDepth;
71 
72     protected SurfaceControl mSurface;
73 
74     // Hints that there is potentially content behind Launcher and that we shouldn't optimize by
75     // marking the launcher surface as opaque.  Only used in certain Launcher states.
76     private boolean mHasContentBehindLauncher;
77     /**
78      * Last blur value, in pixels, that was applied.
79      * For debugging purposes.
80      */
81     protected int mCurrentBlur;
82     /**
83      * If we requested early wake-up offsets to SurfaceFlinger.
84      */
85     protected boolean mInEarlyWakeUp;
86 
BaseDepthController(Launcher activity)87     public BaseDepthController(Launcher activity) {
88         mLauncher = activity;
89         mMaxBlurRadius = activity.getResources().getInteger(R.integer.max_depth_blur_radius);
90         mWallpaperManager = activity.getSystemService(WallpaperManager.class);
91 
92         MultiPropertyFactory<BaseDepthController> depthProperty =
93                 new MultiPropertyFactory<>(this, DEPTH, DEPTH_INDEX_COUNT, Float::max);
94         stateDepth = depthProperty.get(DEPTH_INDEX_STATE_TRANSITION);
95         widgetDepth = depthProperty.get(DEPTH_INDEX_WIDGET);
96     }
97 
setCrossWindowBlursEnabled(boolean isEnabled)98     protected void setCrossWindowBlursEnabled(boolean isEnabled) {
99         mCrossWindowBlursEnabled = isEnabled;
100         applyDepthAndBlur();
101     }
102 
setHasContentBehindLauncher(boolean hasContentBehindLauncher)103     public void setHasContentBehindLauncher(boolean hasContentBehindLauncher) {
104         mHasContentBehindLauncher = hasContentBehindLauncher;
105     }
106 
applyDepthAndBlur()107     protected void applyDepthAndBlur() {
108         float depth = mDepth;
109         IBinder windowToken = mLauncher.getRootView().getWindowToken();
110         if (windowToken != null) {
111             // The API's full zoom-out is three times larger than the zoom-out we apply to the
112             // icons. To keep the two consistent throughout the animation while keeping Launcher's
113             // concept of full depth unchanged, we divide the depth by 3 here.
114             mWallpaperManager.setWallpaperZoomOut(windowToken, depth / 3);
115         }
116 
117         if (!BlurUtils.supportsBlursOnWindows()) {
118             return;
119         }
120         if (mSurface == null || !mSurface.isValid()) {
121             return;
122         }
123         boolean hasOpaqueBg = mLauncher.getScrimView().isFullyOpaque();
124         boolean isSurfaceOpaque = !mHasContentBehindLauncher && hasOpaqueBg;
125 
126         mCurrentBlur = !mCrossWindowBlursEnabled || hasOpaqueBg
127                 ? 0 : (int) (depth * mMaxBlurRadius);
128         SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()
129                 .setBackgroundBlurRadius(mSurface, mCurrentBlur)
130                 .setOpaque(mSurface, isSurfaceOpaque);
131 
132         // Set early wake-up flags when we know we're executing an expensive operation, this way
133         // SurfaceFlinger will adjust its internal offsets to avoid jank.
134         boolean wantsEarlyWakeUp = depth > 0 && depth < 1;
135         if (wantsEarlyWakeUp && !mInEarlyWakeUp) {
136             transaction.setEarlyWakeupStart();
137             mInEarlyWakeUp = true;
138         } else if (!wantsEarlyWakeUp && mInEarlyWakeUp) {
139             transaction.setEarlyWakeupEnd();
140             mInEarlyWakeUp = false;
141         }
142 
143         AttachedSurfaceControl rootSurfaceControl =
144                 mLauncher.getRootView().getRootSurfaceControl();
145         if (rootSurfaceControl != null) {
146             rootSurfaceControl.applyTransactionOnDraw(transaction);
147         }
148     }
149 
150     private void setDepth(float depth) {
151         depth = Utilities.boundToRange(depth, 0, 1);
152         // Round out the depth to dedupe frequent, non-perceptable updates
153         int depthI = (int) (depth * 256);
154         float depthF = depthI / 256f;
155         if (Float.compare(mDepth, depthF) == 0) {
156             return;
157         }
158         mDepth = depthF;
159         applyDepthAndBlur();
160     }
161 
162     /**
163      * Sets the specified app target surface to apply the blur to.
164      */
165     protected void setSurface(SurfaceControl surface) {
166         if (mSurface != surface) {
167             mSurface = surface;
168             applyDepthAndBlur();
169         }
170     }
171 }
172