1 /*
2  * Copyright (C) 2008 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.view.cts;
18 
19 import com.android.cts.view.R;
20 
21 import android.app.Instrumentation;
22 import android.app.Presentation;
23 import android.content.Context;
24 import android.content.res.Configuration;
25 import android.content.res.TypedArray;
26 import android.cts.util.PollingCheck;
27 import android.graphics.Color;
28 import android.graphics.PixelFormat;
29 import android.graphics.drawable.ColorDrawable;
30 import android.graphics.drawable.Drawable;
31 import android.hardware.display.DisplayManager;
32 import android.hardware.display.VirtualDisplay;
33 import android.media.AudioManager;
34 import android.net.Uri;
35 import android.os.Bundle;
36 import android.os.Handler;
37 import android.os.SystemClock;
38 import android.test.ActivityInstrumentationTestCase2;
39 import android.test.UiThreadTest;
40 import android.util.DisplayMetrics;
41 import android.util.Log;
42 import android.view.ActionMode;
43 import android.view.Display;
44 import android.view.Gravity;
45 import android.view.InputDevice;
46 import android.view.InputQueue;
47 import android.view.KeyEvent;
48 import android.view.LayoutInflater;
49 import android.view.Menu;
50 import android.view.MenuItem;
51 import android.view.MotionEvent;
52 import android.view.SearchEvent;
53 import android.view.Surface;
54 import android.view.SurfaceHolder;
55 import android.view.SurfaceView;
56 import android.view.View;
57 import android.view.ViewGroup;
58 import android.view.Window;
59 import android.view.WindowManager;
60 import android.view.accessibility.AccessibilityEvent;
61 import android.widget.Button;
62 import android.widget.TextView;
63 
64 import java.util.concurrent.Semaphore;
65 import java.util.concurrent.TimeUnit;
66 
67 public class WindowTest extends ActivityInstrumentationTestCase2<WindowCtsActivity> {
68     static final String TAG = "WindowTest";
69     private Window mWindow;
70     private Context mContext;
71     private Instrumentation mInstrumentation;
72     private WindowCtsActivity mActivity;
73     private SurfaceView surfaceView;
74 
75     private static final int VIEWGROUP_LAYOUT_HEIGHT = 100;
76     private static final int VIEWGROUP_LAYOUT_WIDTH = 200;
77 
78     // for testing setLocalFocus
79     private ProjectedPresentation mPresentation;
80     private VirtualDisplay mVirtualDisplay;
81 
WindowTest()82     public WindowTest() {
83         super("com.android.cts.view", WindowCtsActivity.class);
84     }
85 
86     @Override
setUp()87     protected void setUp() throws Exception {
88         super.setUp();
89         mInstrumentation = getInstrumentation();
90         mContext = mInstrumentation.getContext();
91         mActivity = getActivity();
92         mWindow = mActivity.getWindow();
93     }
94 
95     @Override
tearDown()96     protected void tearDown() throws Exception {
97         if (mActivity != null) {
98             mActivity.setFlagFalse();
99         }
100         super.tearDown();
101     }
102 
103     @UiThreadTest
testConstructor()104     public void testConstructor() throws Exception {
105         mWindow = new MockWindow(mContext);
106         assertSame(mContext, mWindow.getContext());
107     }
108 
109     /**
110      * Test flags related methods:
111      * 1. addFlags: add the given flag to WindowManager.LayoutParams.flags, if add more than one
112      *    in sequence, flags will be set to formerFlag | latterFlag.
113      * 2. setFlags: _1. set the flags of the window.
114      *              _2. test invocation of Window.Callback#onWindowAttributesChanged.
115      * 3. clearFlags: clear the flag bits as specified in flags.
116      */
testOpFlags()117    public void testOpFlags() throws Exception {
118         mWindow = new MockWindow(mContext);
119         final WindowManager.LayoutParams attrs = mWindow.getAttributes();
120         assertEquals(0, attrs.flags);
121 
122         mWindow.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
123         assertEquals(WindowManager.LayoutParams.FLAG_FULLSCREEN, attrs.flags);
124 
125         mWindow.addFlags(WindowManager.LayoutParams.FLAG_DITHER);
126         assertEquals(WindowManager.LayoutParams.FLAG_FULLSCREEN
127                 | WindowManager.LayoutParams.FLAG_DITHER, attrs.flags);
128 
129         mWindow.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
130         assertEquals(WindowManager.LayoutParams.FLAG_DITHER, attrs.flags);
131         mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DITHER);
132         assertEquals(0, attrs.flags);
133 
134         MockWindowCallback callback = new MockWindowCallback();
135         mWindow.setCallback(callback);
136         assertFalse(callback.isOnWindowAttributesChangedCalled());
137         // mask == flag, no bit of flag need to be modified.
138         mWindow.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
139                 WindowManager.LayoutParams.FLAG_FULLSCREEN);
140         assertEquals(WindowManager.LayoutParams.FLAG_FULLSCREEN, attrs.flags);
141 
142         // Test if the callback method is called by system
143         assertTrue(callback.isOnWindowAttributesChangedCalled());
144         mWindow.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
145         mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DITHER);
146     }
147 
testFindViewById()148     public void testFindViewById() throws Exception {
149         TextView v = (TextView) mWindow.findViewById(R.id.listview_window);
150         assertNotNull(v);
151         assertEquals(R.id.listview_window, v.getId());
152     }
153 
154     /**
155      * getAttributes: Retrieve the current window attributes associated with this panel.
156      *    Return is 1.the existing window attributes object.
157      *              2.a freshly created one if there is none.
158      * setAttributes: Specify custom window attributes.
159      *    Here we just set some parameters to test if it can set, and the window is just
160      *    available in this method. But it's not proper to setAttributes arbitrarily.
161      * setCallback: Set the Callback interface for this window. In Window.java,
162      *    there is just one method, onWindowAttributesChanged, used.
163      * getCallback: Return the current Callback interface for this window.
164      */
testAccessAttributes()165     public void testAccessAttributes() throws Exception {
166         mWindow = new MockWindow(mContext);
167 
168         // default attributes
169         WindowManager.LayoutParams attr = mWindow.getAttributes();
170         assertEquals(WindowManager.LayoutParams.MATCH_PARENT, attr.width);
171         assertEquals(WindowManager.LayoutParams.MATCH_PARENT, attr.height);
172         assertEquals(WindowManager.LayoutParams.TYPE_APPLICATION, attr.type);
173         assertEquals(PixelFormat.OPAQUE, attr.format);
174 
175         int width = 200;
176         int height = 300;
177         WindowManager.LayoutParams param = new WindowManager.LayoutParams(width, height,
178                 WindowManager.LayoutParams.TYPE_BASE_APPLICATION,
179                 WindowManager.LayoutParams.FLAG_DITHER, PixelFormat.RGBA_8888);
180         MockWindowCallback callback = new MockWindowCallback();
181         mWindow.setCallback(callback);
182         assertSame(callback, mWindow.getCallback());
183         assertFalse(callback.isOnWindowAttributesChangedCalled());
184         mWindow.setAttributes(param);
185         attr = mWindow.getAttributes();
186         assertEquals(width, attr.width);
187         assertEquals(height, attr.height);
188         assertEquals(WindowManager.LayoutParams.TYPE_BASE_APPLICATION, attr.type);
189         assertEquals(PixelFormat.RGBA_8888, attr.format);
190         assertEquals(WindowManager.LayoutParams.FLAG_DITHER, attr.flags);
191         assertTrue(callback.isOnWindowAttributesChangedCalled());
192     }
193 
194     /**
195      * If not set container, the DecorWindow operates as a top-level window, the mHasChildren of
196      * container is false;
197      * Otherwise, it will display itself meanwhile container's mHasChildren is true.
198      */
testAccessContainer()199     public void testAccessContainer() throws Exception {
200         mWindow = new MockWindow(mContext);
201         assertNull(mWindow.getContainer());
202         assertFalse(mWindow.hasChildren());
203 
204         MockWindow container = new MockWindow(mContext);
205         mWindow.setContainer(container);
206         assertSame(container, mWindow.getContainer());
207         assertTrue(container.hasChildren());
208     }
209 
210     /**
211      * addContentView: add an additional content view to the screen.
212      *    1.Added after any existing ones in the screen.
213      *    2.Existing views are NOT removed.
214      * getLayoutInflater: Quick access to the {@link LayoutInflater} instance that this Window
215      *    retrieved from its Context.
216      */
testAddContentView()217     public void testAddContentView() throws Throwable {
218         final ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(VIEWGROUP_LAYOUT_WIDTH,
219                 VIEWGROUP_LAYOUT_HEIGHT);
220         // The LayoutInflater instance will be inflated to a view and used by
221         // addContentView,
222         // id of this view should be same with inflated id.
223         final LayoutInflater inflater = mActivity.getLayoutInflater();
224         runTestOnUiThread(new Runnable() {
225             public void run() {
226                 TextView addedView = (TextView) mWindow.findViewById(R.id.listview_addwindow);
227                 assertNull(addedView);
228                 mWindow.addContentView(inflater.inflate(R.layout.windowstub_addlayout, null), lp);
229                 TextView view = (TextView) mWindow.findViewById(R.id.listview_window);
230                 addedView = (TextView) mWindow.findViewById(R.id.listview_addwindow);
231                 assertNotNull(view);
232                 assertNotNull(addedView);
233                 assertEquals(R.id.listview_window, view.getId());
234                 assertEquals(R.id.listview_addwindow, addedView.getId());
235             }
236         });
237         mInstrumentation.waitForIdleSync();
238     }
239 
testCloseAllPanels()240     public void testCloseAllPanels() throws Throwable {
241     }
242 
243     /**
244      * getCurrentFocus: Return the view in this Window that currently has focus, or null if
245      *                  there are none.
246      * The test will be:
247      * 1. Set focus view to null, get current focus, it should be null
248      * 2. Set listview_window as focus view, get it and compare.
249      */
testGetCurrentFocus()250     public void testGetCurrentFocus() throws Throwable {
251         runTestOnUiThread(new Runnable() {
252             public void run() {
253                 TextView v = (TextView) mWindow.findViewById(R.id.listview_window);
254                 v.clearFocus();
255                 assertNull(mWindow.getCurrentFocus());
256 
257                 v.setFocusable(true);
258                 assertTrue(v.isFocusable());
259                 assertTrue(v.requestFocus());
260                 View focus = mWindow.getCurrentFocus();
261                 assertNotNull(focus);
262                 assertEquals(R.id.listview_window, focus.getId());
263             }
264         });
265         mInstrumentation.waitForIdleSync();
266     }
267 
268     /**
269      * 1. getDecorView() retrieves the top-level window decor view, which contains the standard
270      *    window frame/decorations and the client's content inside of that, we should check the
271      *    primary components of this view which have no relationship concrete realization of Window.
272      *    Therefore we should check if the size of this view equals to the screen size and the
273      *    ontext is same as Window's context.
274      * 2. Return null if decor view is not created, else the same with detDecorView.
275      */
testDecorView()276     public void testDecorView() throws Exception {
277         mInstrumentation.waitForIdleSync();
278         View decor = mWindow.getDecorView();
279         assertNotNull(decor);
280         checkDecorView(decor);
281 
282         decor = mWindow.peekDecorView();
283         if (decor != null) {
284             checkDecorView(decor);
285         }
286     }
287 
checkDecorView(View decor)288     private void checkDecorView(View decor) {
289         DisplayMetrics dm = new DisplayMetrics();
290         mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
291         int screenWidth = dm.widthPixels;
292         int screenHeight = dm.heightPixels;
293         assertTrue(decor.getWidth() >= screenWidth);
294         assertTrue(decor.getHeight() >= screenHeight);
295         assertSame(mWindow.getContext(), decor.getContext());
296     }
297 
298     /**
299      * setVolumeControlStream: Suggests an audio stream whose volume should be changed by
300      *    the hardware volume controls.
301      * getVolumeControlStream: Gets the suggested audio stream whose volume should be changed by
302      *    the harwdare volume controls.
303      */
testAccessVolumeControlStream()304     public void testAccessVolumeControlStream() throws Exception {
305         // Default value is AudioManager.USE_DEFAULT_STREAM_TYPE, see javadoc of
306         // {@link Activity#setVolumeControlStream}.
307         assertEquals(AudioManager.USE_DEFAULT_STREAM_TYPE, mWindow.getVolumeControlStream());
308         mWindow.setVolumeControlStream(AudioManager.STREAM_MUSIC);
309         assertEquals(AudioManager.STREAM_MUSIC, mWindow.getVolumeControlStream());
310     }
311 
312     /**
313      * setWindowManager: Set the window manager for use by this Window.
314      * getWindowManager: Return the window manager allowing this Window to display its own
315      *    windows.
316      */
testAccessWindowManager()317     public void testAccessWindowManager() throws Exception {
318         mWindow = new MockWindow(getActivity());
319         WindowManager expected = (WindowManager) getActivity().getSystemService(
320                 Context.WINDOW_SERVICE);
321         assertNull(mWindow.getWindowManager());
322         mWindow.setWindowManager(expected, null, getName());
323         // No way to compare the expected and actual directly, they are
324         // different object
325         assertNotNull(mWindow.getWindowManager());
326     }
327 
328     /**
329      * Return the {@link android.R.styleable#Window} attributes from this
330      * window's theme. It's invisible.
331      */
testGetWindowStyle()332     public void testGetWindowStyle() throws Exception {
333         mWindow = new MockWindow(mContext);
334         final TypedArray windowStyle = mWindow.getWindowStyle();
335         // the windowStyle is obtained from
336         // com.android.internal.R.styleable.Window whose details
337         // are invisible for user.
338         assertNotNull(windowStyle);
339     }
340 
testIsActive()341     public void testIsActive() throws Exception {
342         MockWindow window = new MockWindow(mContext);
343         assertFalse(window.isActive());
344 
345         window.makeActive();
346         assertTrue(window.isActive());
347         assertTrue(window.mIsOnActiveCalled);
348     }
349 
350     /**
351      * isFloating: Return whether this window is being displayed with a floating style
352      * (based on the {@link android.R.attr#windowIsFloating} attribute in the style/theme).
353      */
testIsFloating()354     public void testIsFloating() throws Exception {
355         // Default system theme defined by themes.xml, the windowIsFloating is set false.
356         assertFalse(mWindow.isFloating());
357     }
358 
testPerformMethods()359     public void testPerformMethods() throws Exception {
360     }
361 
testKeepHierarchyState()362     public void testKeepHierarchyState() throws Exception {
363     }
364 
365     /**
366      * Change the background of this window to a custom Drawable.
367      * Setting the background to null will make the window be opaque(No way to get the window
368      *  attribute of PixelFormat to check if the window is opaque). To make the window
369      * transparent, you can use an empty drawable(eg. ColorDrawable with the color 0).
370      */
testSetBackgroundDrawable()371     public void testSetBackgroundDrawable() throws Throwable {
372         // DecorView holds the background
373         View decor = mWindow.getDecorView();
374         if (!mWindow.hasFeature(Window.FEATURE_SWIPE_TO_DISMISS)) {
375             assertEquals(PixelFormat.OPAQUE, decor.getBackground().getOpacity());
376         }
377         runTestOnUiThread(new Runnable() {
378             public void run() {
379                 // setBackgroundDrawableResource(int resId) has the same
380                 // functionality with
381                 // setBackgroundDrawable(Drawable drawable), just different in
382                 // parameter.
383                 mWindow.setBackgroundDrawableResource(R.drawable.faces);
384             }
385         });
386         mInstrumentation.waitForIdleSync();
387 
388         runTestOnUiThread(new Runnable() {
389             public void run() {
390                 ColorDrawable drawable = new ColorDrawable(0);
391                 mWindow.setBackgroundDrawable(drawable);
392             }
393         });
394         mInstrumentation.waitForIdleSync();
395         decor = mWindow.getDecorView();
396         // Color 0 with one alpha bit
397         assertEquals(PixelFormat.TRANSPARENT, decor.getBackground().getOpacity());
398 
399         runTestOnUiThread(new Runnable() {
400             public void run() {
401                 mWindow.setBackgroundDrawable(null);
402             }
403         });
404         mInstrumentation.waitForIdleSync();
405         decor = mWindow.getDecorView();
406         assertNull(decor.getBackground());
407     }
408 
testSetChild()409     public void testSetChild() throws Exception {
410     }
411 
412     /**
413      * setContentView(int): set the screen content from a layout resource.
414      * setContentView(View): set the screen content to an explicit view.
415      * setContentView(View, LayoutParams): Set the screen content to an explicit view.
416      *
417      * Note that calling this function "locks in" various characteristics
418      * of the window that can not, from this point forward, be changed: the
419      * features that have been requested with {@link #requestFeature(int)},
420      * and certain window flags as described in {@link #setFlags(int, int)}.
421      *   This functionality point is hard to test:
422      *   1. can't get the features requested because the getter is protected final.
423      *   2. certain window flags are not clear to concrete one.
424      */
testSetContentView()425     public void testSetContentView() throws Throwable {
426         final ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(VIEWGROUP_LAYOUT_WIDTH,
427                 VIEWGROUP_LAYOUT_HEIGHT);
428         final LayoutInflater inflate = mActivity.getLayoutInflater();
429 
430         runTestOnUiThread(new Runnable() {
431             public void run() {
432                 TextView view;
433                 View setView;
434                 // Test setContentView(int layoutResID)
435                 mWindow.setContentView(R.layout.windowstub_layout);
436                 view = (TextView) mWindow.findViewById(R.id.listview_window);
437                 assertNotNull(view);
438                 assertEquals(R.id.listview_window, view.getId());
439 
440                 // Test setContentView(View view)
441                 setView = inflate.inflate(R.layout.windowstub_addlayout, null);
442                 mWindow.setContentView(setView);
443                 view = (TextView) mWindow.findViewById(R.id.listview_addwindow);
444                 assertNotNull(view);
445                 assertEquals(R.id.listview_addwindow, view.getId());
446 
447                 // Test setContentView(View view, ViewGroup.LayoutParams params)
448                 setView = inflate.inflate(R.layout.windowstub_layout, null);
449                 mWindow.setContentView(setView, lp);
450                 assertEquals(VIEWGROUP_LAYOUT_WIDTH, setView.getLayoutParams().width);
451                 assertEquals(VIEWGROUP_LAYOUT_HEIGHT, setView.getLayoutParams().height);
452                 view = (TextView) mWindow.findViewById(R.id.listview_window);
453                 assertNotNull(view);
454                 assertEquals(R.id.listview_window, view.getId());
455             }
456         });
457         mInstrumentation.waitForIdleSync();
458     }
459 
460     /**
461      * setFeatureDrawable: Set an explicit Drawable value for feature of this window.
462      * setFeatureDrawableAlpha: Set a custom alpha value for the given drawale feature,
463      *    controlling how much the background is visible through it.
464      * setFeatureDrawableResource: Set the value for a drawable feature of this window, from
465      *    a resource identifier.
466      * setFeatureDrawableUri: Set the value for a drawable feature of this window, from a URI.
467      * setFeatureInt: Set the integer value for a feature.  The range of the value depends on
468      *    the feature being set.  For FEATURE_PROGRESSS, it should go from 0 to
469      *    10000. At 10000 the progress is complete and the indicator hidden
470      *
471      * the set views exist, and no getter way to check.
472      */
testSetFeature()473     public void testSetFeature() throws Throwable {
474     }
475 
testSetTitle()476     public void testSetTitle() throws Throwable {
477         final String title = "Android Window Test";
478         runTestOnUiThread(new Runnable() {
479             public void run() {
480                 mWindow.setTitle(title);
481                 mWindow.setTitleColor(Color.BLUE);
482             }
483         });
484         mInstrumentation.waitForIdleSync();
485         // No way to get title and title color
486     }
487 
488     /**
489      * These 3 methods: Used by custom windows, such as Dialog, to pass the key press event
490      * further down the view hierarchy. Application developers should not need to implement or
491      * call this.
492      */
testSuperDispatchEvent()493     public void testSuperDispatchEvent() throws Exception {
494     }
495 
496     /**
497      * takeKeyEvents: Request that key events come to this activity. Use this if your activity
498      * has no views with focus, but the activity still wants a chance to process key events.
499      */
testTakeKeyEvents()500     public void testTakeKeyEvents() throws Throwable {
501         runTestOnUiThread(new Runnable() {
502             public void run() {
503                 View v = mWindow.findViewById(R.id.listview_window);
504                 v.clearFocus();
505                 assertNull(mWindow.getCurrentFocus());
506                 mWindow.takeKeyEvents(false);
507             }
508         });
509         mInstrumentation.waitForIdleSync();
510         // sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
511         // assertFalse(mActivity.isOnKeyDownCalled());
512     }
513 
514     /**
515      * onConfigurationChanged: Should be called when the configuration is changed.
516      */
testOnConfigurationChanged()517     public void testOnConfigurationChanged() throws Exception {
518     }
519 
520     /**
521      * requestFeature: Enable extended screen features.
522      */
testRequestFeature()523     public void testRequestFeature() throws Exception {
524     }
525 
526     /**
527      * setDefaultWindowFormat: Set the format of window, as per the PixelFormat types. This
528      *    is the format that will be used unless the client specifies in explicit format with
529      *    setFormat().
530      * setFormat: Set the format of window, as per the PixelFormat types.
531      *            param format: The new window format (see PixelFormat).  Use
532      *                          PixelFormat.UNKNOWN to allow the Window to select
533      *                          the format.
534      */
testSetDefaultWindowFormat()535     public void testSetDefaultWindowFormat() throws Exception {
536         MockWindowCallback callback;
537         MockWindow window = new MockWindow(mContext);
538 
539         // mHaveWindowFormat will be true after set PixelFormat.OPAQUE and
540         // setDefaultWindowFormat is invalid
541         window.setFormat(PixelFormat.OPAQUE);
542         callback = new MockWindowCallback();
543         window.setCallback(callback);
544         assertFalse(callback.isOnWindowAttributesChangedCalled());
545         window.setDefaultWindowFormat(PixelFormat.JPEG);
546         assertEquals(PixelFormat.OPAQUE, window.getAttributes().format);
547         assertFalse(callback.isOnWindowAttributesChangedCalled());
548 
549         // mHaveWindowFormat will be false after set PixelFormat.UNKNOWN and
550         // setDefaultWindowFormat is valid
551         window.setFormat(PixelFormat.UNKNOWN);
552         callback = new MockWindowCallback();
553         window.setCallback(callback);
554         assertFalse(callback.isOnWindowAttributesChangedCalled());
555         window.setDefaultWindowFormat(PixelFormat.JPEG);
556         assertEquals(PixelFormat.JPEG, window.getAttributes().format);
557         assertTrue(callback.isOnWindowAttributesChangedCalled());
558     }
559 
560     /**
561      * Set the gravity of the window
562      */
testSetGravity()563     public void testSetGravity() throws Exception {
564         mWindow = new MockWindow(mContext);
565         WindowManager.LayoutParams attrs = mWindow.getAttributes();
566         assertEquals(0, attrs.gravity);
567 
568         MockWindowCallback callback = new MockWindowCallback();
569         mWindow.setCallback(callback);
570         assertFalse(callback.isOnWindowAttributesChangedCalled());
571         mWindow.setGravity(Gravity.TOP);
572         attrs = mWindow.getAttributes();
573         assertEquals(Gravity.TOP, attrs.gravity);
574         assertTrue(callback.isOnWindowAttributesChangedCalled());
575     }
576 
577     /**
578      * Set the width and height layout parameters of the window.
579      *    1.The default for both of these is MATCH_PARENT;
580      *    2.You can change them to WRAP_CONTENT to make a window that is not full-screen.
581      */
testSetLayout()582     public void testSetLayout() throws Exception {
583         mWindow = new MockWindow(mContext);
584         WindowManager.LayoutParams attrs = mWindow.getAttributes();
585         assertEquals(WindowManager.LayoutParams.MATCH_PARENT, attrs.width);
586         assertEquals(WindowManager.LayoutParams.MATCH_PARENT, attrs.height);
587 
588         MockWindowCallback callback = new MockWindowCallback();
589         mWindow.setCallback(callback);
590         assertFalse(callback.isOnWindowAttributesChangedCalled());
591         mWindow.setLayout(WindowManager.LayoutParams.WRAP_CONTENT,
592                 WindowManager.LayoutParams.WRAP_CONTENT);
593         attrs = mWindow.getAttributes();
594         assertEquals(WindowManager.LayoutParams.WRAP_CONTENT, attrs.width);
595         assertEquals(WindowManager.LayoutParams.WRAP_CONTENT, attrs.height);
596         assertTrue(callback.isOnWindowAttributesChangedCalled());
597     }
598 
599     /**
600      * Set the type of the window, as per the WindowManager.LayoutParams types.
601      */
testSetType()602     public void testSetType() throws Exception {
603         mWindow = new MockWindow(mContext);
604         WindowManager.LayoutParams attrs = mWindow.getAttributes();
605         assertEquals(WindowManager.LayoutParams.TYPE_APPLICATION, attrs.type);
606 
607         MockWindowCallback callback = new MockWindowCallback();
608         mWindow.setCallback(callback);
609         assertFalse(callback.isOnWindowAttributesChangedCalled());
610         mWindow.setType(WindowManager.LayoutParams.TYPE_BASE_APPLICATION);
611         attrs = mWindow.getAttributes();
612         assertEquals(WindowManager.LayoutParams.TYPE_BASE_APPLICATION, mWindow.getAttributes().type);
613         assertTrue(callback.isOnWindowAttributesChangedCalled());
614     }
615 
616     /**
617      * Specify an explicit soft input mode to use for the window, as per
618      * WindowManager.LayoutParams#softInputMode.
619      *    1.Providing "unspecified" here will NOT override the input mode the window.
620      *    2.Providing "unspecified" here will override the input mode the window.
621      */
testSetSoftInputMode()622     public void testSetSoftInputMode() throws Exception {
623         mWindow = new MockWindow(mContext);
624         assertEquals(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED,
625                 mWindow.getAttributes().softInputMode);
626         mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
627         assertEquals(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE,
628                 mWindow.getAttributes().softInputMode);
629         mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED);
630         assertEquals(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE,
631                 mWindow.getAttributes().softInputMode);
632     }
633 
634     /**
635      * Specify custom animations to use for the window, as per
636      * WindowManager.LayoutParams#windowAnimations.
637      *    1.Providing 0 here will NOT override the animations the window(But here we can't check
638      *    it because the getter is in WindowManagerService and is private)
639      *    2.Providing 0 here will override the animations the window.
640      */
testSetWindowAnimations()641     public void testSetWindowAnimations() throws Exception {
642         mWindow = new MockWindow(mContext);
643 
644         MockWindowCallback callback = new MockWindowCallback();
645         mWindow.setCallback(callback);
646         assertFalse(callback.isOnWindowAttributesChangedCalled());
647         mWindow.setWindowAnimations(R.anim.alpha);
648         WindowManager.LayoutParams attrs = mWindow.getAttributes();
649         assertEquals(R.anim.alpha, attrs.windowAnimations);
650         assertTrue(callback.isOnWindowAttributesChangedCalled());
651     }
652 
testFinalMethod()653     public void testFinalMethod() throws Exception {
654         // No way to test protected final method
655     }
656 
657     /**
658      * Test setLocalFocus together with injectInputEvent.
659      */
testSetLocalFocus()660     public void testSetLocalFocus() throws Throwable {
661         runTestOnUiThread(new Runnable() {
662             public void run() {
663                 surfaceView = new SurfaceView(mContext);
664             }
665         });
666         mInstrumentation.waitForIdleSync();
667 
668         final Semaphore waitingSemaphore = new Semaphore(0);
669         surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
670             @Override
671             public void surfaceCreated(SurfaceHolder holder) {
672             }
673 
674             @Override
675             public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
676                 destroyPresentation();
677                 createPresentation(holder.getSurface(), width, height);
678                 waitingSemaphore.release();
679             }
680 
681             @Override
682             public void surfaceDestroyed(SurfaceHolder holder) {
683                 destroyPresentation();
684             }
685           });
686         runTestOnUiThread(new Runnable() {
687             public void run() {
688                 mWindow.setContentView(surfaceView);
689             }
690         });
691         mInstrumentation.waitForIdleSync();
692         assertTrue(waitingSemaphore.tryAcquire(5, TimeUnit.SECONDS));
693         assertNotNull(mVirtualDisplay);
694         assertNotNull(mPresentation);
695         new PollingCheck() {
696             @Override
697             protected boolean check() {
698                 return (mPresentation.button1 != null) && (mPresentation.button2 != null) &&
699                         (mPresentation.button3 != null) && mPresentation.ready;
700             }
701         }.run();
702         assertTrue(mPresentation.button1.isFocusable() && mPresentation.button2.isFocusable() &&
703                 mPresentation.button3.isFocusable());
704         // currently it is only for debugging
705         View.OnFocusChangeListener listener = new View.OnFocusChangeListener() {
706             @Override
707             public void onFocusChange(View v, boolean hasFocus) {
708                 Log.d(TAG, "view " + v + " focus " + hasFocus);
709             }
710         };
711 
712         // check key event focus
713         mPresentation.button1.setOnFocusChangeListener(listener);
714         mPresentation.button2.setOnFocusChangeListener(listener);
715         mPresentation.button3.setOnFocusChangeListener(listener);
716         final Window presentationWindow = mPresentation.getWindow();
717         presentationWindow.setLocalFocus(true, false);
718         new PollingCheck() {
719             @Override
720             protected boolean check() {
721                 return mPresentation.button1.hasWindowFocus();
722             }
723         }.run();
724         checkPresentationButtonFocus(true, false, false);
725         assertFalse(mPresentation.button1.isInTouchMode());
726         injectKeyEvent(presentationWindow, KeyEvent.KEYCODE_TAB);
727         checkPresentationButtonFocus(false, true, false);
728         injectKeyEvent(presentationWindow, KeyEvent.KEYCODE_TAB);
729         checkPresentationButtonFocus(false, false, true);
730 
731         // check touch input injection
732         presentationWindow.setLocalFocus(true, true);
733         new PollingCheck() {
734             @Override
735             protected boolean check() {
736                 return mPresentation.button1.isInTouchMode();
737             }
738         }.run();
739         View.OnClickListener clickListener = new View.OnClickListener() {
740             @Override
741             public void onClick(View v) {
742                 Log.d(TAG, "onClick " + v);
743                 if (v == mPresentation.button1) {
744                     waitingSemaphore.release();
745                 }
746             }
747         };
748         mPresentation.button1.setOnClickListener(clickListener);
749         mPresentation.button2.setOnClickListener(clickListener);
750         mPresentation.button3.setOnClickListener(clickListener);
751         injectTouchEvent(presentationWindow, mPresentation.button1.getX() +
752                 mPresentation.button1.getWidth() / 2,
753                 mPresentation.button1.getY() + mPresentation.button1.getHeight() / 2);
754         assertTrue(waitingSemaphore.tryAcquire(5, TimeUnit.SECONDS));
755 
756         destroyPresentation();
757     }
758 
checkPresentationButtonFocus(final boolean button1Focused, final boolean button2Focused, final boolean button3Focused)759     private void checkPresentationButtonFocus(final boolean button1Focused,
760             final boolean button2Focused, final boolean button3Focused) {
761         new PollingCheck() {
762             @Override
763             protected boolean check() {
764                 return (mPresentation.button1.isFocused() == button1Focused) &&
765                         (mPresentation.button2.isFocused() == button2Focused) &&
766                         (mPresentation.button3.isFocused() == button3Focused);
767             }
768         }.run();
769     }
770 
injectKeyEvent(Window window, int keyCode)771     private void injectKeyEvent(Window window, int keyCode) {
772         KeyEvent downEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
773         window.injectInputEvent(downEvent);
774         KeyEvent upEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
775         window.injectInputEvent(upEvent);
776     }
777 
injectTouchEvent(Window window, float x, float y)778     private void injectTouchEvent(Window window, float x, float y) {
779         Log.d(TAG, "injectTouchEvent " + x + "," + y);
780         long downTime = SystemClock.uptimeMillis();
781         MotionEvent downEvent = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN,
782                 x, y, 0);
783         downEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
784         window.injectInputEvent(downEvent);
785         long upTime = SystemClock.uptimeMillis();
786         MotionEvent upEvent = MotionEvent.obtain(downTime, upTime, MotionEvent.ACTION_UP,
787                 x, y, 0);
788         upEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
789         window.injectInputEvent(upEvent);
790     }
791 
createPresentation(final Surface surface, final int width, final int height)792     private void createPresentation(final Surface surface, final int width,
793             final int height) {
794         Context context = getInstrumentation().getTargetContext();
795         DisplayManager displayManager =
796                 (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
797         mVirtualDisplay = displayManager.createVirtualDisplay("localFocusTest",
798                 width, height, 300, surface, 0);
799         mPresentation = new ProjectedPresentation(
800                 context, mVirtualDisplay.getDisplay());
801         mPresentation.show();
802     }
803 
destroyPresentation()804     private void destroyPresentation() {
805         if (mPresentation != null) {
806             mPresentation.dismiss();
807         }
808         if (mVirtualDisplay != null) {
809             mVirtualDisplay.release();
810         }
811     }
812 
813     private class ProjectedPresentation extends Presentation {
814         public Button button1 = null;
815         public Button button2 = null;
816         public Button button3 = null;
817         public volatile boolean ready = false;
818 
ProjectedPresentation(Context outerContext, Display display)819         public ProjectedPresentation(Context outerContext, Display display) {
820             super(outerContext, display);
821             getWindow().setType(WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
822             getWindow().addFlags(WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE);
823         }
824 
825         @Override
onCreate(Bundle savedInstanceState)826         protected void onCreate(Bundle savedInstanceState) {
827             super.onCreate(savedInstanceState);
828             setContentView(R.layout.windowstub_presentation);
829             button1 = (Button) findViewById(R.id.presentation_button1);
830             button2 = (Button) findViewById(R.id.presentation_button2);
831             button3 = (Button) findViewById(R.id.presentation_button3);
832         }
833 
834         @Override
show()835         public void show() {
836             super.show();
837             new Handler().post(new Runnable() {
838 
839                 @Override
840                 public void run() {
841                     ready = true;
842                 }
843             });
844         }
845     }
846 
847     public class MockWindow extends Window {
848         public boolean mIsOnConfigurationChangedCalled = false;
849         public boolean mIsOnActiveCalled = false;
850 
MockWindow(Context context)851         public MockWindow(Context context) {
852             super(context);
853         }
854 
isFloating()855         public boolean isFloating() {
856             return false;
857         }
858 
setContentView(int layoutResID)859         public void setContentView(int layoutResID) {
860         }
861 
setContentView(View view)862         public void setContentView(View view) {
863         }
864 
setContentView(View view, ViewGroup.LayoutParams params)865         public void setContentView(View view, ViewGroup.LayoutParams params) {
866         }
867 
addContentView(View view, ViewGroup.LayoutParams params)868         public void addContentView(View view, ViewGroup.LayoutParams params) {
869         }
870 
getCurrentFocus()871         public View getCurrentFocus() {
872             return null;
873         }
874 
getLayoutInflater()875         public LayoutInflater getLayoutInflater() {
876             return null;
877         }
878 
setTitle(CharSequence title)879         public void setTitle(CharSequence title) {
880         }
881 
setTitleColor(int textColor)882         public void setTitleColor(int textColor) {
883         }
884 
openPanel(int featureId, KeyEvent event)885         public void openPanel(int featureId, KeyEvent event) {
886         }
887 
closePanel(int featureId)888         public void closePanel(int featureId) {
889         }
890 
togglePanel(int featureId, KeyEvent event)891         public void togglePanel(int featureId, KeyEvent event) {
892         }
893 
invalidatePanelMenu(int featureId)894         public void invalidatePanelMenu(int featureId) {
895         }
896 
performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags)897         public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
898             return true;
899         }
900 
performPanelIdentifierAction(int featureId, int id, int flags)901         public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
902             return true;
903         }
904 
closeAllPanels()905         public void closeAllPanels() {
906         }
907 
performContextMenuIdentifierAction(int id, int flags)908         public boolean performContextMenuIdentifierAction(int id, int flags) {
909             return true;
910         }
911 
onConfigurationChanged(Configuration newConfig)912         public void onConfigurationChanged(Configuration newConfig) {
913             mIsOnConfigurationChangedCalled = true;
914         }
915 
setBackgroundDrawable(Drawable drawable)916         public void setBackgroundDrawable(Drawable drawable) {
917         }
918 
setFeatureDrawableResource(int featureId, int resId)919         public void setFeatureDrawableResource(int featureId, int resId) {
920         }
921 
setFeatureDrawableUri(int featureId, Uri uri)922         public void setFeatureDrawableUri(int featureId, Uri uri) {
923         }
924 
setFeatureDrawable(int featureId, Drawable drawable)925         public void setFeatureDrawable(int featureId, Drawable drawable) {
926         }
927 
setFeatureDrawableAlpha(int featureId, int alpha)928         public void setFeatureDrawableAlpha(int featureId, int alpha) {
929         }
930 
setFeatureInt(int featureId, int value)931         public void setFeatureInt(int featureId, int value) {
932         }
933 
takeKeyEvents(boolean get)934         public void takeKeyEvents(boolean get) {
935         }
936 
superDispatchKeyEvent(KeyEvent event)937         public boolean superDispatchKeyEvent(KeyEvent event) {
938             return true;
939         }
940 
superDispatchKeyShortcutEvent(KeyEvent event)941         public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
942             return false;
943         }
944 
superDispatchTouchEvent(MotionEvent event)945         public boolean superDispatchTouchEvent(MotionEvent event) {
946             return true;
947         }
948 
superDispatchTrackballEvent(MotionEvent event)949         public boolean superDispatchTrackballEvent(MotionEvent event) {
950             return true;
951         }
952 
superDispatchGenericMotionEvent(MotionEvent event)953         public boolean superDispatchGenericMotionEvent(MotionEvent event) {
954             return true;
955         }
956 
getDecorView()957         public View getDecorView() {
958             return null;
959         }
960 
alwaysReadCloseOnTouchAttr()961         public void alwaysReadCloseOnTouchAttr() {
962         }
963 
peekDecorView()964         public View peekDecorView() {
965             return null;
966         }
967 
saveHierarchyState()968         public Bundle saveHierarchyState() {
969             return null;
970         }
971 
restoreHierarchyState(Bundle savedInstanceState)972         public void restoreHierarchyState(Bundle savedInstanceState) {
973         }
974 
onActive()975         protected void onActive() {
976             mIsOnActiveCalled = true;
977         }
978 
setChildDrawable(int featureId, Drawable drawable)979         public void setChildDrawable(int featureId, Drawable drawable) {
980 
981         }
982 
setChildInt(int featureId, int value)983         public void setChildInt(int featureId, int value) {
984         }
985 
isShortcutKey(int keyCode, KeyEvent event)986         public boolean isShortcutKey(int keyCode, KeyEvent event) {
987             return false;
988         }
989 
setVolumeControlStream(int streamType)990         public void setVolumeControlStream(int streamType) {
991         }
992 
getVolumeControlStream()993         public int getVolumeControlStream() {
994             return 0;
995         }
996 
setDefaultWindowFormatFake(int format)997         public void setDefaultWindowFormatFake(int format) {
998             super.setDefaultWindowFormat(format);
999         }
1000 
1001         @Override
setDefaultWindowFormat(int format)1002         public void setDefaultWindowFormat(int format) {
1003             super.setDefaultWindowFormat(format);
1004         }
1005 
1006         @Override
takeSurface(SurfaceHolder.Callback2 callback)1007         public void takeSurface(SurfaceHolder.Callback2 callback) {
1008         }
1009 
1010         @Override
takeInputQueue(InputQueue.Callback callback)1011         public void takeInputQueue(InputQueue.Callback callback) {
1012         }
1013 
1014         @Override
setStatusBarColor(int color)1015         public void setStatusBarColor(int color) {
1016         }
1017 
1018         @Override
getStatusBarColor()1019         public int getStatusBarColor() {
1020             return 0;
1021         }
1022 
1023         @Override
setNavigationBarColor(int color)1024         public void setNavigationBarColor(int color) {
1025         }
1026 
1027         @Override
getNavigationBarColor()1028         public int getNavigationBarColor() {
1029             return 0;
1030         }
1031     }
1032 
1033     private class MockWindowCallback implements Window.Callback {
1034         private boolean mIsOnWindowAttributesChangedCalled;
1035         private boolean mIsOnPanelClosedCalled;
1036 
dispatchKeyEvent(KeyEvent event)1037         public boolean dispatchKeyEvent(KeyEvent event) {
1038             return true;
1039         }
1040 
dispatchKeyShortcutEvent(KeyEvent event)1041         public boolean dispatchKeyShortcutEvent(KeyEvent event) {
1042             return false;
1043         }
1044 
dispatchTouchEvent(MotionEvent event)1045         public boolean dispatchTouchEvent(MotionEvent event) {
1046             return true;
1047         }
1048 
dispatchTrackballEvent(MotionEvent event)1049         public boolean dispatchTrackballEvent(MotionEvent event) {
1050             return true;
1051         }
1052 
dispatchGenericMotionEvent(MotionEvent event)1053         public boolean dispatchGenericMotionEvent(MotionEvent event) {
1054             return true;
1055         }
1056 
dispatchPopulateAccessibilityEvent(AccessibilityEvent event)1057         public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1058             return true;
1059         }
1060 
onCreatePanelView(int featureId)1061         public View onCreatePanelView(int featureId) {
1062             return null;
1063         }
1064 
onCreatePanelMenu(int featureId, Menu menu)1065         public boolean onCreatePanelMenu(int featureId, Menu menu) {
1066             return false;
1067         }
1068 
onPreparePanel(int featureId, View view, Menu menu)1069         public boolean onPreparePanel(int featureId, View view, Menu menu) {
1070             return false;
1071         }
1072 
onMenuOpened(int featureId, Menu menu)1073         public boolean onMenuOpened(int featureId, Menu menu) {
1074             return false;
1075         }
1076 
onMenuItemSelected(int featureId, MenuItem item)1077         public boolean onMenuItemSelected(int featureId, MenuItem item) {
1078             return true;
1079         }
1080 
onWindowAttributesChanged(WindowManager.LayoutParams attrs)1081         public void onWindowAttributesChanged(WindowManager.LayoutParams attrs) {
1082             mIsOnWindowAttributesChangedCalled = true;
1083         }
1084 
isOnWindowAttributesChangedCalled()1085         public boolean isOnWindowAttributesChangedCalled() {
1086             return mIsOnWindowAttributesChangedCalled;
1087         }
1088 
onContentChanged()1089         public void onContentChanged() {
1090         }
1091 
onWindowFocusChanged(boolean hasFocus)1092         public void onWindowFocusChanged(boolean hasFocus) {
1093         }
1094 
onDetachedFromWindow()1095         public void onDetachedFromWindow() {
1096         }
1097 
onAttachedToWindow()1098         public void onAttachedToWindow() {
1099         }
1100 
onPanelClosed(int featureId, Menu menu)1101         public void onPanelClosed(int featureId, Menu menu) {
1102             mIsOnPanelClosedCalled = true;
1103         }
1104 
isOnPanelClosedCalled()1105         public boolean isOnPanelClosedCalled() {
1106             return mIsOnPanelClosedCalled;
1107         }
1108 
onSearchRequested(SearchEvent searchEvent)1109         public boolean onSearchRequested(SearchEvent searchEvent) {
1110             return onSearchRequested();
1111         }
1112 
onSearchRequested()1113         public boolean onSearchRequested() {
1114             return false;
1115         }
1116 
onWindowStartingActionMode(ActionMode.Callback callback)1117         public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
1118             return null;
1119         }
1120 
onWindowStartingActionMode( ActionMode.Callback callback, int type)1121         public ActionMode onWindowStartingActionMode(
1122                 ActionMode.Callback callback, int type) {
1123             return null;
1124         }
1125 
onActionModeStarted(ActionMode mode)1126         public void onActionModeStarted(ActionMode mode) {
1127         }
1128 
onActionModeFinished(ActionMode mode)1129         public void onActionModeFinished(ActionMode mode) {
1130         }
1131 
onWindowDismissed()1132         public void onWindowDismissed() {
1133         }
1134     }
1135 }
1136