1 /*
2  * Copyright (C) 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 android.server.wm;
18 
19 import static android.graphics.Insets.NONE;
20 import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE;
21 import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
22 
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertNull;
25 import static org.junit.Assert.assertSame;
26 
27 import android.content.Context;
28 import android.graphics.Insets;
29 import android.platform.test.annotations.Presubmit;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.view.WindowInsets;
33 import android.view.WindowInsetsAnimation;
34 import android.view.WindowInsetsAnimation.Bounds;
35 import android.widget.FrameLayout;
36 
37 import androidx.annotation.NonNull;
38 import androidx.test.platform.app.InstrumentationRegistry;
39 
40 import org.junit.Before;
41 import org.junit.Test;
42 
43 import java.util.Collections;
44 import java.util.List;
45 
46 @Presubmit
47 public class WindowInsetsAnimationCallbackTests {
48 
49     private static final Bounds BOUNDS = new Bounds(NONE, Insets.of(1000, 2000, 3000, 4000));
50     private static final WindowInsetsAnimation ANIMATION = new WindowInsetsAnimation(1, null, 1000);
51     private static final WindowInsets INSETS = new WindowInsets.Builder()
52             .setSystemWindowInsets(BOUNDS.getUpperBound()).build();
53     private static final List<WindowInsetsAnimation> RUNNING = Collections.singletonList(ANIMATION);
54 
55     final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
56 
57     private ViewGroup mRoot;
58     private ViewGroup mBlocking;
59     private ViewGroup mSibling;
60     private View mChild;
61     private RecordingCallback mRootCallback;
62     private RecordingCallback mBlockingCallback;
63     private RecordingCallback mSiblingCallback;
64     private RecordingCallback mChildCallback;
65 
66     @Before
setUp()67     public void setUp() throws Exception {
68         mRoot = new FrameLayout(mContext);
69         mBlocking = new FrameLayout(mContext);
70         mSibling = new FrameLayout(mContext);
71         mChild = new View(mContext);
72         mRoot.addView(mBlocking);
73         mRoot.addView(mSibling);
74         mBlocking.addView(mChild);
75 
76         mRootCallback = new RecordingCallback(DISPATCH_MODE_CONTINUE_ON_SUBTREE);
77         mBlockingCallback = new RecordingCallback(DISPATCH_MODE_STOP);
78         mSiblingCallback = new RecordingCallback(DISPATCH_MODE_STOP);
79         mChildCallback = new RecordingCallback(DISPATCH_MODE_CONTINUE_ON_SUBTREE);
80 
81         mRoot.setWindowInsetsAnimationCallback(mRootCallback);
82         mBlocking.setWindowInsetsAnimationCallback(mBlockingCallback);
83         mSibling.setWindowInsetsAnimationCallback(mSiblingCallback);
84         mChild.setWindowInsetsAnimationCallback(mChildCallback);
85     }
86 
87     @Test
dispatchWindowInsetsAnimationPrepare()88     public void dispatchWindowInsetsAnimationPrepare() {
89         mRoot.dispatchWindowInsetsAnimationPrepare(ANIMATION);
90         assertSame(ANIMATION, mRootCallback.mOnPrepare);
91         assertSame(ANIMATION, mBlockingCallback.mOnPrepare);
92         assertSame(ANIMATION, mSiblingCallback.mOnPrepare);
93         assertNull(mChildCallback.mOnPrepare);
94     }
95 
96     @Test
dispatchWindowInsetsAnimationStart()97     public void dispatchWindowInsetsAnimationStart() {
98         mRoot.dispatchWindowInsetsAnimationStart(ANIMATION, BOUNDS);
99         assertSame(ANIMATION, mRootCallback.mOnStart);
100         assertSame(ANIMATION, mBlockingCallback.mOnStart);
101         assertSame(ANIMATION, mSiblingCallback.mOnStart);
102         assertNull(mChildCallback.mOnStart);
103 
104         assertSame(BOUNDS, mRootCallback.mOnStartBoundsIn);
105         assertSame(mRootCallback.mOnStartBoundsOut, mBlockingCallback.mOnStartBoundsIn);
106         assertSame(mRootCallback.mOnStartBoundsOut, mSiblingCallback.mOnStartBoundsIn);
107     }
108 
109     @Test
dispatchWindowInsetsAnimationProgress()110     public void dispatchWindowInsetsAnimationProgress() {
111         mRoot.dispatchWindowInsetsAnimationProgress(INSETS, RUNNING);
112         assertSame(RUNNING, mRootCallback.mOnProgress);
113         assertSame(RUNNING, mBlockingCallback.mOnProgress);
114         assertSame(RUNNING, mSiblingCallback.mOnProgress);
115         assertNull(mChildCallback.mOnProgress);
116 
117         assertSame(INSETS, mRootCallback.mOnProgressIn);
118         assertSame(mRootCallback.mOnProgressOut, mBlockingCallback.mOnProgressIn);
119         assertSame(mRootCallback.mOnProgressOut, mSiblingCallback.mOnProgressIn);
120     }
121 
122     @Test
dispatchWindowInsetsAnimationEnd()123     public void dispatchWindowInsetsAnimationEnd() {
124         mRoot.dispatchWindowInsetsAnimationEnd(ANIMATION);
125         assertSame(ANIMATION, mRootCallback.mOnEnd);
126         assertSame(ANIMATION, mBlockingCallback.mOnEnd);
127         assertSame(ANIMATION, mSiblingCallback.mOnEnd);
128         assertNull(mChildCallback.mOnEnd);
129     }
130 
131     @Test
getDispatchMode()132     public void getDispatchMode() {
133         assertEquals(DISPATCH_MODE_STOP,
134                 new RecordingCallback(DISPATCH_MODE_STOP).getDispatchMode());
135         assertEquals(DISPATCH_MODE_CONTINUE_ON_SUBTREE,
136                 new RecordingCallback(DISPATCH_MODE_CONTINUE_ON_SUBTREE).getDispatchMode());
137     }
138 
139     public static class RecordingCallback extends WindowInsetsAnimation.Callback {
140 
141         WindowInsetsAnimation mOnPrepare;
142         WindowInsetsAnimation mOnStart;
143         Bounds mOnStartBoundsIn;
144         Bounds mOnStartBoundsOut;
145         WindowInsetsAnimation mOnEnd;
146         WindowInsets mOnProgressIn;
147         WindowInsets mOnProgressOut;
148         List<WindowInsetsAnimation> mOnProgress;
149 
RecordingCallback(int dispatchMode)150         public RecordingCallback(int dispatchMode) {
151             super(dispatchMode);
152         }
153 
154         @Override
onPrepare(@onNull WindowInsetsAnimation animation)155         public void onPrepare(@NonNull WindowInsetsAnimation animation) {
156             mOnPrepare = animation;
157         }
158 
159         @NonNull
160         @Override
onStart(@onNull WindowInsetsAnimation animation, @NonNull Bounds bounds)161         public Bounds onStart(@NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) {
162             mOnStart = animation;
163             mOnStartBoundsIn = bounds;
164             return mOnStartBoundsOut = bounds.inset(Insets.of(1, 2, 3, 4));
165         }
166 
167         @NonNull
168         @Override
onProgress(@onNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations)169         public WindowInsets onProgress(@NonNull WindowInsets insets,
170                 @NonNull List<WindowInsetsAnimation> runningAnimations) {
171             mOnProgress = runningAnimations;
172             mOnProgressIn = insets;
173             return mOnProgressOut = insets.inset(1, 2, 3, 4);
174         }
175 
176         @Override
onEnd(@onNull WindowInsetsAnimation animation)177         public void onEnd(@NonNull WindowInsetsAnimation animation) {
178             mOnEnd = animation;
179         }
180     }
181 }
182