1 /*
2  * Copyright (C) 2016 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 package androidx.leanback.testutils;
17 
18 import static org.junit.Assert.fail;
19 
20 import android.app.Activity;
21 import android.view.View;
22 
23 public abstract class PollingCheck {
24 
25     private static final long TIME_SLICE = 250;
26     private long mTimeout = 5000;
27 
28     public abstract static class PollingCheckCondition {
canProceed()29         public abstract boolean canProceed();
30 
canPreProceed()31         public boolean canPreProceed() {
32             return canProceed();
33         }
34     }
35 
PollingCheck()36     public PollingCheck() {
37     }
38 
PollingCheck(long timeout)39     public PollingCheck(long timeout) {
40         mTimeout = timeout;
41     }
42 
check()43     protected abstract boolean check();
44 
preCheck()45     protected boolean preCheck() {
46         return check();
47     }
48 
run()49     public void run() {
50         if (preCheck()) {
51             return;
52         }
53 
54         long timeout = mTimeout;
55         while (timeout > 0) {
56             try {
57                 Thread.sleep(TIME_SLICE);
58             } catch (InterruptedException e) {
59                 fail("unexpected InterruptedException");
60             }
61 
62             if (check()) {
63                 return;
64             }
65 
66             timeout -= TIME_SLICE;
67         }
68 
69         fail("unexpected timeout");
70     }
71 
waitFor(final PollingCheckCondition condition)72     public static void waitFor(final PollingCheckCondition condition) {
73         new PollingCheck() {
74             @Override
75             protected boolean check() {
76                 return condition.canProceed();
77             }
78 
79             @Override
80             protected boolean preCheck() {
81                 return condition.canPreProceed();
82             }
83         }.run();
84     }
85 
waitFor(long timeout, final PollingCheckCondition condition)86     public static void waitFor(long timeout, final PollingCheckCondition condition) {
87         new PollingCheck(timeout) {
88             @Override
89             protected boolean check() {
90                 return condition.canProceed();
91             }
92         }.run();
93     }
94 
95     public static class ViewScreenPositionDetector {
96 
97         int[] lastLocation = null;
98         int[] newLocation = new int[2];
99 
isViewStableOnScreen(View view)100         public boolean isViewStableOnScreen(View view) {
101             if (lastLocation == null) {
102                 // get initial location
103                 lastLocation = new int[2];
104                 view.getLocationInWindow(lastLocation);
105             } else {
106                 // get new location and compare to old location
107                 view.getLocationInWindow(newLocation);
108                 if (newLocation[0] == lastLocation[0]
109                         && newLocation[1] == lastLocation[1]) {
110                     // location stable,  animation finished
111                     return true;
112                 }
113                 lastLocation[0] = newLocation[0];
114                 lastLocation[1] = newLocation[1];
115             }
116             return false;
117         }
118     }
119 
120     public static class ViewStableOnScreen extends PollingCheckCondition {
121 
122         View mView;
123         ViewScreenPositionDetector mDector = new ViewScreenPositionDetector();
124 
ViewStableOnScreen(View view)125         public ViewStableOnScreen(View view) {
126             mView = view;
127         }
128 
129         @Override
canPreProceed()130         public boolean canPreProceed() {
131             return false;
132         }
133 
134         @Override
canProceed()135         public boolean canProceed() {
136             return mDector.isViewStableOnScreen(mView);
137         }
138 
139     }
140 
141     public static class ActivityStop extends PollingCheckCondition {
142 
143         Activity mActivity;
144 
ActivityStop(Activity activity)145         public ActivityStop(Activity activity) {
146             mActivity = activity;
147         }
148 
149         @Override
canProceed()150         public boolean canProceed() {
151             return !mActivity.hasWindowFocus();
152         }
153 
154     }
155 
156 }