blob: 9fe16ae85cfb6a09187a401732fa3be4a1478229 [file] [log] [blame]
Robert Carrf59b8dd2017-10-02 18:58:36 -07001/*
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 */
16
17package com.android.server.wm;
18
19import android.util.ArrayMap;
20import android.util.Slog;
21import android.view.SurfaceControl;
22import android.graphics.Rect;
23
24/**
25 * Utility class for use by a WindowContainer implementation to add "DimLayer" support, that is
26 * black layers of varying opacity at various Z-levels which create the effect of a Dim.
27 */
28class Dimmer {
29 private static final String TAG = "WindowManager";
30
31 private class DimState {
32 SurfaceControl mSurfaceControl;
33 boolean mDimming;
34
35 /**
36 * Used for Dims not assosciated with a WindowContainer. See {@link Dimmer#dimAbove} for
37 * details on Dim lifecycle.
38 */
39 boolean mDontReset;
40
41 DimState(SurfaceControl ctl) {
42 mSurfaceControl = ctl;
43 mDimming = true;
44 }
45 };
46
47 private ArrayMap<WindowContainer, DimState> mDimLayerUsers = new ArrayMap<>();
48
49 /**
50 * The {@link WindowContainer} that our Dim's are bounded to. We may be dimming on behalf of the
51 * host, some controller of it, or one of the hosts children.
52 */
53 private WindowContainer mHost;
54
55 Dimmer(WindowContainer host) {
56 mHost = host;
57 }
58
59 SurfaceControl makeDimLayer() {
60 final SurfaceControl control = mHost.makeChildSurface(null)
61 .setParent(mHost.getSurfaceControl())
62 .setColorLayer(true)
63 .setName("Dim Layer for - " + mHost.getName())
64 .build();
65 return control;
66 }
67
68 /**
69 * Retreive the DimState for a given child of the host.
70 */
71 DimState getDimState(WindowContainer container) {
72 DimState state = mDimLayerUsers.get(container);
73 if (state == null) {
74 final SurfaceControl ctl = makeDimLayer();
75 state = new DimState(ctl);
76 /**
77 * See documentation on {@link #dimAbove} to understand lifecycle management of Dim's
78 * via state resetting for Dim's with containers.
79 */
80 if (container == null) {
81 state.mDontReset = true;
82 }
83 mDimLayerUsers.put(container, state);
84 }
85 return state;
86 }
87
88 private void dim(SurfaceControl.Transaction t, WindowContainer container, int relativeLayer,
89 float alpha) {
90 final DimState d = getDimState(container);
91 t.show(d.mSurfaceControl);
92 if (container != null) {
93 t.setRelativeLayer(d.mSurfaceControl,
94 container.getSurfaceControl(), relativeLayer);
95 } else {
96 t.setLayer(d.mSurfaceControl, Integer.MAX_VALUE);
97 }
98 t.setAlpha(d.mSurfaceControl, alpha);
99
100 d.mDimming = true;
101 }
102
103 /**
104 * Finish a dim started by dimAbove in the case there was no call to dimAbove.
105 *
106 * @param t A Transaction in which to finish the dim.
107 */
108 void stopDim(SurfaceControl.Transaction t) {
109 DimState d = getDimState(null);
110 t.hide(d.mSurfaceControl);
111 d.mDontReset = false;
112 }
113 /**
114 * Place a Dim above the entire host container. The caller is responsible for calling stopDim to
115 * remove this effect. If the Dim can be assosciated with a particular child of the host
116 * consider using the other variant of dimAbove which ties the Dim lifetime to the child
117 * lifetime more explicitly.
118 *
119 * @param t A transaction in which to apply the Dim.
120 * @param alpha The alpha at which to Dim.
121 */
122 void dimAbove(SurfaceControl.Transaction t, float alpha) {
123 dim(t, null, 1, alpha);
124 }
125
126 /**
127 * Place a dim above the given container, which should be a child of the host container.
128 * for each call to {@link WindowContainer#prepareSurfaces} the Dim state will be reset
129 * and the child should call dimAbove again to request the Dim to continue.
130 *
131 * @param t A transaction in which to apply the Dim.
132 * @param container The container which to dim above. Should be a child of our host.
133 * @param alpha The alpha at which to Dim.
134 */
135 void dimAbove(SurfaceControl.Transaction t, WindowContainer container, float alpha) {
136 dim(t, container, 1, alpha);
137 }
138
139 /**
140 * Like {@link #dimAbove} but places the dim below the given container.
141 *
142 * @param t A transaction in which to apply the Dim.
143 * @param container The container which to dim below. Should be a child of our host.
144 * @param alpha The alpha at which to Dim.
145 */
146
147 void dimBelow(SurfaceControl.Transaction t, WindowContainer container, float alpha) {
148 dim(t, container, -1, alpha);
149 }
150
151 /**
152 * Mark all dims as pending completion on the next call to {@link #updateDims}
153 *
154 * This is intended for us by the host container, to be called at the beginning of
155 * {@link WindowContainer#prepareSurfaces}. After calling this, the container should
156 * chain {@link WindowContainer#prepareSurfaces} down to it's children to give them
157 * a chance to request dims to continue.
158 */
159 void resetDimStates() {
160 for (int i = mDimLayerUsers.size() - 1; i >= 0; i--) {
161 final DimState state = mDimLayerUsers.valueAt(i);
162 if (state.mDontReset == false) {
163 state.mDimming = false;
164 }
165 }
166 }
167
168 /**
169 * Call after invoking {@link WindowContainer#prepareSurfaces} on children as
170 * described in {@link #resetDimStates}.
171 *
172 * @param t A transaction in which to update the dims.
173 * @param bounds The bounds at which to dim.
174 * @return true if any Dims were updated.
175 */
176 boolean updateDims(SurfaceControl.Transaction t, Rect bounds) {
177 boolean didSomething = false;
178 for (int i = mDimLayerUsers.size() - 1; i >= 0; i--) {
179 DimState state = mDimLayerUsers.valueAt(i);
180 // TODO: We want to animate the addition and removal of Dim's instead of immediately
181 // acting. When we do this we need to take care to account for the "Replacing Windows"
182 // case (and seamless dim transfer).
183 if (state.mDimming == false) {
184 mDimLayerUsers.removeAt(i);
185 state.mSurfaceControl.destroy();
186 } else {
187 didSomething = true;
188 // TODO: Once we use geometry from hierarchy this falls away.
189 t.setSize(state.mSurfaceControl, bounds.width(), bounds.height());
190 t.setPosition(state.mSurfaceControl, bounds.left, bounds.top);
191 }
192 }
193 return didSomething;
194 }
195}