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