• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base;
6 
7 import static org.mockito.Mockito.mock;
8 import static org.mockito.Mockito.verify;
9 
10 import android.app.Activity;
11 import android.view.ActionMode;
12 import android.view.KeyEvent;
13 import android.view.KeyboardShortcutGroup;
14 import android.view.Menu;
15 import android.view.MenuItem;
16 import android.view.MotionEvent;
17 import android.view.SearchEvent;
18 import android.view.View;
19 import android.view.Window;
20 import android.view.WindowManager;
21 import android.view.accessibility.AccessibilityEvent;
22 
23 import androidx.annotation.RequiresApi;
24 
25 import org.junit.Assert;
26 import org.junit.Test;
27 import org.junit.runner.RunWith;
28 import org.robolectric.Robolectric;
29 import org.robolectric.Shadows;
30 import org.robolectric.android.controller.ActivityController;
31 import org.robolectric.annotation.Config;
32 import org.robolectric.annotation.Implementation;
33 import org.robolectric.annotation.Implements;
34 import org.robolectric.shadows.ShadowActivity;
35 
36 import org.chromium.base.test.BaseRobolectricTestRunner;
37 
38 import java.util.List;
39 
40 /** Unit tests for {@link ApplicationStatus}. */
41 @RunWith(BaseRobolectricTestRunner.class)
42 @Config(manifest = Config.NONE, shadows = {ApplicationStatusTest.TrackingShadowActivity.class})
43 public class ApplicationStatusTest {
44     private static class WindowCallbackWrapper implements Window.Callback {
45         final Window.Callback mWrapped;
46 
WindowCallbackWrapper(Window.Callback wrapped)47         public WindowCallbackWrapper(Window.Callback wrapped) {
48             mWrapped = wrapped;
49         }
50 
51         @Override
dispatchKeyEvent(KeyEvent event)52         public boolean dispatchKeyEvent(KeyEvent event) {
53             return mWrapped.dispatchKeyEvent(event);
54         }
55 
56         @Override
dispatchKeyShortcutEvent(KeyEvent event)57         public boolean dispatchKeyShortcutEvent(KeyEvent event) {
58             return mWrapped.dispatchKeyShortcutEvent(event);
59         }
60 
61         @Override
dispatchTouchEvent(MotionEvent event)62         public boolean dispatchTouchEvent(MotionEvent event) {
63             return mWrapped.dispatchTouchEvent(event);
64         }
65 
66         @Override
dispatchTrackballEvent(MotionEvent event)67         public boolean dispatchTrackballEvent(MotionEvent event) {
68             return mWrapped.dispatchTrackballEvent(event);
69         }
70 
71         @Override
dispatchGenericMotionEvent(MotionEvent event)72         public boolean dispatchGenericMotionEvent(MotionEvent event) {
73             return mWrapped.dispatchGenericMotionEvent(event);
74         }
75 
76         @Override
dispatchPopulateAccessibilityEvent(AccessibilityEvent event)77         public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
78             return mWrapped.dispatchPopulateAccessibilityEvent(event);
79         }
80 
81         @Override
onCreatePanelView(int featureId)82         public View onCreatePanelView(int featureId) {
83             return mWrapped.onCreatePanelView(featureId);
84         }
85 
86         @Override
onCreatePanelMenu(int featureId, Menu menu)87         public boolean onCreatePanelMenu(int featureId, Menu menu) {
88             return mWrapped.onCreatePanelMenu(featureId, menu);
89         }
90 
91         @Override
onPreparePanel(int featureId, View view, Menu menu)92         public boolean onPreparePanel(int featureId, View view, Menu menu) {
93             return mWrapped.onPreparePanel(featureId, view, menu);
94         }
95 
96         @Override
onMenuOpened(int featureId, Menu menu)97         public boolean onMenuOpened(int featureId, Menu menu) {
98             return mWrapped.onMenuOpened(featureId, menu);
99         }
100 
101         @Override
onMenuItemSelected(int featureId, MenuItem item)102         public boolean onMenuItemSelected(int featureId, MenuItem item) {
103             return mWrapped.onMenuItemSelected(featureId, item);
104         }
105 
106         @Override
onWindowAttributesChanged(WindowManager.LayoutParams attrs)107         public void onWindowAttributesChanged(WindowManager.LayoutParams attrs) {
108             mWrapped.onWindowAttributesChanged(attrs);
109         }
110 
111         @Override
onContentChanged()112         public void onContentChanged() {
113             mWrapped.onContentChanged();
114         }
115 
116         @Override
onWindowFocusChanged(boolean hasFocus)117         public void onWindowFocusChanged(boolean hasFocus) {
118             mWrapped.onWindowFocusChanged(hasFocus);
119         }
120 
121         @Override
onAttachedToWindow()122         public void onAttachedToWindow() {
123             mWrapped.onAttachedToWindow();
124         }
125 
126         @Override
onDetachedFromWindow()127         public void onDetachedFromWindow() {
128             mWrapped.onDetachedFromWindow();
129         }
130 
131         @Override
onPanelClosed(int featureId, Menu menu)132         public void onPanelClosed(int featureId, Menu menu) {
133             mWrapped.onPanelClosed(featureId, menu);
134         }
135 
136         @RequiresApi(23)
137         @Override
onSearchRequested(SearchEvent searchEvent)138         public boolean onSearchRequested(SearchEvent searchEvent) {
139             return mWrapped.onSearchRequested(searchEvent);
140         }
141 
142         @Override
onSearchRequested()143         public boolean onSearchRequested() {
144             return mWrapped.onSearchRequested();
145         }
146 
147         @Override
onWindowStartingActionMode(ActionMode.Callback callback)148         public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
149             return mWrapped.onWindowStartingActionMode(callback);
150         }
151 
152         @RequiresApi(23)
153         @Override
onWindowStartingActionMode(ActionMode.Callback callback, int type)154         public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
155             return mWrapped.onWindowStartingActionMode(callback, type);
156         }
157 
158         @Override
onActionModeStarted(ActionMode mode)159         public void onActionModeStarted(ActionMode mode) {
160             mWrapped.onActionModeStarted(mode);
161         }
162 
163         @Override
onActionModeFinished(ActionMode mode)164         public void onActionModeFinished(ActionMode mode) {
165             mWrapped.onActionModeFinished(mode);
166         }
167 
168         @RequiresApi(24)
169         @Override
onProvideKeyboardShortcuts( List<KeyboardShortcutGroup> data, Menu menu, int deviceId)170         public void onProvideKeyboardShortcuts(
171                 List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
172             mWrapped.onProvideKeyboardShortcuts(data, menu, deviceId);
173         }
174 
175         @RequiresApi(26)
176         @Override
onPointerCaptureChanged(boolean hasCapture)177         public void onPointerCaptureChanged(boolean hasCapture) {
178             mWrapped.onPointerCaptureChanged(hasCapture);
179         }
180     }
181 
182     private static class SubclassedCallbackWrapper extends WindowCallbackWrapper {
SubclassedCallbackWrapper(Window.Callback callback)183         public SubclassedCallbackWrapper(Window.Callback callback) {
184             super(callback);
185         }
186     }
187 
188     /** Shadow that tracks calls to onWindowFocusChanged and dispatchKeyEvent. */
189     @Implements(Activity.class)
190     public static class TrackingShadowActivity extends ShadowActivity {
191         private int mWindowFocusCalls;
192         private int mDispatchKeyEventCalls;
193         private boolean mReturnValueForKeyDispatch;
194 
195         @Implementation
onWindowFocusChanged(@uppressWarnings"unused") boolean hasFocus)196         public void onWindowFocusChanged(@SuppressWarnings("unused") boolean hasFocus) {
197             mWindowFocusCalls++;
198         }
199 
200         @Implementation
dispatchKeyEvent(@uppressWarnings"unused") KeyEvent event)201         public boolean dispatchKeyEvent(@SuppressWarnings("unused") KeyEvent event) {
202             mDispatchKeyEventCalls++;
203             return mReturnValueForKeyDispatch;
204         }
205     }
206 
207     @Test
testWindowsFocusChanged()208     public void testWindowsFocusChanged() {
209         ApplicationStatus.WindowFocusChangedListener mock =
210                 mock(ApplicationStatus.WindowFocusChangedListener.class);
211         ApplicationStatus.registerWindowFocusChangedListener(mock);
212 
213         ActivityController<Activity> controller =
214                 Robolectric.buildActivity(Activity.class).create().start().visible();
215         TrackingShadowActivity shadow = (TrackingShadowActivity) Shadows.shadowOf(controller.get());
216 
217         controller.get().getWindow().getCallback().onWindowFocusChanged(true);
218         // Assert that listeners were notified.
219         verify(mock).onWindowFocusChanged(controller.get(), true);
220         // Also ensure that the original activity is forwarded the notification.
221         Assert.assertEquals(1, shadow.mWindowFocusCalls);
222     }
223 
224     @Test
testNullCallback()225     public void testNullCallback() {
226         Assert.assertFalse(ApplicationStatus.reachesWindowCallback(null));
227     }
228 
229     @Test
testOtherCallback()230     public void testOtherCallback() {
231         Assert.assertFalse(ApplicationStatus.reachesWindowCallback(mock(Window.Callback.class)));
232     }
233 
createWindowCallbackProxy()234     private Window.Callback createWindowCallbackProxy() {
235         return ApplicationStatus.createWindowCallbackProxy(
236                 mock(Activity.class), mock(Window.Callback.class));
237     }
238 
239     @Test
testNotWrappedCallback()240     public void testNotWrappedCallback() {
241         Assert.assertTrue(ApplicationStatus.reachesWindowCallback(createWindowCallbackProxy()));
242     }
243 
244     @Test
testSingleWrappedCallback()245     public void testSingleWrappedCallback() {
246         Assert.assertTrue(ApplicationStatus.reachesWindowCallback(
247                 new WindowCallbackWrapper(createWindowCallbackProxy())));
248     }
249 
250     @Test
testDoubleWrappedCallback()251     public void testDoubleWrappedCallback() {
252         Assert.assertTrue(ApplicationStatus.reachesWindowCallback(
253                 new WindowCallbackWrapper(new WindowCallbackWrapper(createWindowCallbackProxy()))));
254     }
255 
256     @Test
testSubclassWrappedCallback()257     public void testSubclassWrappedCallback() {
258         Assert.assertTrue(ApplicationStatus.reachesWindowCallback(
259                 new SubclassedCallbackWrapper(createWindowCallbackProxy())));
260     }
261 
262     @Test
testTaskVisibilityForCreatedActivity()263     public void testTaskVisibilityForCreatedActivity() {
264         ActivityController<Activity> controller = Robolectric.buildActivity(Activity.class);
265 
266         controller.create();
267         Assert.assertFalse(ApplicationStatus.isTaskVisible(controller.get().getTaskId()));
268     }
269 
270     @Test
testTaskVisibilityForStartedActivity()271     public void testTaskVisibilityForStartedActivity() {
272         ActivityController<Activity> controller = Robolectric.buildActivity(Activity.class);
273 
274         controller.create().start();
275         Assert.assertFalse(ApplicationStatus.isTaskVisible(controller.get().getTaskId()));
276     }
277 
278     @Test
testTaskVisibilityForResumedActivity()279     public void testTaskVisibilityForResumedActivity() {
280         ActivityController<Activity> controller = Robolectric.buildActivity(Activity.class);
281 
282         controller.create().resume();
283         Assert.assertTrue(ApplicationStatus.isTaskVisible(controller.get().getTaskId()));
284     }
285 
286     @Test
testTaskVisibilityForPausedActivity()287     public void testTaskVisibilityForPausedActivity() {
288         ActivityController<Activity> controller = Robolectric.buildActivity(Activity.class);
289 
290         controller.create().pause();
291         Assert.assertTrue(ApplicationStatus.isTaskVisible(controller.get().getTaskId()));
292     }
293 
294     @Test
testTaskVisibilityForStoppedActivity()295     public void testTaskVisibilityForStoppedActivity() {
296         ActivityController<Activity> controller = Robolectric.buildActivity(Activity.class);
297 
298         controller.create().stop();
299         Assert.assertFalse(ApplicationStatus.isTaskVisible(controller.get().getTaskId()));
300     }
301 
302     @Test
testTaskVisibilityForDestroyedActivity()303     public void testTaskVisibilityForDestroyedActivity() {
304         ActivityController<Activity> controller = Robolectric.buildActivity(Activity.class);
305 
306         controller.create().destroy();
307         Assert.assertFalse(ApplicationStatus.isTaskVisible(controller.get().getTaskId()));
308     }
309 }
310