1 /*
2  * Copyright 2020 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 
17 package androidx.core.view;
18 
19 import android.annotation.SuppressLint;
20 import android.view.View;
21 import android.view.WindowInsetsAnimationController;
22 
23 import androidx.annotation.FloatRange;
24 import androidx.annotation.RequiresApi;
25 import androidx.core.graphics.Insets;
26 import androidx.core.view.WindowInsetsCompat.Type;
27 import androidx.core.view.WindowInsetsCompat.Type.InsetsType;
28 
29 import org.jspecify.annotations.NonNull;
30 import org.jspecify.annotations.Nullable;
31 
32 /**
33  * Controller for app-driven animation of system windows.
34  * <p>
35  * {@code WindowInsetsAnimationController} lets apps animate system windows such as
36  * the {@link android.inputmethodservice.InputMethodService IME}. The animation is
37  * synchronized, such that changes the system windows and the app's current frame
38  * are rendered at the same time.
39  * <p>
40  * Control is obtained through {@link WindowInsetsControllerCompat#controlWindowInsetsAnimation}.
41  */
42 public final class WindowInsetsAnimationControllerCompat {
43 
44     private final Impl mImpl;
45 
46     @RequiresApi(30)
WindowInsetsAnimationControllerCompat( @onNull WindowInsetsAnimationController controller)47     WindowInsetsAnimationControllerCompat(
48             @NonNull WindowInsetsAnimationController controller) {
49         mImpl = new Impl30(controller);
50     }
51 
52     /**
53      * Retrieves the {@link Insets} when the windows this animation is controlling are fully hidden.
54      * <p>
55      * Note that these insets are always relative to the window, which is the same as being relative
56      * to {@link View#getRootView}
57      * <p>
58      * If there are any animation listeners registered, this value is the same as
59      * {@link WindowInsetsAnimationCompat.BoundsCompat#getLowerBound()} that is being be passed
60      * into the root view of the hierarchy.
61      *
62      * @return Insets when the windows this animation is controlling are fully hidden.
63      * @see WindowInsetsAnimationCompat.BoundsCompat#getLowerBound()
64      */
getHiddenStateInsets()65     public @NonNull Insets getHiddenStateInsets() {
66         return mImpl.getHiddenStateInsets();
67     }
68 
69     /**
70      * Retrieves the {@link Insets} when the windows this animation is
71      * controlling are fully shown.
72      * <p>
73      * Note that these insets are always relative to the window, which is the same as being relative
74      * to {@link View#getRootView}
75      * <p>
76      * If there are any animation listeners registered, this value is the same as
77      * {@link WindowInsetsAnimationCompat.BoundsCompat#getUpperBound()} that is being passed
78      * into the root view of hierarchy.
79      *
80      * @return Insets when the windows this animation is controlling are fully shown.
81      * @see WindowInsetsAnimationCompat.BoundsCompat#getUpperBound()
82      */
getShownStateInsets()83     public @NonNull Insets getShownStateInsets() {
84         return mImpl.getShownStateInsets();
85     }
86 
87     /**
88      * Retrieves the current insets.
89      * <p>
90      * Note that these insets are always relative to the window, which is the same as
91      * being relative
92      * to {@link View#getRootView}
93      *
94      * @return The current insets on the currently showing frame. These insets will change as the
95      * animation progresses to reflect the current insets provided by the controlled window.
96      */
getCurrentInsets()97     public @NonNull Insets getCurrentInsets() {
98         return mImpl.getCurrentInsets();
99     }
100 
101     /**
102      * Returns the progress as previously set by {@code fraction} in {@link #setInsetsAndAlpha}
103      *
104      * @return the progress of the animation, where {@code 0} is fully hidden and {@code 1} is
105      * fully shown.
106      * <p>
107      * Note: this value represents raw overall progress of the animation
108      * i.e. the combined progress of insets and alpha.
109      * <p>
110      */
111     @FloatRange(from = 0f, to = 1f)
getCurrentFraction()112     public float getCurrentFraction() {
113         return mImpl.getCurrentFraction();
114     }
115 
116     /**
117      * Current alpha value of the window.
118      *
119      * @return float value between 0 and 1.
120      */
getCurrentAlpha()121     public float getCurrentAlpha() {
122         return mImpl.getCurrentAlpha();
123     }
124 
125     /**
126      * @return The {@link Type}s this object is currently controlling.
127      */
128     @InsetsType
getTypes()129     public int getTypes() {
130         return mImpl.getTypes();
131     }
132 
133     /**
134      * Modifies the insets for the frame being drawn by indirectly moving the windows around in the
135      * system that are causing window insets.
136      * <p>
137      * Note that these insets are always relative to the window, which is the same as being relative
138      * to {@link View#getRootView}
139      * <p>
140      * Also note that this will <b>not</b> inform the view system of a full inset change via
141      * {@link View#dispatchApplyWindowInsets} in order to avoid a full layout pass during the
142      * animation. If you'd like to animate views during a window inset animation, register a
143      * {@link WindowInsetsAnimationCompat.Callback} by calling
144      *
145      * {@link ViewCompat#setWindowInsetsAnimationCallback(View,
146      * WindowInsetsAnimationCompat.Callback)}
147      * that will be notified about any insets change via
148      * {@link WindowInsetsAnimationCompat.Callback#onProgress} during the animation.
149      * <p>
150      * {@link View#dispatchApplyWindowInsets} will instead be called once the animation has
151      * finished, i.e. once {@link #finish} has been called.
152      * Note: If there are no insets, alpha animation is still applied.
153      *
154      * @param insets   The new insets to apply. Based on the requested insets, the system will
155      *                 calculate the positions of the windows in the system causing insets such that
156      *                 the resulting insets of that configuration will match the passed in
157      *                 parameter.
158      *                 Note that these insets are being clamped to the range from
159      *                 {@link #getHiddenStateInsets} to {@link #getShownStateInsets}.
160      *                 If you intend on changing alpha only, pass null or
161      *                 {@link #getCurrentInsets()}.
162      * @param alpha    The new alpha to apply to the inset side.
163      * @param fraction instantaneous animation progress. This value is dispatched to
164      *                 {@link WindowInsetsAnimationCompat.Callback}.
165      * @see WindowInsetsAnimationCompat.Callback
166      * @see ViewCompat#setWindowInsetsAnimationCallback(View, WindowInsetsAnimationCompat.Callback)
167      */
168 
setInsetsAndAlpha(@ullable Insets insets, @FloatRange(from = 0f, to = 1f) float alpha, @FloatRange(from = 0f, to = 1f) float fraction)169     public void setInsetsAndAlpha(@Nullable Insets insets,
170             @FloatRange(from = 0f, to = 1f) float alpha,
171             @FloatRange(from = 0f, to = 1f) float fraction) {
172         mImpl.setInsetsAndAlpha(insets, alpha, fraction);
173     }
174 
175     /**
176      * Finishes the animation, and leaves the windows shown or hidden.
177      * <p>
178      * After invoking {@link #finish}, this instance is no longer {@link #isReady ready}.
179      * <p>
180      * Note: Finishing an animation implicitly {@link #setInsetsAndAlpha sets insets and alpha}
181      * according to the requested end state without any further animation.
182      *
183      * @param shown if {@code true}, the windows will be shown after finishing the
184      *              animation. Otherwise they will be hidden.
185      */
finish(boolean shown)186     public void finish(boolean shown) {
187         mImpl.finish(shown);
188     }
189 
190     /**
191      * Returns whether this instance is ready to be used to control window insets.
192      * <p>
193      * Instances are ready when passed in {@link WindowInsetsAnimationControlListenerCompat#onReady}
194      * and stop being ready when it is either {@link #isFinished() finished} or
195      * {@link #isCancelled() cancelled}.
196      *
197      * @return {@code true} if the instance is ready, {@code false} otherwise.
198      */
199 
isReady()200     public boolean isReady() {
201         return !isFinished() && !isCancelled();
202     }
203 
204     /**
205      * Returns whether this instance has been finished by a call to {@link #finish}.
206      *
207      * @return {@code true} if the instance is finished, {@code false} otherwise.
208      * @see WindowInsetsAnimationControlListenerCompat#onFinished
209      */
isFinished()210     public boolean isFinished() {
211         return mImpl.isFinished();
212     }
213 
214     /**
215      * Returns whether this instance has been cancelled by the system, or by invoking the
216      * {@link android.os.CancellationSignal} passed into
217      * {@link WindowInsetsControllerCompat#controlWindowInsetsAnimation}.
218      *
219      * @return {@code true} if the instance is cancelled, {@code false} otherwise.
220      * @see WindowInsetsAnimationControlListenerCompat#onCancelled
221      */
isCancelled()222     public boolean isCancelled() {
223         return mImpl.isCancelled();
224     }
225 
226     private static class Impl {
Impl()227         Impl() {
228             //privatex
229         }
230 
getHiddenStateInsets()231         public @NonNull Insets getHiddenStateInsets() {
232             return Insets.NONE;
233         }
234 
getShownStateInsets()235         public @NonNull Insets getShownStateInsets() {
236             return Insets.NONE;
237         }
238 
getCurrentInsets()239         public @NonNull Insets getCurrentInsets() {
240             return Insets.NONE;
241         }
242 
243         @FloatRange(from = 0f, to = 1f)
getCurrentFraction()244         public float getCurrentFraction() {
245             return 0f;
246         }
247 
getCurrentAlpha()248         public float getCurrentAlpha() {
249             return 0f;
250         }
251 
252         @InsetsType
getTypes()253         public int getTypes() {
254             return 0;
255         }
256 
setInsetsAndAlpha(@ullable Insets insets, @FloatRange(from = 0f, to = 1f) float alpha, @FloatRange(from = 0f, to = 1f) float fraction)257         public void setInsetsAndAlpha(@Nullable Insets insets,
258                 @FloatRange(from = 0f, to = 1f) float alpha,
259                 @FloatRange(from = 0f, to = 1f) float fraction) {
260         }
261 
finish(boolean shown)262         void finish(boolean shown) {
263         }
264 
isFinished()265         boolean isFinished() {
266             return false;
267         }
268 
isCancelled()269         boolean isCancelled() {
270             return true;
271         }
272     }
273 
274     @RequiresApi(30)
275     private static class Impl30 extends Impl {
276 
277         private final WindowInsetsAnimationController mController;
278 
Impl30(@onNull WindowInsetsAnimationController controller)279         Impl30(@NonNull WindowInsetsAnimationController controller) {
280             mController = controller;
281         }
282 
283         @Override
getHiddenStateInsets()284         public @NonNull Insets getHiddenStateInsets() {
285             return Insets.toCompatInsets(mController.getHiddenStateInsets());
286         }
287 
288         @Override
getShownStateInsets()289         public @NonNull Insets getShownStateInsets() {
290             return Insets.toCompatInsets(mController.getShownStateInsets());
291         }
292 
293         @Override
getCurrentInsets()294         public @NonNull Insets getCurrentInsets() {
295             return Insets.toCompatInsets(mController.getCurrentInsets());
296         }
297 
298         @Override
getCurrentFraction()299         public float getCurrentFraction() {
300             return mController.getCurrentFraction();
301         }
302 
303         @Override
getCurrentAlpha()304         public float getCurrentAlpha() {
305             return mController.getCurrentAlpha();
306         }
307 
308         @SuppressLint("WrongConstant")
309         @Override
getTypes()310         public int getTypes() {
311             return mController.getTypes();
312         }
313 
314         @Override
setInsetsAndAlpha(@ullable Insets insets, float alpha, float fraction)315         public void setInsetsAndAlpha(@Nullable Insets insets, float alpha, float fraction) {
316             mController.setInsetsAndAlpha(insets == null ? null : insets.toPlatformInsets(),
317                     alpha,
318                     fraction
319             );
320         }
321 
322         @Override
finish(boolean shown)323         void finish(boolean shown) {
324             mController.finish(shown);
325         }
326 
327         @Override
isFinished()328         boolean isFinished() {
329             return mController.isFinished();
330         }
331 
332         @Override
isCancelled()333         boolean isCancelled() {
334             return mController.isCancelled();
335         }
336     }
337 }
338 
339