blob: 7f3641803770d040dc7b6cd66b9d1050b378f59f [file] [log] [blame]
Jorim Jaggi57157ac2019-01-22 19:01:48 +01001/*
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
17package android.view;
18
19import android.os.CancellationSignal;
20import android.view.WindowInsets.Type.InsetsType;
21import android.view.animation.Interpolator;
22
23import com.android.internal.annotations.VisibleForTesting;
24
25import java.util.ArrayList;
26
27/**
28 * An insets controller that keeps track of pending requests. This is such that an app can freely
29 * use {@link WindowInsetsController} before the view root is attached during activity startup.
30 * @hide
31 */
32public class PendingInsetsController implements WindowInsetsController {
33
34 private static final int KEEP_BEHAVIOR = -1;
35 private final ArrayList<PendingRequest> mRequests = new ArrayList<>();
36 private @Appearance int mAppearance;
37 private @Appearance int mAppearanceMask;
38 private @Behavior int mBehavior = KEEP_BEHAVIOR;
39 private final InsetsState mDummyState = new InsetsState();
40 private InsetsController mReplayedInsetsController;
Jorim Jaggied35b172020-03-06 00:13:57 +010041 private ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
42 = new ArrayList<>();
Jorim Jaggi57157ac2019-01-22 19:01:48 +010043
44 @Override
45 public void show(int types) {
46 if (mReplayedInsetsController != null) {
47 mReplayedInsetsController.show(types);
48 } else {
49 mRequests.add(new ShowRequest(types));
50 }
51 }
52
53 @Override
54 public void hide(int types) {
55 if (mReplayedInsetsController != null) {
56 mReplayedInsetsController.hide(types);
57 } else {
58 mRequests.add(new HideRequest(types));
59 }
60 }
61
62 @Override
63 public CancellationSignal controlWindowInsetsAnimation(int types, long durationMillis,
64 Interpolator interpolator,
65 WindowInsetsAnimationControlListener listener) {
66 if (mReplayedInsetsController != null) {
67 return mReplayedInsetsController.controlWindowInsetsAnimation(types, durationMillis,
68 interpolator, listener);
69 } else {
70 listener.onCancelled();
71 CancellationSignal cancellationSignal = new CancellationSignal();
72 cancellationSignal.cancel();
73 return cancellationSignal;
74 }
75 }
76
77 @Override
78 public void setSystemBarsAppearance(int appearance, int mask) {
79 if (mReplayedInsetsController != null) {
80 mReplayedInsetsController.setSystemBarsAppearance(appearance, mask);
81 } else {
82 mAppearance = (mAppearance & ~mask) | (appearance & mask);
83 mAppearanceMask |= mask;
84 }
85 }
86
87 @Override
88 public int getSystemBarsAppearance() {
89 if (mReplayedInsetsController != null) {
90 return mReplayedInsetsController.getSystemBarsAppearance();
91 }
92 return mAppearance;
93 }
94
95 @Override
96 public void setSystemBarsBehavior(int behavior) {
97 if (mReplayedInsetsController != null) {
98 mReplayedInsetsController.setSystemBarsBehavior(behavior);
99 } else {
100 mBehavior = behavior;
101 }
102 }
103
104 @Override
105 public int getSystemBarsBehavior() {
106 if (mReplayedInsetsController != null) {
107 return mReplayedInsetsController.getSystemBarsBehavior();
108 }
109 return mBehavior;
110 }
111
112 @Override
113 public InsetsState getState() {
114 return mDummyState;
115 }
116
Jorim Jaggied35b172020-03-06 00:13:57 +0100117 @Override
118 public void addOnControllableInsetsChangedListener(
119 OnControllableInsetsChangedListener listener) {
120 if (mReplayedInsetsController != null) {
121 mReplayedInsetsController.addOnControllableInsetsChangedListener(listener);
122 } else {
123 mControllableInsetsChangedListeners.add(listener);
124 listener.onControllableInsetsChanged(this, 0);
125 }
126 }
127
128 @Override
129 public void removeOnControllableInsetsChangedListener(
130 OnControllableInsetsChangedListener listener) {
131 if (mReplayedInsetsController != null) {
132 mReplayedInsetsController.removeOnControllableInsetsChangedListener(listener);
133 } else {
134 mControllableInsetsChangedListeners.remove(listener);
135 }
136 }
137
Jorim Jaggi57157ac2019-01-22 19:01:48 +0100138 /**
139 * Replays the commands on {@code controller} and attaches it to this instance such that any
140 * calls will be forwarded to the real instance in the future.
141 */
142 @VisibleForTesting
143 public void replayAndAttach(InsetsController controller) {
144 if (mBehavior != KEEP_BEHAVIOR) {
145 controller.setSystemBarsBehavior(mBehavior);
146 }
147 if (mAppearanceMask != 0) {
148 controller.setSystemBarsAppearance(mAppearance, mAppearanceMask);
149 }
150 int size = mRequests.size();
151 for (int i = 0; i < size; i++) {
152 mRequests.get(i).replay(controller);
153 }
Jorim Jaggied35b172020-03-06 00:13:57 +0100154 size = mControllableInsetsChangedListeners.size();
155 for (int i = 0; i < size; i++) {
156 controller.addOnControllableInsetsChangedListener(
157 mControllableInsetsChangedListeners.get(i));
158 }
Jorim Jaggi57157ac2019-01-22 19:01:48 +0100159
160 // Reset all state so it doesn't get applied twice just in case
161 mRequests.clear();
Jorim Jaggied35b172020-03-06 00:13:57 +0100162 mControllableInsetsChangedListeners.clear();
Jorim Jaggi57157ac2019-01-22 19:01:48 +0100163 mBehavior = KEEP_BEHAVIOR;
164 mAppearance = 0;
165 mAppearanceMask = 0;
166
167 // After replaying, we forward everything directly to the replayed instance.
168 mReplayedInsetsController = controller;
169 }
170
171 /**
172 * Detaches the controller to no longer forward calls to the real instance.
173 */
174 @VisibleForTesting
175 public void detach() {
176 mReplayedInsetsController = null;
177 }
178
179 private interface PendingRequest {
180 void replay(InsetsController controller);
181 }
182
183 private static class ShowRequest implements PendingRequest {
184
185 private final @InsetsType int mTypes;
186
187 public ShowRequest(int types) {
188 mTypes = types;
189 }
190
191 @Override
192 public void replay(InsetsController controller) {
193 controller.show(mTypes);
194 }
195 }
196
197 private static class HideRequest implements PendingRequest {
198
199 private final @InsetsType int mTypes;
200
201 public HideRequest(int types) {
202 mTypes = types;
203 }
204
205 @Override
206 public void replay(InsetsController controller) {
207 controller.hide(mTypes);
208 }
209 }
210}