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