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