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