blob: c0ed9359c613a96cd17a2de31dcb3d41b0112d5f [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;
41
42 @Override
43 public void show(int types) {
44 if (mReplayedInsetsController != null) {
45 mReplayedInsetsController.show(types);
46 } else {
47 mRequests.add(new ShowRequest(types));
48 }
49 }
50
51 @Override
52 public void hide(int types) {
53 if (mReplayedInsetsController != null) {
54 mReplayedInsetsController.hide(types);
55 } else {
56 mRequests.add(new HideRequest(types));
57 }
58 }
59
60 @Override
61 public CancellationSignal controlWindowInsetsAnimation(int types, long durationMillis,
62 Interpolator interpolator,
63 WindowInsetsAnimationControlListener listener) {
64 if (mReplayedInsetsController != null) {
65 return mReplayedInsetsController.controlWindowInsetsAnimation(types, durationMillis,
66 interpolator, listener);
67 } else {
68 listener.onCancelled();
69 CancellationSignal cancellationSignal = new CancellationSignal();
70 cancellationSignal.cancel();
71 return cancellationSignal;
72 }
73 }
74
75 @Override
76 public void setSystemBarsAppearance(int appearance, int mask) {
77 if (mReplayedInsetsController != null) {
78 mReplayedInsetsController.setSystemBarsAppearance(appearance, mask);
79 } else {
80 mAppearance = (mAppearance & ~mask) | (appearance & mask);
81 mAppearanceMask |= mask;
82 }
83 }
84
85 @Override
86 public int getSystemBarsAppearance() {
87 if (mReplayedInsetsController != null) {
88 return mReplayedInsetsController.getSystemBarsAppearance();
89 }
90 return mAppearance;
91 }
92
93 @Override
94 public void setSystemBarsBehavior(int behavior) {
95 if (mReplayedInsetsController != null) {
96 mReplayedInsetsController.setSystemBarsBehavior(behavior);
97 } else {
98 mBehavior = behavior;
99 }
100 }
101
102 @Override
103 public int getSystemBarsBehavior() {
104 if (mReplayedInsetsController != null) {
105 return mReplayedInsetsController.getSystemBarsBehavior();
106 }
107 return mBehavior;
108 }
109
110 @Override
111 public InsetsState getState() {
112 return mDummyState;
113 }
114
115 /**
116 * Replays the commands on {@code controller} and attaches it to this instance such that any
117 * calls will be forwarded to the real instance in the future.
118 */
119 @VisibleForTesting
120 public void replayAndAttach(InsetsController controller) {
121 if (mBehavior != KEEP_BEHAVIOR) {
122 controller.setSystemBarsBehavior(mBehavior);
123 }
124 if (mAppearanceMask != 0) {
125 controller.setSystemBarsAppearance(mAppearance, mAppearanceMask);
126 }
127 int size = mRequests.size();
128 for (int i = 0; i < size; i++) {
129 mRequests.get(i).replay(controller);
130 }
131
132 // Reset all state so it doesn't get applied twice just in case
133 mRequests.clear();
134 mBehavior = KEEP_BEHAVIOR;
135 mAppearance = 0;
136 mAppearanceMask = 0;
137
138 // After replaying, we forward everything directly to the replayed instance.
139 mReplayedInsetsController = controller;
140 }
141
142 /**
143 * Detaches the controller to no longer forward calls to the real instance.
144 */
145 @VisibleForTesting
146 public void detach() {
147 mReplayedInsetsController = null;
148 }
149
150 private interface PendingRequest {
151 void replay(InsetsController controller);
152 }
153
154 private static class ShowRequest implements PendingRequest {
155
156 private final @InsetsType int mTypes;
157
158 public ShowRequest(int types) {
159 mTypes = types;
160 }
161
162 @Override
163 public void replay(InsetsController controller) {
164 controller.show(mTypes);
165 }
166 }
167
168 private static class HideRequest implements PendingRequest {
169
170 private final @InsetsType int mTypes;
171
172 public HideRequest(int types) {
173 mTypes = types;
174 }
175
176 @Override
177 public void replay(InsetsController controller) {
178 controller.hide(mTypes);
179 }
180 }
181}