1 /* 2 * Copyright (C) 2006 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; 18 19 import android.Manifest; 20 import android.animation.LayoutTransition; 21 import android.app.ActivityManagerNative; 22 import android.content.ClipDescription; 23 import android.content.ComponentCallbacks; 24 import android.content.ComponentCallbacks2; 25 import android.content.Context; 26 import android.content.pm.ApplicationInfo; 27 import android.content.pm.PackageManager; 28 import android.content.res.CompatibilityInfo; 29 import android.content.res.Configuration; 30 import android.content.res.Resources; 31 import android.graphics.Canvas; 32 import android.graphics.Paint; 33 import android.graphics.PixelFormat; 34 import android.graphics.Point; 35 import android.graphics.PointF; 36 import android.graphics.PorterDuff; 37 import android.graphics.Rect; 38 import android.graphics.Region; 39 import android.graphics.drawable.Drawable; 40 import android.media.AudioManager; 41 import android.os.Binder; 42 import android.os.Bundle; 43 import android.os.Debug; 44 import android.os.Handler; 45 import android.os.LatencyTimer; 46 import android.os.Looper; 47 import android.os.Message; 48 import android.os.ParcelFileDescriptor; 49 import android.os.PowerManager; 50 import android.os.Process; 51 import android.os.RemoteException; 52 import android.os.SystemClock; 53 import android.os.SystemProperties; 54 import android.os.Trace; 55 import android.util.AndroidRuntimeException; 56 import android.util.DisplayMetrics; 57 import android.util.Log; 58 import android.util.Slog; 59 import android.util.TypedValue; 60 import android.view.View.AttachInfo; 61 import android.view.View.MeasureSpec; 62 import android.view.accessibility.AccessibilityEvent; 63 import android.view.accessibility.AccessibilityManager; 64 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; 65 import android.view.accessibility.AccessibilityNodeInfo; 66 import android.view.accessibility.AccessibilityNodeProvider; 67 import android.view.accessibility.IAccessibilityInteractionConnection; 68 import android.view.accessibility.IAccessibilityInteractionConnectionCallback; 69 import android.view.animation.AccelerateDecelerateInterpolator; 70 import android.view.animation.Interpolator; 71 import android.view.inputmethod.InputConnection; 72 import android.view.inputmethod.InputMethodManager; 73 import android.widget.Scroller; 74 75 import com.android.internal.R; 76 import com.android.internal.os.SomeArgs; 77 import com.android.internal.policy.PolicyManager; 78 import com.android.internal.view.BaseSurfaceHolder; 79 import com.android.internal.view.RootViewSurfaceTaker; 80 81 import java.io.IOException; 82 import java.io.OutputStream; 83 import java.lang.ref.WeakReference; 84 import java.util.ArrayList; 85 import java.util.HashSet; 86 87 /** 88 * The top of a view hierarchy, implementing the needed protocol between View 89 * and the WindowManager. This is for the most part an internal implementation 90 * detail of {@link WindowManagerGlobal}. 91 * 92 * {@hide} 93 */ 94 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"}) 95 public final class ViewRootImpl implements ViewParent, 96 View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { 97 private static final String TAG = "ViewRootImpl"; 98 private static final boolean DBG = false; 99 private static final boolean LOCAL_LOGV = false; 100 /** @noinspection PointlessBooleanExpression*/ 101 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV; 102 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV; 103 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV; 104 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV; 105 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV; 106 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV; 107 private static final boolean DEBUG_IMF = false || LOCAL_LOGV; 108 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV; 109 private static final boolean DEBUG_FPS = false; 110 111 private static final boolean USE_RENDER_THREAD = false; 112 113 /** 114 * Set this system property to true to force the view hierarchy to render 115 * at 60 Hz. This can be used to measure the potential framerate. 116 */ 117 private static final String PROPERTY_PROFILE_RENDERING = "viewancestor.profile_rendering"; 118 119 private static final boolean MEASURE_LATENCY = false; 120 private static LatencyTimer lt; 121 122 /** 123 * Maximum time we allow the user to roll the trackball enough to generate 124 * a key event, before resetting the counters. 125 */ 126 static final int MAX_TRACKBALL_DELAY = 250; 127 128 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>(); 129 130 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>(); 131 static boolean sFirstDrawComplete = false; 132 133 static final ArrayList<ComponentCallbacks> sConfigCallbacks 134 = new ArrayList<ComponentCallbacks>(); 135 136 private static boolean sUseRenderThread = false; 137 private static boolean sRenderThreadQueried = false; 138 private static final Object[] sRenderThreadQueryLock = new Object[0]; 139 140 final IWindowSession mWindowSession; 141 final Display mDisplay; 142 143 long mLastTrackballTime = 0; 144 final TrackballAxis mTrackballAxisX = new TrackballAxis(); 145 final TrackballAxis mTrackballAxisY = new TrackballAxis(); 146 147 int mLastJoystickXDirection; 148 int mLastJoystickYDirection; 149 int mLastJoystickXKeyCode; 150 int mLastJoystickYKeyCode; 151 152 final int[] mTmpLocation = new int[2]; 153 154 final TypedValue mTmpValue = new TypedValue(); 155 156 final InputMethodCallback mInputMethodCallback; 157 final Thread mThread; 158 159 final WindowLeaked mLocation; 160 161 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams(); 162 163 final W mWindow; 164 165 final int mTargetSdkVersion; 166 167 int mSeq; 168 169 View mView; 170 View mFocusedView; 171 View mRealFocusedView; // this is not set to null in touch mode 172 View mOldFocusedView; 173 174 View mAccessibilityFocusedHost; 175 AccessibilityNodeInfo mAccessibilityFocusedVirtualView; 176 177 int mViewVisibility; 178 boolean mAppVisible = true; 179 int mOrigWindowType = -1; 180 181 // Set to true if the owner of this window is in the stopped state, 182 // so the window should no longer be active. 183 boolean mStopped = false; 184 185 boolean mLastInCompatMode = false; 186 187 SurfaceHolder.Callback2 mSurfaceHolderCallback; 188 BaseSurfaceHolder mSurfaceHolder; 189 boolean mIsCreating; 190 boolean mDrawingAllowed; 191 192 final Region mTransparentRegion; 193 final Region mPreviousTransparentRegion; 194 195 int mWidth; 196 int mHeight; 197 Rect mDirty; 198 final Rect mCurrentDirty = new Rect(); 199 final Rect mPreviousDirty = new Rect(); 200 boolean mIsAnimating; 201 202 CompatibilityInfo.Translator mTranslator; 203 204 final View.AttachInfo mAttachInfo; 205 InputChannel mInputChannel; 206 InputQueue.Callback mInputQueueCallback; 207 InputQueue mInputQueue; 208 FallbackEventHandler mFallbackEventHandler; 209 Choreographer mChoreographer; 210 211 final Rect mTempRect; // used in the transaction to not thrash the heap. 212 final Rect mVisRect; // used to retrieve visible rect of focused view. 213 214 boolean mTraversalScheduled; 215 int mTraversalBarrier; 216 boolean mWillDrawSoon; 217 /** Set to true while in performTraversals for detecting when die(true) is called from internal 218 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */ 219 boolean mIsInTraversal; 220 boolean mFitSystemWindowsRequested; 221 boolean mLayoutRequested; 222 boolean mFirst; 223 boolean mReportNextDraw; 224 boolean mFullRedrawNeeded; 225 boolean mNewSurfaceNeeded; 226 boolean mHasHadWindowFocus; 227 boolean mLastWasImTarget; 228 boolean mWindowsAnimating; 229 boolean mIsDrawing; 230 int mLastSystemUiVisibility; 231 int mClientWindowLayoutFlags; 232 233 // Pool of queued input events. 234 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10; 235 private QueuedInputEvent mQueuedInputEventPool; 236 private int mQueuedInputEventPoolSize; 237 238 // Input event queue. 239 QueuedInputEvent mFirstPendingInputEvent; 240 QueuedInputEvent mCurrentInputEvent; 241 boolean mProcessInputEventsScheduled; 242 243 boolean mWindowAttributesChanged = false; 244 int mWindowAttributesChangesFlag = 0; 245 246 // These can be accessed by any thread, must be protected with a lock. 247 // Surface can never be reassigned or cleared (use Surface.clear()). 248 private final Surface mSurface = new Surface(); 249 250 boolean mAdded; 251 boolean mAddedTouchMode; 252 253 final CompatibilityInfoHolder mCompatibilityInfo; 254 255 // These are accessed by multiple threads. 256 final Rect mWinFrame; // frame given by window manager. 257 258 final Rect mPendingVisibleInsets = new Rect(); 259 final Rect mPendingContentInsets = new Rect(); 260 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets 261 = new ViewTreeObserver.InternalInsetsInfo(); 262 263 final Rect mFitSystemWindowsInsets = new Rect(); 264 265 final Configuration mLastConfiguration = new Configuration(); 266 final Configuration mPendingConfiguration = new Configuration(); 267 268 boolean mScrollMayChange; 269 int mSoftInputMode; 270 View mLastScrolledFocus; 271 int mScrollY; 272 int mCurScrollY; 273 Scroller mScroller; 274 HardwareLayer mResizeBuffer; 275 long mResizeBufferStartTime; 276 int mResizeBufferDuration; 277 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator(); 278 private ArrayList<LayoutTransition> mPendingTransitions; 279 280 final ViewConfiguration mViewConfiguration; 281 282 /* Drag/drop */ 283 ClipDescription mDragDescription; 284 View mCurrentDragView; 285 volatile Object mLocalDragState; 286 final PointF mDragPoint = new PointF(); 287 final PointF mLastTouchPoint = new PointF(); 288 289 private boolean mProfileRendering; 290 private Thread mRenderProfiler; 291 private volatile boolean mRenderProfilingEnabled; 292 293 // Variables to track frames per second, enabled via DEBUG_FPS flag 294 private long mFpsStartTime = -1; 295 private long mFpsPrevTime = -1; 296 private int mFpsNumFrames; 297 298 private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>(24); 299 300 /** 301 * see {@link #playSoundEffect(int)} 302 */ 303 AudioManager mAudioManager; 304 305 final AccessibilityManager mAccessibilityManager; 306 307 AccessibilityInteractionController mAccessibilityInteractionController; 308 309 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager; 310 311 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent; 312 313 HashSet<View> mTempHashSet; 314 315 private final int mDensity; 316 private final int mNoncompatDensity; 317 318 private int mViewLayoutDirectionInitial; 319 320 /** 321 * Consistency verifier for debugging purposes. 322 */ 323 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 324 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 325 new InputEventConsistencyVerifier(this, 0) : null; 326 327 static final class SystemUiVisibilityInfo { 328 int seq; 329 int globalVisibility; 330 int localValue; 331 int localChanges; 332 } 333 ViewRootImpl(Context context, Display display)334 public ViewRootImpl(Context context, Display display) { 335 super(); 336 337 if (MEASURE_LATENCY) { 338 if (lt == null) { 339 lt = new LatencyTimer(100, 1000); 340 } 341 } 342 343 // Initialize the statics when this class is first instantiated. This is 344 // done here instead of in the static block because Zygote does not 345 // allow the spawning of threads. 346 mWindowSession = WindowManagerGlobal.getWindowSession(context.getMainLooper()); 347 mDisplay = display; 348 349 CompatibilityInfoHolder cih = display.getCompatibilityInfo(); 350 mCompatibilityInfo = cih != null ? cih : new CompatibilityInfoHolder(); 351 352 mThread = Thread.currentThread(); 353 mLocation = new WindowLeaked(null); 354 mLocation.fillInStackTrace(); 355 mWidth = -1; 356 mHeight = -1; 357 mDirty = new Rect(); 358 mTempRect = new Rect(); 359 mVisRect = new Rect(); 360 mWinFrame = new Rect(); 361 mWindow = new W(this); 362 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; 363 mInputMethodCallback = new InputMethodCallback(this); 364 mViewVisibility = View.GONE; 365 mTransparentRegion = new Region(); 366 mPreviousTransparentRegion = new Region(); 367 mFirst = true; // true for the first time the view is added 368 mAdded = false; 369 mAccessibilityManager = AccessibilityManager.getInstance(context); 370 mAccessibilityInteractionConnectionManager = 371 new AccessibilityInteractionConnectionManager(); 372 mAccessibilityManager.addAccessibilityStateChangeListener( 373 mAccessibilityInteractionConnectionManager); 374 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this); 375 mViewConfiguration = ViewConfiguration.get(context); 376 mDensity = context.getResources().getDisplayMetrics().densityDpi; 377 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi; 378 mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context); 379 mProfileRendering = Boolean.parseBoolean( 380 SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false")); 381 mChoreographer = Choreographer.getInstance(); 382 383 PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 384 mAttachInfo.mScreenOn = powerManager.isScreenOn(); 385 loadSystemProperties(); 386 } 387 388 /** 389 * @return True if the application requests the use of a separate render thread, 390 * false otherwise 391 */ isRenderThreadRequested(Context context)392 private static boolean isRenderThreadRequested(Context context) { 393 if (USE_RENDER_THREAD) { 394 synchronized (sRenderThreadQueryLock) { 395 if (!sRenderThreadQueried) { 396 final PackageManager packageManager = context.getPackageManager(); 397 final String packageName = context.getApplicationInfo().packageName; 398 try { 399 ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 400 PackageManager.GET_META_DATA); 401 if (applicationInfo.metaData != null) { 402 sUseRenderThread = applicationInfo.metaData.getBoolean( 403 "android.graphics.renderThread", false); 404 } 405 } catch (PackageManager.NameNotFoundException e) { 406 } finally { 407 sRenderThreadQueried = true; 408 } 409 } 410 return sUseRenderThread; 411 } 412 } else { 413 return false; 414 } 415 } 416 addFirstDrawHandler(Runnable callback)417 public static void addFirstDrawHandler(Runnable callback) { 418 synchronized (sFirstDrawHandlers) { 419 if (!sFirstDrawComplete) { 420 sFirstDrawHandlers.add(callback); 421 } 422 } 423 } 424 addConfigCallback(ComponentCallbacks callback)425 public static void addConfigCallback(ComponentCallbacks callback) { 426 synchronized (sConfigCallbacks) { 427 sConfigCallbacks.add(callback); 428 } 429 } 430 431 // FIXME for perf testing only 432 private boolean mProfile = false; 433 434 /** 435 * Call this to profile the next traversal call. 436 * FIXME for perf testing only. Remove eventually 437 */ profile()438 public void profile() { 439 mProfile = true; 440 } 441 442 /** 443 * Indicates whether we are in touch mode. Calling this method triggers an IPC 444 * call and should be avoided whenever possible. 445 * 446 * @return True, if the device is in touch mode, false otherwise. 447 * 448 * @hide 449 */ isInTouchMode()450 static boolean isInTouchMode() { 451 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession(); 452 if (windowSession != null) { 453 try { 454 return windowSession.getInTouchMode(); 455 } catch (RemoteException e) { 456 } 457 } 458 return false; 459 } 460 461 /** 462 * We have one child 463 */ setView(View view, WindowManager.LayoutParams attrs, View panelParentView)464 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { 465 synchronized (this) { 466 if (mView == null) { 467 mView = view; 468 mViewLayoutDirectionInitial = mView.getRawLayoutDirection(); 469 mFallbackEventHandler.setView(view); 470 mWindowAttributes.copyFrom(attrs); 471 attrs = mWindowAttributes; 472 // Keep track of the actual window flags supplied by the client. 473 mClientWindowLayoutFlags = attrs.flags; 474 475 setAccessibilityFocus(null, null); 476 477 if (view instanceof RootViewSurfaceTaker) { 478 mSurfaceHolderCallback = 479 ((RootViewSurfaceTaker)view).willYouTakeTheSurface(); 480 if (mSurfaceHolderCallback != null) { 481 mSurfaceHolder = new TakenSurfaceHolder(); 482 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN); 483 } 484 } 485 486 CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get(); 487 mTranslator = compatibilityInfo.getTranslator(); 488 489 // If the application owns the surface, don't enable hardware acceleration 490 if (mSurfaceHolder == null) { 491 enableHardwareAcceleration(mView.getContext(), attrs); 492 } 493 494 boolean restore = false; 495 if (mTranslator != null) { 496 mSurface.setCompatibilityTranslator(mTranslator); 497 restore = true; 498 attrs.backup(); 499 mTranslator.translateWindowLayout(attrs); 500 } 501 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs); 502 503 if (!compatibilityInfo.supportsScreen()) { 504 attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; 505 mLastInCompatMode = true; 506 } 507 508 mSoftInputMode = attrs.softInputMode; 509 mWindowAttributesChanged = true; 510 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED; 511 mAttachInfo.mRootView = view; 512 mAttachInfo.mScalingRequired = mTranslator != null; 513 mAttachInfo.mApplicationScale = 514 mTranslator == null ? 1.0f : mTranslator.applicationScale; 515 if (panelParentView != null) { 516 mAttachInfo.mPanelParentWindowToken 517 = panelParentView.getApplicationWindowToken(); 518 } 519 mAdded = true; 520 int res; /* = WindowManagerImpl.ADD_OKAY; */ 521 522 // Schedule the first layout -before- adding to the window 523 // manager, to make sure we do the relayout before receiving 524 // any other events from the system. 525 requestLayout(); 526 if ((mWindowAttributes.inputFeatures 527 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { 528 mInputChannel = new InputChannel(); 529 } 530 try { 531 mOrigWindowType = mWindowAttributes.type; 532 mAttachInfo.mRecomputeGlobalAttributes = true; 533 collectViewAttributes(); 534 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, 535 getHostVisibility(), mDisplay.getDisplayId(), 536 mAttachInfo.mContentInsets, mInputChannel); 537 } catch (RemoteException e) { 538 mAdded = false; 539 mView = null; 540 mAttachInfo.mRootView = null; 541 mInputChannel = null; 542 mFallbackEventHandler.setView(null); 543 unscheduleTraversals(); 544 setAccessibilityFocus(null, null); 545 throw new RuntimeException("Adding window failed", e); 546 } finally { 547 if (restore) { 548 attrs.restore(); 549 } 550 } 551 552 if (mTranslator != null) { 553 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets); 554 } 555 mPendingContentInsets.set(mAttachInfo.mContentInsets); 556 mPendingVisibleInsets.set(0, 0, 0, 0); 557 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow); 558 if (res < WindowManagerGlobal.ADD_OKAY) { 559 mAttachInfo.mRootView = null; 560 mAdded = false; 561 mFallbackEventHandler.setView(null); 562 unscheduleTraversals(); 563 setAccessibilityFocus(null, null); 564 switch (res) { 565 case WindowManagerGlobal.ADD_BAD_APP_TOKEN: 566 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN: 567 throw new WindowManager.BadTokenException( 568 "Unable to add window -- token " + attrs.token 569 + " is not valid; is your activity running?"); 570 case WindowManagerGlobal.ADD_NOT_APP_TOKEN: 571 throw new WindowManager.BadTokenException( 572 "Unable to add window -- token " + attrs.token 573 + " is not for an application"); 574 case WindowManagerGlobal.ADD_APP_EXITING: 575 throw new WindowManager.BadTokenException( 576 "Unable to add window -- app for token " + attrs.token 577 + " is exiting"); 578 case WindowManagerGlobal.ADD_DUPLICATE_ADD: 579 throw new WindowManager.BadTokenException( 580 "Unable to add window -- window " + mWindow 581 + " has already been added"); 582 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED: 583 // Silently ignore -- we would have just removed it 584 // right away, anyway. 585 return; 586 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON: 587 throw new WindowManager.BadTokenException( 588 "Unable to add window " + mWindow + 589 " -- another window of this type already exists"); 590 case WindowManagerGlobal.ADD_PERMISSION_DENIED: 591 throw new WindowManager.BadTokenException( 592 "Unable to add window " + mWindow + 593 " -- permission denied for this window type"); 594 case WindowManagerGlobal.ADD_INVALID_DISPLAY: 595 throw new WindowManager.InvalidDisplayException( 596 "Unable to add window " + mWindow + 597 " -- the specified display can not be found"); 598 } 599 throw new RuntimeException( 600 "Unable to add window -- unknown error code " + res); 601 } 602 603 if (view instanceof RootViewSurfaceTaker) { 604 mInputQueueCallback = 605 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue(); 606 } 607 if (mInputChannel != null) { 608 if (mInputQueueCallback != null) { 609 mInputQueue = new InputQueue(mInputChannel); 610 mInputQueueCallback.onInputQueueCreated(mInputQueue); 611 } else { 612 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, 613 Looper.myLooper()); 614 } 615 } 616 617 view.assignParent(this); 618 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0; 619 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0; 620 621 if (mAccessibilityManager.isEnabled()) { 622 mAccessibilityInteractionConnectionManager.ensureConnection(); 623 } 624 625 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 626 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); 627 } 628 } 629 } 630 } 631 destroyHardwareResources()632 void destroyHardwareResources() { 633 if (mAttachInfo.mHardwareRenderer != null) { 634 if (mAttachInfo.mHardwareRenderer.isEnabled()) { 635 mAttachInfo.mHardwareRenderer.destroyLayers(mView); 636 } 637 mAttachInfo.mHardwareRenderer.destroy(false); 638 } 639 } 640 terminateHardwareResources()641 void terminateHardwareResources() { 642 if (mAttachInfo.mHardwareRenderer != null) { 643 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView); 644 mAttachInfo.mHardwareRenderer.destroy(false); 645 } 646 } 647 destroyHardwareLayers()648 void destroyHardwareLayers() { 649 if (mThread != Thread.currentThread()) { 650 if (mAttachInfo.mHardwareRenderer != null && 651 mAttachInfo.mHardwareRenderer.isEnabled()) { 652 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE); 653 } 654 } else { 655 if (mAttachInfo.mHardwareRenderer != null && 656 mAttachInfo.mHardwareRenderer.isEnabled()) { 657 mAttachInfo.mHardwareRenderer.destroyLayers(mView); 658 } 659 } 660 } 661 pushHardwareLayerUpdate(HardwareLayer layer)662 void pushHardwareLayerUpdate(HardwareLayer layer) { 663 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { 664 mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer); 665 } 666 } 667 attachFunctor(int functor)668 public boolean attachFunctor(int functor) { 669 //noinspection SimplifiableIfStatement 670 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { 671 return mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor); 672 } 673 return false; 674 } 675 detachFunctor(int functor)676 public void detachFunctor(int functor) { 677 if (mAttachInfo.mHardwareRenderer != null) { 678 mAttachInfo.mHardwareRenderer.detachFunctor(functor); 679 } 680 } 681 enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs)682 private void enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs) { 683 mAttachInfo.mHardwareAccelerated = false; 684 mAttachInfo.mHardwareAccelerationRequested = false; 685 686 // Don't enable hardware acceleration when the application is in compatibility mode 687 if (mTranslator != null) return; 688 689 // Try to enable hardware acceleration if requested 690 final boolean hardwareAccelerated = 691 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; 692 693 if (hardwareAccelerated) { 694 if (!HardwareRenderer.isAvailable()) { 695 return; 696 } 697 698 // Persistent processes (including the system) should not do 699 // accelerated rendering on low-end devices. In that case, 700 // sRendererDisabled will be set. In addition, the system process 701 // itself should never do accelerated rendering. In that case, both 702 // sRendererDisabled and sSystemRendererDisabled are set. When 703 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED 704 // can be used by code on the system process to escape that and enable 705 // HW accelerated drawing. (This is basically for the lock screen.) 706 707 final boolean fakeHwAccelerated = (attrs.privateFlags & 708 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0; 709 final boolean forceHwAccelerated = (attrs.privateFlags & 710 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0; 711 712 if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled 713 && forceHwAccelerated)) { 714 // Don't enable hardware acceleration when we're not on the main thread 715 if (!HardwareRenderer.sSystemRendererDisabled && 716 Looper.getMainLooper() != Looper.myLooper()) { 717 Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware " 718 + "acceleration outside of the main thread, aborting"); 719 return; 720 } 721 722 final boolean renderThread = isRenderThreadRequested(context); 723 if (renderThread) { 724 Log.i(HardwareRenderer.LOG_TAG, "Render threat initiated"); 725 } 726 727 if (mAttachInfo.mHardwareRenderer != null) { 728 mAttachInfo.mHardwareRenderer.destroy(true); 729 } 730 731 final boolean translucent = attrs.format != PixelFormat.OPAQUE; 732 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent); 733 mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested 734 = mAttachInfo.mHardwareRenderer != null; 735 736 } else if (fakeHwAccelerated) { 737 // The window had wanted to use hardware acceleration, but this 738 // is not allowed in its process. By setting this flag, it can 739 // still render as if it was accelerated. This is basically for 740 // the preview windows the window manager shows for launching 741 // applications, so they will look more like the app being launched. 742 mAttachInfo.mHardwareAccelerationRequested = true; 743 } 744 } 745 } 746 getView()747 public View getView() { 748 return mView; 749 } 750 getLocation()751 final WindowLeaked getLocation() { 752 return mLocation; 753 } 754 setLayoutParams(WindowManager.LayoutParams attrs, boolean newView)755 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) { 756 synchronized (this) { 757 int oldSoftInputMode = mWindowAttributes.softInputMode; 758 // Keep track of the actual window flags supplied by the client. 759 mClientWindowLayoutFlags = attrs.flags; 760 // preserve compatible window flag if exists. 761 int compatibleWindowFlag = 762 mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; 763 // transfer over system UI visibility values as they carry current state. 764 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility; 765 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility; 766 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs); 767 mWindowAttributes.flags |= compatibleWindowFlag; 768 769 applyKeepScreenOnFlag(mWindowAttributes); 770 771 if (newView) { 772 mSoftInputMode = attrs.softInputMode; 773 requestLayout(); 774 } 775 // Don't lose the mode we last auto-computed. 776 if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) 777 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { 778 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode 779 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) 780 | (oldSoftInputMode 781 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST); 782 } 783 mWindowAttributesChanged = true; 784 scheduleTraversals(); 785 } 786 } 787 handleAppVisibility(boolean visible)788 void handleAppVisibility(boolean visible) { 789 if (mAppVisible != visible) { 790 mAppVisible = visible; 791 scheduleTraversals(); 792 } 793 } 794 handleGetNewSurface()795 void handleGetNewSurface() { 796 mNewSurfaceNeeded = true; 797 mFullRedrawNeeded = true; 798 scheduleTraversals(); 799 } 800 handleScreenStateChange(boolean on)801 void handleScreenStateChange(boolean on) { 802 if (on != mAttachInfo.mScreenOn) { 803 mAttachInfo.mScreenOn = on; 804 if (mView != null) { 805 mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF); 806 } 807 if (on) { 808 mFullRedrawNeeded = true; 809 scheduleTraversals(); 810 } 811 } 812 } 813 814 @Override requestFitSystemWindows()815 public void requestFitSystemWindows() { 816 checkThread(); 817 mFitSystemWindowsRequested = true; 818 scheduleTraversals(); 819 } 820 821 @Override requestLayout()822 public void requestLayout() { 823 checkThread(); 824 mLayoutRequested = true; 825 scheduleTraversals(); 826 } 827 828 @Override isLayoutRequested()829 public boolean isLayoutRequested() { 830 return mLayoutRequested; 831 } 832 invalidate()833 void invalidate() { 834 mDirty.set(0, 0, mWidth, mHeight); 835 scheduleTraversals(); 836 } 837 invalidateWorld(View view)838 void invalidateWorld(View view) { 839 view.invalidate(); 840 if (view instanceof ViewGroup) { 841 ViewGroup parent = (ViewGroup) view; 842 for (int i = 0; i < parent.getChildCount(); i++) { 843 invalidateWorld(parent.getChildAt(i)); 844 } 845 } 846 } 847 848 @Override invalidateChild(View child, Rect dirty)849 public void invalidateChild(View child, Rect dirty) { 850 invalidateChildInParent(null, dirty); 851 } 852 invalidateChildInParent(int[] location, Rect dirty)853 public ViewParent invalidateChildInParent(int[] location, Rect dirty) { 854 checkThread(); 855 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty); 856 857 if (dirty == null) { 858 invalidate(); 859 return null; 860 } else if (dirty.isEmpty() && !mIsAnimating) { 861 return null; 862 } 863 864 if (mCurScrollY != 0 || mTranslator != null) { 865 mTempRect.set(dirty); 866 dirty = mTempRect; 867 if (mCurScrollY != 0) { 868 dirty.offset(0, -mCurScrollY); 869 } 870 if (mTranslator != null) { 871 mTranslator.translateRectInAppWindowToScreen(dirty); 872 } 873 if (mAttachInfo.mScalingRequired) { 874 dirty.inset(-1, -1); 875 } 876 } 877 878 final Rect localDirty = mDirty; 879 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) { 880 mAttachInfo.mSetIgnoreDirtyState = true; 881 mAttachInfo.mIgnoreDirtyState = true; 882 } 883 884 // Add the new dirty rect to the current one 885 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom); 886 // Intersect with the bounds of the window to skip 887 // updates that lie outside of the visible region 888 final float appScale = mAttachInfo.mApplicationScale; 889 final boolean intersected = localDirty.intersect(0, 0, 890 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f)); 891 if (!intersected) { 892 localDirty.setEmpty(); 893 } 894 if (!mWillDrawSoon && (intersected || mIsAnimating)) { 895 scheduleTraversals(); 896 } 897 898 return null; 899 } 900 setStopped(boolean stopped)901 void setStopped(boolean stopped) { 902 if (mStopped != stopped) { 903 mStopped = stopped; 904 if (!stopped) { 905 scheduleTraversals(); 906 } 907 } 908 } 909 getParent()910 public ViewParent getParent() { 911 return null; 912 } 913 getChildVisibleRect(View child, Rect r, android.graphics.Point offset)914 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) { 915 if (child != mView) { 916 throw new RuntimeException("child is not mine, honest!"); 917 } 918 // Note: don't apply scroll offset, because we want to know its 919 // visibility in the virtual canvas being given to the view hierarchy. 920 return r.intersect(0, 0, mWidth, mHeight); 921 } 922 bringChildToFront(View child)923 public void bringChildToFront(View child) { 924 } 925 getHostVisibility()926 int getHostVisibility() { 927 return mAppVisible ? mView.getVisibility() : View.GONE; 928 } 929 disposeResizeBuffer()930 void disposeResizeBuffer() { 931 if (mResizeBuffer != null) { 932 mResizeBuffer.destroy(); 933 mResizeBuffer = null; 934 } 935 } 936 937 /** 938 * Add LayoutTransition to the list of transitions to be started in the next traversal. 939 * This list will be cleared after the transitions on the list are start()'ed. These 940 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup 941 * happens during the layout phase of traversal, which we want to complete before any of the 942 * animations are started (because those animations may side-effect properties that layout 943 * depends upon, like the bounding rectangles of the affected views). So we add the transition 944 * to the list and it is started just prior to starting the drawing phase of traversal. 945 * 946 * @param transition The LayoutTransition to be started on the next traversal. 947 * 948 * @hide 949 */ requestTransitionStart(LayoutTransition transition)950 public void requestTransitionStart(LayoutTransition transition) { 951 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) { 952 if (mPendingTransitions == null) { 953 mPendingTransitions = new ArrayList<LayoutTransition>(); 954 } 955 mPendingTransitions.add(transition); 956 } 957 } 958 scheduleTraversals()959 void scheduleTraversals() { 960 if (!mTraversalScheduled) { 961 mTraversalScheduled = true; 962 mTraversalBarrier = mHandler.getLooper().postSyncBarrier(); 963 mChoreographer.postCallback( 964 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); 965 scheduleConsumeBatchedInput(); 966 } 967 } 968 unscheduleTraversals()969 void unscheduleTraversals() { 970 if (mTraversalScheduled) { 971 mTraversalScheduled = false; 972 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier); 973 mChoreographer.removeCallbacks( 974 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); 975 } 976 } 977 doTraversal()978 void doTraversal() { 979 if (mTraversalScheduled) { 980 mTraversalScheduled = false; 981 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier); 982 983 if (mProfile) { 984 Debug.startMethodTracing("ViewAncestor"); 985 } 986 987 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals"); 988 try { 989 performTraversals(); 990 } finally { 991 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 992 } 993 994 if (mProfile) { 995 Debug.stopMethodTracing(); 996 mProfile = false; 997 } 998 } 999 } 1000 applyKeepScreenOnFlag(WindowManager.LayoutParams params)1001 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) { 1002 // Update window's global keep screen on flag: if a view has requested 1003 // that the screen be kept on, then it is always set; otherwise, it is 1004 // set to whatever the client last requested for the global state. 1005 if (mAttachInfo.mKeepScreenOn) { 1006 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; 1007 } else { 1008 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) 1009 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 1010 } 1011 } 1012 collectViewAttributes()1013 private boolean collectViewAttributes() { 1014 final View.AttachInfo attachInfo = mAttachInfo; 1015 if (attachInfo.mRecomputeGlobalAttributes) { 1016 //Log.i(TAG, "Computing view hierarchy attributes!"); 1017 attachInfo.mRecomputeGlobalAttributes = false; 1018 boolean oldScreenOn = attachInfo.mKeepScreenOn; 1019 attachInfo.mKeepScreenOn = false; 1020 attachInfo.mSystemUiVisibility = 0; 1021 attachInfo.mHasSystemUiListeners = false; 1022 mView.dispatchCollectViewAttributes(attachInfo, 0); 1023 attachInfo.mSystemUiVisibility &= ~attachInfo.mDisabledSystemUiVisibility; 1024 WindowManager.LayoutParams params = mWindowAttributes; 1025 if (attachInfo.mKeepScreenOn != oldScreenOn 1026 || attachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility 1027 || attachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) { 1028 applyKeepScreenOnFlag(params); 1029 params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility; 1030 params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners; 1031 mView.dispatchWindowSystemUiVisiblityChanged(attachInfo.mSystemUiVisibility); 1032 return true; 1033 } 1034 } 1035 return false; 1036 } 1037 measureHierarchy(final View host, final WindowManager.LayoutParams lp, final Resources res, final int desiredWindowWidth, final int desiredWindowHeight)1038 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp, 1039 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) { 1040 int childWidthMeasureSpec; 1041 int childHeightMeasureSpec; 1042 boolean windowSizeMayChange = false; 1043 1044 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG, 1045 "Measuring " + host + " in display " + desiredWindowWidth 1046 + "x" + desiredWindowHeight + "..."); 1047 1048 boolean goodMeasure = false; 1049 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) { 1050 // On large screens, we don't want to allow dialogs to just 1051 // stretch to fill the entire width of the screen to display 1052 // one line of text. First try doing the layout at a smaller 1053 // size to see if it will fit. 1054 final DisplayMetrics packageMetrics = res.getDisplayMetrics(); 1055 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true); 1056 int baseSize = 0; 1057 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) { 1058 baseSize = (int)mTmpValue.getDimension(packageMetrics); 1059 } 1060 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize); 1061 if (baseSize != 0 && desiredWindowWidth > baseSize) { 1062 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width); 1063 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); 1064 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 1065 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured (" 1066 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")"); 1067 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) { 1068 goodMeasure = true; 1069 } else { 1070 // Didn't fit in that size... try expanding a bit. 1071 baseSize = (baseSize+desiredWindowWidth)/2; 1072 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize=" 1073 + baseSize); 1074 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width); 1075 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 1076 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured (" 1077 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")"); 1078 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) { 1079 if (DEBUG_DIALOG) Log.v(TAG, "Good!"); 1080 goodMeasure = true; 1081 } 1082 } 1083 } 1084 } 1085 1086 if (!goodMeasure) { 1087 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width); 1088 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); 1089 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 1090 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) { 1091 windowSizeMayChange = true; 1092 } 1093 } 1094 1095 if (DBG) { 1096 System.out.println("======================================"); 1097 System.out.println("performTraversals -- after measure"); 1098 host.debug(); 1099 } 1100 1101 return windowSizeMayChange; 1102 } 1103 performTraversals()1104 private void performTraversals() { 1105 // cache mView since it is used so much below... 1106 final View host = mView; 1107 1108 if (DBG) { 1109 System.out.println("======================================"); 1110 System.out.println("performTraversals"); 1111 host.debug(); 1112 } 1113 1114 if (host == null || !mAdded) 1115 return; 1116 1117 mIsInTraversal = true; 1118 mWillDrawSoon = true; 1119 boolean windowSizeMayChange = false; 1120 boolean newSurface = false; 1121 boolean surfaceChanged = false; 1122 WindowManager.LayoutParams lp = mWindowAttributes; 1123 1124 int desiredWindowWidth; 1125 int desiredWindowHeight; 1126 1127 final View.AttachInfo attachInfo = mAttachInfo; 1128 1129 final int viewVisibility = getHostVisibility(); 1130 boolean viewVisibilityChanged = mViewVisibility != viewVisibility 1131 || mNewSurfaceNeeded; 1132 1133 WindowManager.LayoutParams params = null; 1134 if (mWindowAttributesChanged) { 1135 mWindowAttributesChanged = false; 1136 surfaceChanged = true; 1137 params = lp; 1138 } 1139 CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get(); 1140 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) { 1141 params = lp; 1142 mFullRedrawNeeded = true; 1143 mLayoutRequested = true; 1144 if (mLastInCompatMode) { 1145 params.flags &= ~WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; 1146 mLastInCompatMode = false; 1147 } else { 1148 params.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; 1149 mLastInCompatMode = true; 1150 } 1151 } 1152 1153 mWindowAttributesChangesFlag = 0; 1154 1155 Rect frame = mWinFrame; 1156 if (mFirst) { 1157 mFullRedrawNeeded = true; 1158 mLayoutRequested = true; 1159 1160 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) { 1161 // NOTE -- system code, won't try to do compat mode. 1162 Point size = new Point(); 1163 mDisplay.getRealSize(size); 1164 desiredWindowWidth = size.x; 1165 desiredWindowHeight = size.y; 1166 } else { 1167 DisplayMetrics packageMetrics = 1168 mView.getContext().getResources().getDisplayMetrics(); 1169 desiredWindowWidth = packageMetrics.widthPixels; 1170 desiredWindowHeight = packageMetrics.heightPixels; 1171 } 1172 1173 // For the very first time, tell the view hierarchy that it 1174 // is attached to the window. Note that at this point the surface 1175 // object is not initialized to its backing store, but soon it 1176 // will be (assuming the window is visible). 1177 attachInfo.mSurface = mSurface; 1178 // We used to use the following condition to choose 32 bits drawing caches: 1179 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888 1180 // However, windows are now always 32 bits by default, so choose 32 bits 1181 attachInfo.mUse32BitDrawingCache = true; 1182 attachInfo.mHasWindowFocus = false; 1183 attachInfo.mWindowVisibility = viewVisibility; 1184 attachInfo.mRecomputeGlobalAttributes = false; 1185 viewVisibilityChanged = false; 1186 mLastConfiguration.setTo(host.getResources().getConfiguration()); 1187 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; 1188 // Set the layout direction if it has not been set before (inherit is the default) 1189 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { 1190 host.setLayoutDirection(mLastConfiguration.getLayoutDirection()); 1191 } 1192 host.dispatchAttachedToWindow(attachInfo, 0); 1193 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets); 1194 host.fitSystemWindows(mFitSystemWindowsInsets); 1195 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn); 1196 1197 } else { 1198 desiredWindowWidth = frame.width(); 1199 desiredWindowHeight = frame.height(); 1200 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) { 1201 if (DEBUG_ORIENTATION) Log.v(TAG, 1202 "View " + host + " resized to: " + frame); 1203 mFullRedrawNeeded = true; 1204 mLayoutRequested = true; 1205 windowSizeMayChange = true; 1206 } 1207 } 1208 1209 if (viewVisibilityChanged) { 1210 attachInfo.mWindowVisibility = viewVisibility; 1211 host.dispatchWindowVisibilityChanged(viewVisibility); 1212 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) { 1213 destroyHardwareResources(); 1214 } 1215 if (viewVisibility == View.GONE) { 1216 // After making a window gone, we will count it as being 1217 // shown for the first time the next time it gets focus. 1218 mHasHadWindowFocus = false; 1219 } 1220 } 1221 1222 // Execute enqueued actions on every traversal in case a detached view enqueued an action 1223 getRunQueue().executeActions(attachInfo.mHandler); 1224 1225 boolean insetsChanged = false; 1226 1227 boolean layoutRequested = mLayoutRequested && !mStopped; 1228 if (layoutRequested) { 1229 1230 final Resources res = mView.getContext().getResources(); 1231 1232 if (mFirst) { 1233 // make sure touch mode code executes by setting cached value 1234 // to opposite of the added touch mode. 1235 mAttachInfo.mInTouchMode = !mAddedTouchMode; 1236 ensureTouchModeLocally(mAddedTouchMode); 1237 } else { 1238 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) { 1239 insetsChanged = true; 1240 } 1241 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) { 1242 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets); 1243 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: " 1244 + mAttachInfo.mVisibleInsets); 1245 } 1246 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT 1247 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { 1248 windowSizeMayChange = true; 1249 1250 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) { 1251 // NOTE -- system code, won't try to do compat mode. 1252 Point size = new Point(); 1253 mDisplay.getRealSize(size); 1254 desiredWindowWidth = size.x; 1255 desiredWindowHeight = size.y; 1256 } else { 1257 DisplayMetrics packageMetrics = res.getDisplayMetrics(); 1258 desiredWindowWidth = packageMetrics.widthPixels; 1259 desiredWindowHeight = packageMetrics.heightPixels; 1260 } 1261 } 1262 } 1263 1264 // Ask host how big it wants to be 1265 windowSizeMayChange |= measureHierarchy(host, lp, res, 1266 desiredWindowWidth, desiredWindowHeight); 1267 } 1268 1269 if (collectViewAttributes()) { 1270 params = lp; 1271 } 1272 if (attachInfo.mForceReportNewAttributes) { 1273 attachInfo.mForceReportNewAttributes = false; 1274 params = lp; 1275 } 1276 1277 if (mFirst || attachInfo.mViewVisibilityChanged) { 1278 attachInfo.mViewVisibilityChanged = false; 1279 int resizeMode = mSoftInputMode & 1280 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; 1281 // If we are in auto resize mode, then we need to determine 1282 // what mode to use now. 1283 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { 1284 final int N = attachInfo.mScrollContainers.size(); 1285 for (int i=0; i<N; i++) { 1286 if (attachInfo.mScrollContainers.get(i).isShown()) { 1287 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 1288 } 1289 } 1290 if (resizeMode == 0) { 1291 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; 1292 } 1293 if ((lp.softInputMode & 1294 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) { 1295 lp.softInputMode = (lp.softInputMode & 1296 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) | 1297 resizeMode; 1298 params = lp; 1299 } 1300 } 1301 } 1302 1303 if (params != null && (host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 1304 if (!PixelFormat.formatHasAlpha(params.format)) { 1305 params.format = PixelFormat.TRANSLUCENT; 1306 } 1307 } 1308 1309 if (mFitSystemWindowsRequested) { 1310 mFitSystemWindowsRequested = false; 1311 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets); 1312 host.fitSystemWindows(mFitSystemWindowsInsets); 1313 if (mLayoutRequested) { 1314 // Short-circuit catching a new layout request here, so 1315 // we don't need to go through two layout passes when things 1316 // change due to fitting system windows, which can happen a lot. 1317 windowSizeMayChange |= measureHierarchy(host, lp, 1318 mView.getContext().getResources(), 1319 desiredWindowWidth, desiredWindowHeight); 1320 } 1321 } 1322 1323 if (layoutRequested) { 1324 // Clear this now, so that if anything requests a layout in the 1325 // rest of this function we will catch it and re-run a full 1326 // layout pass. 1327 mLayoutRequested = false; 1328 } 1329 1330 boolean windowShouldResize = layoutRequested && windowSizeMayChange 1331 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) 1332 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT && 1333 frame.width() < desiredWindowWidth && frame.width() != mWidth) 1334 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT && 1335 frame.height() < desiredWindowHeight && frame.height() != mHeight)); 1336 1337 final boolean computesInternalInsets = 1338 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners(); 1339 1340 boolean insetsPending = false; 1341 int relayoutResult = 0; 1342 1343 if (mFirst || windowShouldResize || insetsChanged || 1344 viewVisibilityChanged || params != null) { 1345 1346 if (viewVisibility == View.VISIBLE) { 1347 // If this window is giving internal insets to the window 1348 // manager, and it is being added or changing its visibility, 1349 // then we want to first give the window manager "fake" 1350 // insets to cause it to effectively ignore the content of 1351 // the window during layout. This avoids it briefly causing 1352 // other windows to resize/move based on the raw frame of the 1353 // window, waiting until we can finish laying out this window 1354 // and get back to the window manager with the ultimately 1355 // computed insets. 1356 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged); 1357 } 1358 1359 if (mSurfaceHolder != null) { 1360 mSurfaceHolder.mSurfaceLock.lock(); 1361 mDrawingAllowed = true; 1362 } 1363 1364 boolean hwInitialized = false; 1365 boolean contentInsetsChanged = false; 1366 boolean visibleInsetsChanged; 1367 boolean hadSurface = mSurface.isValid(); 1368 1369 try { 1370 if (DEBUG_LAYOUT) { 1371 Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" + 1372 host.getMeasuredHeight() + ", params=" + params); 1373 } 1374 1375 final int surfaceGenerationId = mSurface.getGenerationId(); 1376 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); 1377 1378 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString() 1379 + " content=" + mPendingContentInsets.toShortString() 1380 + " visible=" + mPendingVisibleInsets.toShortString() 1381 + " surface=" + mSurface); 1382 1383 if (mPendingConfiguration.seq != 0) { 1384 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: " 1385 + mPendingConfiguration); 1386 updateConfiguration(mPendingConfiguration, !mFirst); 1387 mPendingConfiguration.seq = 0; 1388 } 1389 1390 contentInsetsChanged = !mPendingContentInsets.equals( 1391 mAttachInfo.mContentInsets); 1392 visibleInsetsChanged = !mPendingVisibleInsets.equals( 1393 mAttachInfo.mVisibleInsets); 1394 if (contentInsetsChanged) { 1395 if (mWidth > 0 && mHeight > 0 && lp != null && 1396 ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility) 1397 & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 && 1398 mSurface != null && mSurface.isValid() && 1399 !mAttachInfo.mTurnOffWindowResizeAnim && 1400 mAttachInfo.mHardwareRenderer != null && 1401 mAttachInfo.mHardwareRenderer.isEnabled() && 1402 mAttachInfo.mHardwareRenderer.validate() && 1403 lp != null && !PixelFormat.formatHasAlpha(lp.format)) { 1404 1405 disposeResizeBuffer(); 1406 1407 boolean completed = false; 1408 HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas(); 1409 HardwareCanvas layerCanvas = null; 1410 try { 1411 if (mResizeBuffer == null) { 1412 mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer( 1413 mWidth, mHeight, false); 1414 } else if (mResizeBuffer.getWidth() != mWidth || 1415 mResizeBuffer.getHeight() != mHeight) { 1416 mResizeBuffer.resize(mWidth, mHeight); 1417 } 1418 // TODO: should handle create/resize failure 1419 layerCanvas = mResizeBuffer.start(hwRendererCanvas); 1420 layerCanvas.setViewport(mWidth, mHeight); 1421 layerCanvas.onPreDraw(null); 1422 final int restoreCount = layerCanvas.save(); 1423 1424 int yoff; 1425 final boolean scrolling = mScroller != null 1426 && mScroller.computeScrollOffset(); 1427 if (scrolling) { 1428 yoff = mScroller.getCurrY(); 1429 mScroller.abortAnimation(); 1430 } else { 1431 yoff = mScrollY; 1432 } 1433 1434 layerCanvas.translate(0, -yoff); 1435 if (mTranslator != null) { 1436 mTranslator.translateCanvas(layerCanvas); 1437 } 1438 1439 DisplayList displayList = mView.mDisplayList; 1440 if (displayList != null) { 1441 layerCanvas.drawDisplayList(displayList, null, 1442 DisplayList.FLAG_CLIP_CHILDREN); 1443 } else { 1444 mView.draw(layerCanvas); 1445 } 1446 1447 drawAccessibilityFocusedDrawableIfNeeded(layerCanvas); 1448 1449 mResizeBufferStartTime = SystemClock.uptimeMillis(); 1450 mResizeBufferDuration = mView.getResources().getInteger( 1451 com.android.internal.R.integer.config_mediumAnimTime); 1452 completed = true; 1453 1454 layerCanvas.restoreToCount(restoreCount); 1455 } catch (OutOfMemoryError e) { 1456 Log.w(TAG, "Not enough memory for content change anim buffer", e); 1457 } finally { 1458 if (layerCanvas != null) { 1459 layerCanvas.onPostDraw(); 1460 } 1461 if (mResizeBuffer != null) { 1462 mResizeBuffer.end(hwRendererCanvas); 1463 if (!completed) { 1464 mResizeBuffer.destroy(); 1465 mResizeBuffer = null; 1466 } 1467 } 1468 } 1469 } 1470 mAttachInfo.mContentInsets.set(mPendingContentInsets); 1471 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: " 1472 + mAttachInfo.mContentInsets); 1473 } 1474 if (contentInsetsChanged || mLastSystemUiVisibility != 1475 mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested) { 1476 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; 1477 mFitSystemWindowsRequested = false; 1478 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets); 1479 host.fitSystemWindows(mFitSystemWindowsInsets); 1480 } 1481 if (visibleInsetsChanged) { 1482 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets); 1483 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: " 1484 + mAttachInfo.mVisibleInsets); 1485 } 1486 1487 if (!hadSurface) { 1488 if (mSurface.isValid()) { 1489 // If we are creating a new surface, then we need to 1490 // completely redraw it. Also, when we get to the 1491 // point of drawing it we will hold off and schedule 1492 // a new traversal instead. This is so we can tell the 1493 // window manager about all of the windows being displayed 1494 // before actually drawing them, so it can display then 1495 // all at once. 1496 newSurface = true; 1497 mFullRedrawNeeded = true; 1498 mPreviousTransparentRegion.setEmpty(); 1499 1500 if (mAttachInfo.mHardwareRenderer != null) { 1501 try { 1502 hwInitialized = mAttachInfo.mHardwareRenderer.initialize( 1503 mHolder.getSurface()); 1504 } catch (Surface.OutOfResourcesException e) { 1505 Log.e(TAG, "OutOfResourcesException initializing HW surface", e); 1506 try { 1507 if (!mWindowSession.outOfMemory(mWindow) && 1508 Process.myUid() != Process.SYSTEM_UID) { 1509 Slog.w(TAG, "No processes killed for memory; killing self"); 1510 Process.killProcess(Process.myPid()); 1511 } 1512 } catch (RemoteException ex) { 1513 } 1514 mLayoutRequested = true; // ask wm for a new surface next time. 1515 return; 1516 } 1517 } 1518 } 1519 } else if (!mSurface.isValid()) { 1520 // If the surface has been removed, then reset the scroll 1521 // positions. 1522 mLastScrolledFocus = null; 1523 mScrollY = mCurScrollY = 0; 1524 if (mScroller != null) { 1525 mScroller.abortAnimation(); 1526 } 1527 disposeResizeBuffer(); 1528 // Our surface is gone 1529 if (mAttachInfo.mHardwareRenderer != null && 1530 mAttachInfo.mHardwareRenderer.isEnabled()) { 1531 mAttachInfo.mHardwareRenderer.destroy(true); 1532 } 1533 } else if (surfaceGenerationId != mSurface.getGenerationId() && 1534 mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) { 1535 mFullRedrawNeeded = true; 1536 try { 1537 mAttachInfo.mHardwareRenderer.updateSurface(mHolder.getSurface()); 1538 } catch (Surface.OutOfResourcesException e) { 1539 Log.e(TAG, "OutOfResourcesException updating HW surface", e); 1540 try { 1541 if (!mWindowSession.outOfMemory(mWindow)) { 1542 Slog.w(TAG, "No processes killed for memory; killing self"); 1543 Process.killProcess(Process.myPid()); 1544 } 1545 } catch (RemoteException ex) { 1546 } 1547 mLayoutRequested = true; // ask wm for a new surface next time. 1548 return; 1549 } 1550 } 1551 } catch (RemoteException e) { 1552 } 1553 1554 if (DEBUG_ORIENTATION) Log.v( 1555 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface); 1556 1557 attachInfo.mWindowLeft = frame.left; 1558 attachInfo.mWindowTop = frame.top; 1559 1560 // !!FIXME!! This next section handles the case where we did not get the 1561 // window size we asked for. We should avoid this by getting a maximum size from 1562 // the window session beforehand. 1563 if (mWidth != frame.width() || mHeight != frame.height()) { 1564 mWidth = frame.width(); 1565 mHeight = frame.height(); 1566 } 1567 1568 if (mSurfaceHolder != null) { 1569 // The app owns the surface; tell it about what is going on. 1570 if (mSurface.isValid()) { 1571 // XXX .copyFrom() doesn't work! 1572 //mSurfaceHolder.mSurface.copyFrom(mSurface); 1573 mSurfaceHolder.mSurface = mSurface; 1574 } 1575 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight); 1576 mSurfaceHolder.mSurfaceLock.unlock(); 1577 if (mSurface.isValid()) { 1578 if (!hadSurface) { 1579 mSurfaceHolder.ungetCallbacks(); 1580 1581 mIsCreating = true; 1582 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder); 1583 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); 1584 if (callbacks != null) { 1585 for (SurfaceHolder.Callback c : callbacks) { 1586 c.surfaceCreated(mSurfaceHolder); 1587 } 1588 } 1589 surfaceChanged = true; 1590 } 1591 if (surfaceChanged) { 1592 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder, 1593 lp.format, mWidth, mHeight); 1594 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); 1595 if (callbacks != null) { 1596 for (SurfaceHolder.Callback c : callbacks) { 1597 c.surfaceChanged(mSurfaceHolder, lp.format, 1598 mWidth, mHeight); 1599 } 1600 } 1601 } 1602 mIsCreating = false; 1603 } else if (hadSurface) { 1604 mSurfaceHolder.ungetCallbacks(); 1605 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); 1606 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder); 1607 if (callbacks != null) { 1608 for (SurfaceHolder.Callback c : callbacks) { 1609 c.surfaceDestroyed(mSurfaceHolder); 1610 } 1611 } 1612 mSurfaceHolder.mSurfaceLock.lock(); 1613 try { 1614 mSurfaceHolder.mSurface = new Surface(); 1615 } finally { 1616 mSurfaceHolder.mSurfaceLock.unlock(); 1617 } 1618 } 1619 } 1620 1621 if (mAttachInfo.mHardwareRenderer != null && 1622 mAttachInfo.mHardwareRenderer.isEnabled()) { 1623 if (hwInitialized || windowShouldResize || 1624 mWidth != mAttachInfo.mHardwareRenderer.getWidth() || 1625 mHeight != mAttachInfo.mHardwareRenderer.getHeight()) { 1626 mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight); 1627 if (!hwInitialized) { 1628 mAttachInfo.mHardwareRenderer.invalidate(mHolder.getSurface()); 1629 mFullRedrawNeeded = true; 1630 } 1631 } 1632 } 1633 1634 if (!mStopped) { 1635 boolean focusChangedDueToTouchMode = ensureTouchModeLocally( 1636 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0); 1637 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth() 1638 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) { 1639 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); 1640 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height); 1641 1642 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth=" 1643 + mWidth + " measuredWidth=" + host.getMeasuredWidth() 1644 + " mHeight=" + mHeight 1645 + " measuredHeight=" + host.getMeasuredHeight() 1646 + " coveredInsetsChanged=" + contentInsetsChanged); 1647 1648 // Ask host how big it wants to be 1649 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 1650 1651 // Implementation of weights from WindowManager.LayoutParams 1652 // We just grow the dimensions as needed and re-measure if 1653 // needs be 1654 int width = host.getMeasuredWidth(); 1655 int height = host.getMeasuredHeight(); 1656 boolean measureAgain = false; 1657 1658 if (lp.horizontalWeight > 0.0f) { 1659 width += (int) ((mWidth - width) * lp.horizontalWeight); 1660 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, 1661 MeasureSpec.EXACTLY); 1662 measureAgain = true; 1663 } 1664 if (lp.verticalWeight > 0.0f) { 1665 height += (int) ((mHeight - height) * lp.verticalWeight); 1666 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, 1667 MeasureSpec.EXACTLY); 1668 measureAgain = true; 1669 } 1670 1671 if (measureAgain) { 1672 if (DEBUG_LAYOUT) Log.v(TAG, 1673 "And hey let's measure once more: width=" + width 1674 + " height=" + height); 1675 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 1676 } 1677 1678 layoutRequested = true; 1679 } 1680 } 1681 } else { 1682 // Not the first pass and no window/insets/visibility change but the window 1683 // may have moved and we need check that and if so to update the left and right 1684 // in the attach info. We translate only the window frame since on window move 1685 // the window manager tells us only for the new frame but the insets are the 1686 // same and we do not want to translate them more than once. 1687 1688 // TODO: Well, we are checking whether the frame has changed similarly 1689 // to how this is done for the insets. This is however incorrect since 1690 // the insets and the frame are translated. For example, the old frame 1691 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new 1692 // reported frame is (2, 2 - 2, 2) which implies no change but this is not 1693 // true since we are comparing a not translated value to a translated one. 1694 // This scenario is rare but we may want to fix that. 1695 1696 final boolean windowMoved = (attachInfo.mWindowLeft != frame.left 1697 || attachInfo.mWindowTop != frame.top); 1698 if (windowMoved) { 1699 if (mTranslator != null) { 1700 mTranslator.translateRectInScreenToAppWinFrame(frame); 1701 } 1702 attachInfo.mWindowLeft = frame.left; 1703 attachInfo.mWindowTop = frame.top; 1704 } 1705 } 1706 1707 final boolean didLayout = layoutRequested && !mStopped; 1708 boolean triggerGlobalLayoutListener = didLayout 1709 || attachInfo.mRecomputeGlobalAttributes; 1710 if (didLayout) { 1711 performLayout(); 1712 1713 // By this point all views have been sized and positionned 1714 // We can compute the transparent area 1715 1716 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 1717 // start out transparent 1718 // TODO: AVOID THAT CALL BY CACHING THE RESULT? 1719 host.getLocationInWindow(mTmpLocation); 1720 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1], 1721 mTmpLocation[0] + host.mRight - host.mLeft, 1722 mTmpLocation[1] + host.mBottom - host.mTop); 1723 1724 host.gatherTransparentRegion(mTransparentRegion); 1725 if (mTranslator != null) { 1726 mTranslator.translateRegionInWindowToScreen(mTransparentRegion); 1727 } 1728 1729 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) { 1730 mPreviousTransparentRegion.set(mTransparentRegion); 1731 // reconfigure window manager 1732 try { 1733 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion); 1734 } catch (RemoteException e) { 1735 } 1736 } 1737 } 1738 1739 if (DBG) { 1740 System.out.println("======================================"); 1741 System.out.println("performTraversals -- after setFrame"); 1742 host.debug(); 1743 } 1744 } 1745 1746 if (triggerGlobalLayoutListener) { 1747 attachInfo.mRecomputeGlobalAttributes = false; 1748 attachInfo.mTreeObserver.dispatchOnGlobalLayout(); 1749 1750 if (AccessibilityManager.getInstance(host.mContext).isEnabled()) { 1751 postSendWindowContentChangedCallback(mView); 1752 } 1753 } 1754 1755 if (computesInternalInsets) { 1756 // Clear the original insets. 1757 final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets; 1758 insets.reset(); 1759 1760 // Compute new insets in place. 1761 attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets); 1762 1763 // Tell the window manager. 1764 if (insetsPending || !mLastGivenInsets.equals(insets)) { 1765 mLastGivenInsets.set(insets); 1766 1767 // Translate insets to screen coordinates if needed. 1768 final Rect contentInsets; 1769 final Rect visibleInsets; 1770 final Region touchableRegion; 1771 if (mTranslator != null) { 1772 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets); 1773 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets); 1774 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion); 1775 } else { 1776 contentInsets = insets.contentInsets; 1777 visibleInsets = insets.visibleInsets; 1778 touchableRegion = insets.touchableRegion; 1779 } 1780 1781 try { 1782 mWindowSession.setInsets(mWindow, insets.mTouchableInsets, 1783 contentInsets, visibleInsets, touchableRegion); 1784 } catch (RemoteException e) { 1785 } 1786 } 1787 } 1788 1789 boolean skipDraw = false; 1790 1791 if (mFirst) { 1792 // handle first focus request 1793 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()=" 1794 + mView.hasFocus()); 1795 if (mView != null) { 1796 if (!mView.hasFocus()) { 1797 mView.requestFocus(View.FOCUS_FORWARD); 1798 mFocusedView = mRealFocusedView = mView.findFocus(); 1799 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view=" 1800 + mFocusedView); 1801 } else { 1802 mRealFocusedView = mView.findFocus(); 1803 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view=" 1804 + mRealFocusedView); 1805 } 1806 } 1807 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) { 1808 // The first time we relayout the window, if the system is 1809 // doing window animations, we want to hold of on any future 1810 // draws until the animation is done. 1811 mWindowsAnimating = true; 1812 } 1813 } else if (mWindowsAnimating) { 1814 skipDraw = true; 1815 } 1816 1817 mFirst = false; 1818 mWillDrawSoon = false; 1819 mNewSurfaceNeeded = false; 1820 mViewVisibility = viewVisibility; 1821 1822 if (mAttachInfo.mHasWindowFocus) { 1823 final boolean imTarget = WindowManager.LayoutParams 1824 .mayUseInputMethod(mWindowAttributes.flags); 1825 if (imTarget != mLastWasImTarget) { 1826 mLastWasImTarget = imTarget; 1827 InputMethodManager imm = InputMethodManager.peekInstance(); 1828 if (imm != null && imTarget) { 1829 imm.startGettingWindowFocus(mView); 1830 imm.onWindowFocus(mView, mView.findFocus(), 1831 mWindowAttributes.softInputMode, 1832 !mHasHadWindowFocus, mWindowAttributes.flags); 1833 } 1834 } 1835 } 1836 1837 // Remember if we must report the next draw. 1838 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { 1839 mReportNextDraw = true; 1840 } 1841 1842 boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() || 1843 viewVisibility != View.VISIBLE; 1844 1845 if (!cancelDraw && !newSurface) { 1846 if (!skipDraw || mReportNextDraw) { 1847 if (mPendingTransitions != null && mPendingTransitions.size() > 0) { 1848 for (int i = 0; i < mPendingTransitions.size(); ++i) { 1849 mPendingTransitions.get(i).startChangingAnimations(); 1850 } 1851 mPendingTransitions.clear(); 1852 } 1853 1854 performDraw(); 1855 } 1856 } else { 1857 if (viewVisibility == View.VISIBLE) { 1858 // Try again 1859 scheduleTraversals(); 1860 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) { 1861 for (int i = 0; i < mPendingTransitions.size(); ++i) { 1862 mPendingTransitions.get(i).endChangingAnimations(); 1863 } 1864 mPendingTransitions.clear(); 1865 } 1866 } 1867 1868 mIsInTraversal = false; 1869 } 1870 performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec)1871 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) { 1872 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure"); 1873 try { 1874 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); 1875 } finally { 1876 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 1877 } 1878 } 1879 performLayout()1880 private void performLayout() { 1881 mLayoutRequested = false; 1882 mScrollMayChange = true; 1883 1884 final View host = mView; 1885 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) { 1886 Log.v(TAG, "Laying out " + host + " to (" + 1887 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")"); 1888 } 1889 1890 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout"); 1891 try { 1892 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); 1893 } finally { 1894 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 1895 } 1896 } 1897 requestTransparentRegion(View child)1898 public void requestTransparentRegion(View child) { 1899 // the test below should not fail unless someone is messing with us 1900 checkThread(); 1901 if (mView == child) { 1902 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS; 1903 // Need to make sure we re-evaluate the window attributes next 1904 // time around, to ensure the window has the correct format. 1905 mWindowAttributesChanged = true; 1906 mWindowAttributesChangesFlag = 0; 1907 requestLayout(); 1908 } 1909 } 1910 1911 /** 1912 * Figures out the measure spec for the root view in a window based on it's 1913 * layout params. 1914 * 1915 * @param windowSize 1916 * The available width or height of the window 1917 * 1918 * @param rootDimension 1919 * The layout params for one dimension (width or height) of the 1920 * window. 1921 * 1922 * @return The measure spec to use to measure the root view. 1923 */ getRootMeasureSpec(int windowSize, int rootDimension)1924 private static int getRootMeasureSpec(int windowSize, int rootDimension) { 1925 int measureSpec; 1926 switch (rootDimension) { 1927 1928 case ViewGroup.LayoutParams.MATCH_PARENT: 1929 // Window can't resize. Force root view to be windowSize. 1930 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY); 1931 break; 1932 case ViewGroup.LayoutParams.WRAP_CONTENT: 1933 // Window can resize. Set max size for root view. 1934 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST); 1935 break; 1936 default: 1937 // Window wants to be an exact size. Force root view to be that size. 1938 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY); 1939 break; 1940 } 1941 return measureSpec; 1942 } 1943 1944 int mHardwareYOffset; 1945 int mResizeAlpha; 1946 final Paint mResizePaint = new Paint(); 1947 onHardwarePreDraw(HardwareCanvas canvas)1948 public void onHardwarePreDraw(HardwareCanvas canvas) { 1949 canvas.translate(0, -mHardwareYOffset); 1950 } 1951 onHardwarePostDraw(HardwareCanvas canvas)1952 public void onHardwarePostDraw(HardwareCanvas canvas) { 1953 if (mResizeBuffer != null) { 1954 mResizePaint.setAlpha(mResizeAlpha); 1955 canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint); 1956 } 1957 drawAccessibilityFocusedDrawableIfNeeded(canvas); 1958 } 1959 1960 /** 1961 * @hide 1962 */ outputDisplayList(View view)1963 void outputDisplayList(View view) { 1964 if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) { 1965 DisplayList displayList = view.getDisplayList(); 1966 if (displayList != null) { 1967 mAttachInfo.mHardwareCanvas.outputDisplayList(displayList); 1968 } 1969 } 1970 } 1971 1972 /** 1973 * @see #PROPERTY_PROFILE_RENDERING 1974 */ profileRendering(boolean enabled)1975 private void profileRendering(boolean enabled) { 1976 if (mProfileRendering) { 1977 mRenderProfilingEnabled = enabled; 1978 if (mRenderProfiler == null) { 1979 mRenderProfiler = new Thread(new Runnable() { 1980 @Override 1981 public void run() { 1982 Log.d(TAG, "Starting profiling thread"); 1983 while (mRenderProfilingEnabled) { 1984 mAttachInfo.mHandler.post(new Runnable() { 1985 @Override 1986 public void run() { 1987 mDirty.set(0, 0, mWidth, mHeight); 1988 scheduleTraversals(); 1989 } 1990 }); 1991 try { 1992 // TODO: This should use vsync when we get an API 1993 Thread.sleep(15); 1994 } catch (InterruptedException e) { 1995 Log.d(TAG, "Exiting profiling thread"); 1996 } 1997 } 1998 } 1999 }, "Rendering Profiler"); 2000 mRenderProfiler.start(); 2001 } else { 2002 mRenderProfiler.interrupt(); 2003 mRenderProfiler = null; 2004 } 2005 } 2006 } 2007 2008 /** 2009 * Called from draw() when DEBUG_FPS is enabled 2010 */ trackFPS()2011 private void trackFPS() { 2012 // Tracks frames per second drawn. First value in a series of draws may be bogus 2013 // because it down not account for the intervening idle time 2014 long nowTime = System.currentTimeMillis(); 2015 if (mFpsStartTime < 0) { 2016 mFpsStartTime = mFpsPrevTime = nowTime; 2017 mFpsNumFrames = 0; 2018 } else { 2019 ++mFpsNumFrames; 2020 String thisHash = Integer.toHexString(System.identityHashCode(this)); 2021 long frameTime = nowTime - mFpsPrevTime; 2022 long totalTime = nowTime - mFpsStartTime; 2023 Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime); 2024 mFpsPrevTime = nowTime; 2025 if (totalTime > 1000) { 2026 float fps = (float) mFpsNumFrames * 1000 / totalTime; 2027 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps); 2028 mFpsStartTime = nowTime; 2029 mFpsNumFrames = 0; 2030 } 2031 } 2032 } 2033 performDraw()2034 private void performDraw() { 2035 if (!mAttachInfo.mScreenOn && !mReportNextDraw) { 2036 return; 2037 } 2038 2039 final boolean fullRedrawNeeded = mFullRedrawNeeded; 2040 mFullRedrawNeeded = false; 2041 2042 mIsDrawing = true; 2043 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw"); 2044 try { 2045 draw(fullRedrawNeeded); 2046 } finally { 2047 mIsDrawing = false; 2048 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 2049 } 2050 2051 if (mReportNextDraw) { 2052 mReportNextDraw = false; 2053 2054 if (LOCAL_LOGV) { 2055 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle()); 2056 } 2057 if (mSurfaceHolder != null && mSurface.isValid()) { 2058 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder); 2059 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); 2060 if (callbacks != null) { 2061 for (SurfaceHolder.Callback c : callbacks) { 2062 if (c instanceof SurfaceHolder.Callback2) { 2063 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded( 2064 mSurfaceHolder); 2065 } 2066 } 2067 } 2068 } 2069 try { 2070 mWindowSession.finishDrawing(mWindow); 2071 } catch (RemoteException e) { 2072 } 2073 } 2074 } 2075 draw(boolean fullRedrawNeeded)2076 private void draw(boolean fullRedrawNeeded) { 2077 Surface surface = mSurface; 2078 if (surface == null || !surface.isValid()) { 2079 return; 2080 } 2081 2082 if (DEBUG_FPS) { 2083 trackFPS(); 2084 } 2085 2086 if (!sFirstDrawComplete) { 2087 synchronized (sFirstDrawHandlers) { 2088 sFirstDrawComplete = true; 2089 final int count = sFirstDrawHandlers.size(); 2090 for (int i = 0; i< count; i++) { 2091 mHandler.post(sFirstDrawHandlers.get(i)); 2092 } 2093 } 2094 } 2095 2096 scrollToRectOrFocus(null, false); 2097 2098 final AttachInfo attachInfo = mAttachInfo; 2099 if (attachInfo.mViewScrollChanged) { 2100 attachInfo.mViewScrollChanged = false; 2101 attachInfo.mTreeObserver.dispatchOnScrollChanged(); 2102 } 2103 2104 int yoff; 2105 boolean animating = mScroller != null && mScroller.computeScrollOffset(); 2106 if (animating) { 2107 yoff = mScroller.getCurrY(); 2108 } else { 2109 yoff = mScrollY; 2110 } 2111 if (mCurScrollY != yoff) { 2112 mCurScrollY = yoff; 2113 fullRedrawNeeded = true; 2114 } 2115 2116 final float appScale = attachInfo.mApplicationScale; 2117 final boolean scalingRequired = attachInfo.mScalingRequired; 2118 2119 int resizeAlpha = 0; 2120 if (mResizeBuffer != null) { 2121 long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime; 2122 if (deltaTime < mResizeBufferDuration) { 2123 float amt = deltaTime/(float) mResizeBufferDuration; 2124 amt = mResizeInterpolator.getInterpolation(amt); 2125 animating = true; 2126 resizeAlpha = 255 - (int)(amt*255); 2127 } else { 2128 disposeResizeBuffer(); 2129 } 2130 } 2131 2132 final Rect dirty = mDirty; 2133 if (mSurfaceHolder != null) { 2134 // The app owns the surface, we won't draw. 2135 dirty.setEmpty(); 2136 if (animating) { 2137 if (mScroller != null) { 2138 mScroller.abortAnimation(); 2139 } 2140 disposeResizeBuffer(); 2141 } 2142 return; 2143 } 2144 2145 if (fullRedrawNeeded) { 2146 attachInfo.mIgnoreDirtyState = true; 2147 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f)); 2148 } 2149 2150 if (DEBUG_ORIENTATION || DEBUG_DRAW) { 2151 Log.v(TAG, "Draw " + mView + "/" 2152 + mWindowAttributes.getTitle() 2153 + ": dirty={" + dirty.left + "," + dirty.top 2154 + "," + dirty.right + "," + dirty.bottom + "} surface=" 2155 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" + 2156 appScale + ", width=" + mWidth + ", height=" + mHeight); 2157 } 2158 2159 attachInfo.mTreeObserver.dispatchOnDraw(); 2160 2161 if (!dirty.isEmpty() || mIsAnimating) { 2162 if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) { 2163 // Draw with hardware renderer. 2164 mIsAnimating = false; 2165 mHardwareYOffset = yoff; 2166 mResizeAlpha = resizeAlpha; 2167 2168 mCurrentDirty.set(dirty); 2169 mCurrentDirty.union(mPreviousDirty); 2170 mPreviousDirty.set(dirty); 2171 dirty.setEmpty(); 2172 2173 if (attachInfo.mHardwareRenderer.draw(mView, attachInfo, this, 2174 animating ? null : mCurrentDirty)) { 2175 mPreviousDirty.set(0, 0, mWidth, mHeight); 2176 } 2177 } else if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) { 2178 return; 2179 } 2180 } 2181 2182 if (animating) { 2183 mFullRedrawNeeded = true; 2184 scheduleTraversals(); 2185 } 2186 } 2187 2188 /** 2189 * @return true if drawing was succesfull, false if an error occurred 2190 */ drawSoftware(Surface surface, AttachInfo attachInfo, int yoff, boolean scalingRequired, Rect dirty)2191 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff, 2192 boolean scalingRequired, Rect dirty) { 2193 2194 // If we get here with a disabled & requested hardware renderer, something went 2195 // wrong (an invalidate posted right before we destroyed the hardware surface 2196 // for instance) so we should just bail out. Locking the surface with software 2197 // rendering at this point would lock it forever and prevent hardware renderer 2198 // from doing its job when it comes back. 2199 if (attachInfo.mHardwareRenderer != null && !attachInfo.mHardwareRenderer.isEnabled() && 2200 attachInfo.mHardwareRenderer.isRequested()) { 2201 mFullRedrawNeeded = true; 2202 scheduleTraversals(); 2203 return false; 2204 } 2205 2206 // Draw with software renderer. 2207 Canvas canvas; 2208 try { 2209 int left = dirty.left; 2210 int top = dirty.top; 2211 int right = dirty.right; 2212 int bottom = dirty.bottom; 2213 2214 canvas = mSurface.lockCanvas(dirty); 2215 2216 if (left != dirty.left || top != dirty.top || right != dirty.right || 2217 bottom != dirty.bottom) { 2218 attachInfo.mIgnoreDirtyState = true; 2219 } 2220 2221 // TODO: Do this in native 2222 canvas.setDensity(mDensity); 2223 } catch (Surface.OutOfResourcesException e) { 2224 Log.e(TAG, "OutOfResourcesException locking surface", e); 2225 try { 2226 if (!mWindowSession.outOfMemory(mWindow)) { 2227 Slog.w(TAG, "No processes killed for memory; killing self"); 2228 Process.killProcess(Process.myPid()); 2229 } 2230 } catch (RemoteException ex) { 2231 } 2232 mLayoutRequested = true; // ask wm for a new surface next time. 2233 return false; 2234 } catch (IllegalArgumentException e) { 2235 Log.e(TAG, "Could not lock surface", e); 2236 // Don't assume this is due to out of memory, it could be 2237 // something else, and if it is something else then we could 2238 // kill stuff (or ourself) for no reason. 2239 mLayoutRequested = true; // ask wm for a new surface next time. 2240 return false; 2241 } 2242 2243 try { 2244 if (DEBUG_ORIENTATION || DEBUG_DRAW) { 2245 Log.v(TAG, "Surface " + surface + " drawing to bitmap w=" 2246 + canvas.getWidth() + ", h=" + canvas.getHeight()); 2247 //canvas.drawARGB(255, 255, 0, 0); 2248 } 2249 2250 // If this bitmap's format includes an alpha channel, we 2251 // need to clear it before drawing so that the child will 2252 // properly re-composite its drawing on a transparent 2253 // background. This automatically respects the clip/dirty region 2254 // or 2255 // If we are applying an offset, we need to clear the area 2256 // where the offset doesn't appear to avoid having garbage 2257 // left in the blank areas. 2258 if (!canvas.isOpaque() || yoff != 0) { 2259 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 2260 } 2261 2262 dirty.setEmpty(); 2263 mIsAnimating = false; 2264 attachInfo.mDrawingTime = SystemClock.uptimeMillis(); 2265 mView.mPrivateFlags |= View.PFLAG_DRAWN; 2266 2267 if (DEBUG_DRAW) { 2268 Context cxt = mView.getContext(); 2269 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() + 2270 ", metrics=" + cxt.getResources().getDisplayMetrics() + 2271 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo()); 2272 } 2273 try { 2274 canvas.translate(0, -yoff); 2275 if (mTranslator != null) { 2276 mTranslator.translateCanvas(canvas); 2277 } 2278 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0); 2279 attachInfo.mSetIgnoreDirtyState = false; 2280 2281 mView.draw(canvas); 2282 2283 drawAccessibilityFocusedDrawableIfNeeded(canvas); 2284 } finally { 2285 if (!attachInfo.mSetIgnoreDirtyState) { 2286 // Only clear the flag if it was not set during the mView.draw() call 2287 attachInfo.mIgnoreDirtyState = false; 2288 } 2289 } 2290 } finally { 2291 try { 2292 surface.unlockCanvasAndPost(canvas); 2293 } catch (IllegalArgumentException e) { 2294 Log.e(TAG, "Could not unlock surface", e); 2295 mLayoutRequested = true; // ask wm for a new surface next time. 2296 //noinspection ReturnInsideFinallyBlock 2297 return false; 2298 } 2299 2300 if (LOCAL_LOGV) { 2301 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost"); 2302 } 2303 } 2304 return true; 2305 } 2306 2307 /** 2308 * We want to draw a highlight around the current accessibility focused. 2309 * Since adding a style for all possible view is not a viable option we 2310 * have this specialized drawing method. 2311 * 2312 * Note: We are doing this here to be able to draw the highlight for 2313 * virtual views in addition to real ones. 2314 * 2315 * @param canvas The canvas on which to draw. 2316 */ drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas)2317 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) { 2318 AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext); 2319 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 2320 return; 2321 } 2322 if (mAccessibilityFocusedHost == null || mAccessibilityFocusedHost.mAttachInfo == null) { 2323 return; 2324 } 2325 Drawable drawable = getAccessibilityFocusedDrawable(); 2326 if (drawable == null) { 2327 return; 2328 } 2329 AccessibilityNodeProvider provider = 2330 mAccessibilityFocusedHost.getAccessibilityNodeProvider(); 2331 Rect bounds = mView.mAttachInfo.mTmpInvalRect; 2332 if (provider == null) { 2333 mAccessibilityFocusedHost.getBoundsOnScreen(bounds); 2334 } else { 2335 if (mAccessibilityFocusedVirtualView == null) { 2336 return; 2337 } 2338 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds); 2339 } 2340 bounds.offset(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop); 2341 bounds.intersect(0, 0, mAttachInfo.mViewRootImpl.mWidth, mAttachInfo.mViewRootImpl.mHeight); 2342 drawable.setBounds(bounds); 2343 drawable.draw(canvas); 2344 } 2345 getAccessibilityFocusedDrawable()2346 private Drawable getAccessibilityFocusedDrawable() { 2347 if (mAttachInfo != null) { 2348 // Lazily load the accessibility focus drawable. 2349 if (mAttachInfo.mAccessibilityFocusDrawable == null) { 2350 TypedValue value = new TypedValue(); 2351 final boolean resolved = mView.mContext.getTheme().resolveAttribute( 2352 R.attr.accessibilityFocusedDrawable, value, true); 2353 if (resolved) { 2354 mAttachInfo.mAccessibilityFocusDrawable = 2355 mView.mContext.getResources().getDrawable(value.resourceId); 2356 } 2357 } 2358 return mAttachInfo.mAccessibilityFocusDrawable; 2359 } 2360 return null; 2361 } 2362 invalidateDisplayLists()2363 void invalidateDisplayLists() { 2364 final ArrayList<DisplayList> displayLists = mDisplayLists; 2365 final int count = displayLists.size(); 2366 2367 for (int i = 0; i < count; i++) { 2368 final DisplayList displayList = displayLists.get(i); 2369 displayList.invalidate(); 2370 displayList.clear(); 2371 } 2372 2373 displayLists.clear(); 2374 } 2375 scrollToRectOrFocus(Rect rectangle, boolean immediate)2376 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) { 2377 final View.AttachInfo attachInfo = mAttachInfo; 2378 final Rect ci = attachInfo.mContentInsets; 2379 final Rect vi = attachInfo.mVisibleInsets; 2380 int scrollY = 0; 2381 boolean handled = false; 2382 2383 if (vi.left > ci.left || vi.top > ci.top 2384 || vi.right > ci.right || vi.bottom > ci.bottom) { 2385 // We'll assume that we aren't going to change the scroll 2386 // offset, since we want to avoid that unless it is actually 2387 // going to make the focus visible... otherwise we scroll 2388 // all over the place. 2389 scrollY = mScrollY; 2390 // We can be called for two different situations: during a draw, 2391 // to update the scroll position if the focus has changed (in which 2392 // case 'rectangle' is null), or in response to a 2393 // requestChildRectangleOnScreen() call (in which case 'rectangle' 2394 // is non-null and we just want to scroll to whatever that 2395 // rectangle is). 2396 View focus = mRealFocusedView; 2397 2398 // When in touch mode, focus points to the previously focused view, 2399 // which may have been removed from the view hierarchy. The following 2400 // line checks whether the view is still in our hierarchy. 2401 if (focus == null || focus.mAttachInfo != mAttachInfo) { 2402 mRealFocusedView = null; 2403 return false; 2404 } 2405 2406 if (focus != mLastScrolledFocus) { 2407 // If the focus has changed, then ignore any requests to scroll 2408 // to a rectangle; first we want to make sure the entire focus 2409 // view is visible. 2410 rectangle = null; 2411 } 2412 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus 2413 + " rectangle=" + rectangle + " ci=" + ci 2414 + " vi=" + vi); 2415 if (focus == mLastScrolledFocus && !mScrollMayChange 2416 && rectangle == null) { 2417 // Optimization: if the focus hasn't changed since last 2418 // time, and no layout has happened, then just leave things 2419 // as they are. 2420 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y=" 2421 + mScrollY + " vi=" + vi.toShortString()); 2422 } else if (focus != null) { 2423 // We need to determine if the currently focused view is 2424 // within the visible part of the window and, if not, apply 2425 // a pan so it can be seen. 2426 mLastScrolledFocus = focus; 2427 mScrollMayChange = false; 2428 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?"); 2429 // Try to find the rectangle from the focus view. 2430 if (focus.getGlobalVisibleRect(mVisRect, null)) { 2431 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w=" 2432 + mView.getWidth() + " h=" + mView.getHeight() 2433 + " ci=" + ci.toShortString() 2434 + " vi=" + vi.toShortString()); 2435 if (rectangle == null) { 2436 focus.getFocusedRect(mTempRect); 2437 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus 2438 + ": focusRect=" + mTempRect.toShortString()); 2439 if (mView instanceof ViewGroup) { 2440 ((ViewGroup) mView).offsetDescendantRectToMyCoords( 2441 focus, mTempRect); 2442 } 2443 if (DEBUG_INPUT_RESIZE) Log.v(TAG, 2444 "Focus in window: focusRect=" 2445 + mTempRect.toShortString() 2446 + " visRect=" + mVisRect.toShortString()); 2447 } else { 2448 mTempRect.set(rectangle); 2449 if (DEBUG_INPUT_RESIZE) Log.v(TAG, 2450 "Request scroll to rect: " 2451 + mTempRect.toShortString() 2452 + " visRect=" + mVisRect.toShortString()); 2453 } 2454 if (mTempRect.intersect(mVisRect)) { 2455 if (DEBUG_INPUT_RESIZE) Log.v(TAG, 2456 "Focus window visible rect: " 2457 + mTempRect.toShortString()); 2458 if (mTempRect.height() > 2459 (mView.getHeight()-vi.top-vi.bottom)) { 2460 // If the focus simply is not going to fit, then 2461 // best is probably just to leave things as-is. 2462 if (DEBUG_INPUT_RESIZE) Log.v(TAG, 2463 "Too tall; leaving scrollY=" + scrollY); 2464 } else if ((mTempRect.top-scrollY) < vi.top) { 2465 scrollY -= vi.top - (mTempRect.top-scrollY); 2466 if (DEBUG_INPUT_RESIZE) Log.v(TAG, 2467 "Top covered; scrollY=" + scrollY); 2468 } else if ((mTempRect.bottom-scrollY) 2469 > (mView.getHeight()-vi.bottom)) { 2470 scrollY += (mTempRect.bottom-scrollY) 2471 - (mView.getHeight()-vi.bottom); 2472 if (DEBUG_INPUT_RESIZE) Log.v(TAG, 2473 "Bottom covered; scrollY=" + scrollY); 2474 } 2475 handled = true; 2476 } 2477 } 2478 } 2479 } 2480 2481 if (scrollY != mScrollY) { 2482 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old=" 2483 + mScrollY + " , new=" + scrollY); 2484 if (!immediate && mResizeBuffer == null) { 2485 if (mScroller == null) { 2486 mScroller = new Scroller(mView.getContext()); 2487 } 2488 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY); 2489 } else if (mScroller != null) { 2490 mScroller.abortAnimation(); 2491 } 2492 mScrollY = scrollY; 2493 } 2494 2495 return handled; 2496 } 2497 2498 /** 2499 * @hide 2500 */ getAccessibilityFocusedHost()2501 public View getAccessibilityFocusedHost() { 2502 return mAccessibilityFocusedHost; 2503 } 2504 2505 /** 2506 * @hide 2507 */ getAccessibilityFocusedVirtualView()2508 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() { 2509 return mAccessibilityFocusedVirtualView; 2510 } 2511 setAccessibilityFocus(View view, AccessibilityNodeInfo node)2512 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) { 2513 // If we have a virtual view with accessibility focus we need 2514 // to clear the focus and invalidate the virtual view bounds. 2515 if (mAccessibilityFocusedVirtualView != null) { 2516 2517 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView; 2518 View focusHost = mAccessibilityFocusedHost; 2519 focusHost.clearAccessibilityFocusNoCallbacks(); 2520 2521 // Wipe the state of the current accessibility focus since 2522 // the call into the provider to clear accessibility focus 2523 // will fire an accessibility event which will end up calling 2524 // this method and we want to have clean state when this 2525 // invocation happens. 2526 mAccessibilityFocusedHost = null; 2527 mAccessibilityFocusedVirtualView = null; 2528 2529 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider(); 2530 if (provider != null) { 2531 // Invalidate the area of the cleared accessibility focus. 2532 focusNode.getBoundsInParent(mTempRect); 2533 focusHost.invalidate(mTempRect); 2534 // Clear accessibility focus in the virtual node. 2535 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId( 2536 focusNode.getSourceNodeId()); 2537 provider.performAction(virtualNodeId, 2538 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); 2539 } 2540 focusNode.recycle(); 2541 } 2542 if (mAccessibilityFocusedHost != null) { 2543 // Clear accessibility focus in the view. 2544 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(); 2545 } 2546 2547 // Set the new focus host and node. 2548 mAccessibilityFocusedHost = view; 2549 mAccessibilityFocusedVirtualView = node; 2550 } 2551 requestChildFocus(View child, View focused)2552 public void requestChildFocus(View child, View focused) { 2553 checkThread(); 2554 2555 if (DEBUG_INPUT_RESIZE) { 2556 Log.v(TAG, "Request child focus: focus now " + focused); 2557 } 2558 2559 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, focused); 2560 scheduleTraversals(); 2561 2562 mFocusedView = mRealFocusedView = focused; 2563 } 2564 clearChildFocus(View child)2565 public void clearChildFocus(View child) { 2566 checkThread(); 2567 2568 if (DEBUG_INPUT_RESIZE) { 2569 Log.v(TAG, "Clearing child focus"); 2570 } 2571 2572 mOldFocusedView = mFocusedView; 2573 2574 // Invoke the listener only if there is no view to take focus 2575 if (focusSearch(null, View.FOCUS_FORWARD) == null) { 2576 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, null); 2577 } 2578 2579 mFocusedView = mRealFocusedView = null; 2580 } 2581 2582 @Override getParentForAccessibility()2583 public ViewParent getParentForAccessibility() { 2584 return null; 2585 } 2586 focusableViewAvailable(View v)2587 public void focusableViewAvailable(View v) { 2588 checkThread(); 2589 if (mView != null) { 2590 if (!mView.hasFocus()) { 2591 v.requestFocus(); 2592 } else { 2593 // the one case where will transfer focus away from the current one 2594 // is if the current view is a view group that prefers to give focus 2595 // to its children first AND the view is a descendant of it. 2596 mFocusedView = mView.findFocus(); 2597 boolean descendantsHaveDibsOnFocus = 2598 (mFocusedView instanceof ViewGroup) && 2599 (((ViewGroup) mFocusedView).getDescendantFocusability() == 2600 ViewGroup.FOCUS_AFTER_DESCENDANTS); 2601 if (descendantsHaveDibsOnFocus && isViewDescendantOf(v, mFocusedView)) { 2602 // If a view gets the focus, the listener will be invoked from requestChildFocus() 2603 v.requestFocus(); 2604 } 2605 } 2606 } 2607 } 2608 recomputeViewAttributes(View child)2609 public void recomputeViewAttributes(View child) { 2610 checkThread(); 2611 if (mView == child) { 2612 mAttachInfo.mRecomputeGlobalAttributes = true; 2613 if (!mWillDrawSoon) { 2614 scheduleTraversals(); 2615 } 2616 } 2617 } 2618 dispatchDetachedFromWindow()2619 void dispatchDetachedFromWindow() { 2620 if (mView != null && mView.mAttachInfo != null) { 2621 if (mAttachInfo.mHardwareRenderer != null && 2622 mAttachInfo.mHardwareRenderer.isEnabled()) { 2623 mAttachInfo.mHardwareRenderer.validate(); 2624 } 2625 mView.dispatchDetachedFromWindow(); 2626 } 2627 2628 mAccessibilityInteractionConnectionManager.ensureNoConnection(); 2629 mAccessibilityManager.removeAccessibilityStateChangeListener( 2630 mAccessibilityInteractionConnectionManager); 2631 removeSendWindowContentChangedCallback(); 2632 2633 destroyHardwareRenderer(); 2634 2635 setAccessibilityFocus(null, null); 2636 2637 mView = null; 2638 mAttachInfo.mRootView = null; 2639 mAttachInfo.mSurface = null; 2640 2641 mSurface.release(); 2642 2643 if (mInputQueueCallback != null && mInputQueue != null) { 2644 mInputQueueCallback.onInputQueueDestroyed(mInputQueue); 2645 mInputQueueCallback = null; 2646 mInputQueue = null; 2647 } else if (mInputEventReceiver != null) { 2648 mInputEventReceiver.dispose(); 2649 mInputEventReceiver = null; 2650 } 2651 try { 2652 mWindowSession.remove(mWindow); 2653 } catch (RemoteException e) { 2654 } 2655 2656 // Dispose the input channel after removing the window so the Window Manager 2657 // doesn't interpret the input channel being closed as an abnormal termination. 2658 if (mInputChannel != null) { 2659 mInputChannel.dispose(); 2660 mInputChannel = null; 2661 } 2662 2663 unscheduleTraversals(); 2664 } 2665 updateConfiguration(Configuration config, boolean force)2666 void updateConfiguration(Configuration config, boolean force) { 2667 if (DEBUG_CONFIGURATION) Log.v(TAG, 2668 "Applying new config to window " 2669 + mWindowAttributes.getTitle() 2670 + ": " + config); 2671 2672 CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded(); 2673 if (ci != null) { 2674 config = new Configuration(config); 2675 ci.applyToConfiguration(mNoncompatDensity, config); 2676 } 2677 2678 synchronized (sConfigCallbacks) { 2679 for (int i=sConfigCallbacks.size()-1; i>=0; i--) { 2680 sConfigCallbacks.get(i).onConfigurationChanged(config); 2681 } 2682 } 2683 if (mView != null) { 2684 // At this point the resources have been updated to 2685 // have the most recent config, whatever that is. Use 2686 // the one in them which may be newer. 2687 config = mView.getResources().getConfiguration(); 2688 if (force || mLastConfiguration.diff(config) != 0) { 2689 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection(); 2690 final int currentLayoutDirection = config.getLayoutDirection(); 2691 mLastConfiguration.setTo(config); 2692 if (lastLayoutDirection != currentLayoutDirection && 2693 mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { 2694 mView.setLayoutDirection(currentLayoutDirection); 2695 } 2696 mView.dispatchConfigurationChanged(config); 2697 } 2698 } 2699 } 2700 2701 /** 2702 * Return true if child is an ancestor of parent, (or equal to the parent). 2703 */ isViewDescendantOf(View child, View parent)2704 public static boolean isViewDescendantOf(View child, View parent) { 2705 if (child == parent) { 2706 return true; 2707 } 2708 2709 final ViewParent theParent = child.getParent(); 2710 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent); 2711 } 2712 forceLayout(View view)2713 private static void forceLayout(View view) { 2714 view.forceLayout(); 2715 if (view instanceof ViewGroup) { 2716 ViewGroup group = (ViewGroup) view; 2717 final int count = group.getChildCount(); 2718 for (int i = 0; i < count; i++) { 2719 forceLayout(group.getChildAt(i)); 2720 } 2721 } 2722 } 2723 2724 private final static int MSG_INVALIDATE = 1; 2725 private final static int MSG_INVALIDATE_RECT = 2; 2726 private final static int MSG_DIE = 3; 2727 private final static int MSG_RESIZED = 4; 2728 private final static int MSG_RESIZED_REPORT = 5; 2729 private final static int MSG_WINDOW_FOCUS_CHANGED = 6; 2730 private final static int MSG_DISPATCH_KEY = 7; 2731 private final static int MSG_DISPATCH_APP_VISIBILITY = 8; 2732 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9; 2733 private final static int MSG_IME_FINISHED_EVENT = 10; 2734 private final static int MSG_DISPATCH_KEY_FROM_IME = 11; 2735 private final static int MSG_FINISH_INPUT_CONNECTION = 12; 2736 private final static int MSG_CHECK_FOCUS = 13; 2737 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14; 2738 private final static int MSG_DISPATCH_DRAG_EVENT = 15; 2739 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16; 2740 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17; 2741 private final static int MSG_UPDATE_CONFIGURATION = 18; 2742 private final static int MSG_PROCESS_INPUT_EVENTS = 19; 2743 private final static int MSG_DISPATCH_SCREEN_STATE = 20; 2744 private final static int MSG_INVALIDATE_DISPLAY_LIST = 21; 2745 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 22; 2746 private final static int MSG_DISPATCH_DONE_ANIMATING = 23; 2747 private final static int MSG_INVALIDATE_WORLD = 24; 2748 private final static int MSG_WINDOW_MOVED = 25; 2749 2750 final class ViewRootHandler extends Handler { 2751 @Override getMessageName(Message message)2752 public String getMessageName(Message message) { 2753 switch (message.what) { 2754 case MSG_INVALIDATE: 2755 return "MSG_INVALIDATE"; 2756 case MSG_INVALIDATE_RECT: 2757 return "MSG_INVALIDATE_RECT"; 2758 case MSG_DIE: 2759 return "MSG_DIE"; 2760 case MSG_RESIZED: 2761 return "MSG_RESIZED"; 2762 case MSG_RESIZED_REPORT: 2763 return "MSG_RESIZED_REPORT"; 2764 case MSG_WINDOW_FOCUS_CHANGED: 2765 return "MSG_WINDOW_FOCUS_CHANGED"; 2766 case MSG_DISPATCH_KEY: 2767 return "MSG_DISPATCH_KEY"; 2768 case MSG_DISPATCH_APP_VISIBILITY: 2769 return "MSG_DISPATCH_APP_VISIBILITY"; 2770 case MSG_DISPATCH_GET_NEW_SURFACE: 2771 return "MSG_DISPATCH_GET_NEW_SURFACE"; 2772 case MSG_IME_FINISHED_EVENT: 2773 return "MSG_IME_FINISHED_EVENT"; 2774 case MSG_DISPATCH_KEY_FROM_IME: 2775 return "MSG_DISPATCH_KEY_FROM_IME"; 2776 case MSG_FINISH_INPUT_CONNECTION: 2777 return "MSG_FINISH_INPUT_CONNECTION"; 2778 case MSG_CHECK_FOCUS: 2779 return "MSG_CHECK_FOCUS"; 2780 case MSG_CLOSE_SYSTEM_DIALOGS: 2781 return "MSG_CLOSE_SYSTEM_DIALOGS"; 2782 case MSG_DISPATCH_DRAG_EVENT: 2783 return "MSG_DISPATCH_DRAG_EVENT"; 2784 case MSG_DISPATCH_DRAG_LOCATION_EVENT: 2785 return "MSG_DISPATCH_DRAG_LOCATION_EVENT"; 2786 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: 2787 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY"; 2788 case MSG_UPDATE_CONFIGURATION: 2789 return "MSG_UPDATE_CONFIGURATION"; 2790 case MSG_PROCESS_INPUT_EVENTS: 2791 return "MSG_PROCESS_INPUT_EVENTS"; 2792 case MSG_DISPATCH_SCREEN_STATE: 2793 return "MSG_DISPATCH_SCREEN_STATE"; 2794 case MSG_INVALIDATE_DISPLAY_LIST: 2795 return "MSG_INVALIDATE_DISPLAY_LIST"; 2796 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: 2797 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST"; 2798 case MSG_DISPATCH_DONE_ANIMATING: 2799 return "MSG_DISPATCH_DONE_ANIMATING"; 2800 case MSG_WINDOW_MOVED: 2801 return "MSG_WINDOW_MOVED"; 2802 } 2803 return super.getMessageName(message); 2804 } 2805 2806 @Override handleMessage(Message msg)2807 public void handleMessage(Message msg) { 2808 switch (msg.what) { 2809 case MSG_INVALIDATE: 2810 ((View) msg.obj).invalidate(); 2811 break; 2812 case MSG_INVALIDATE_RECT: 2813 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj; 2814 info.target.invalidate(info.left, info.top, info.right, info.bottom); 2815 info.release(); 2816 break; 2817 case MSG_IME_FINISHED_EVENT: 2818 handleImeFinishedEvent(msg.arg1, msg.arg2 != 0); 2819 break; 2820 case MSG_PROCESS_INPUT_EVENTS: 2821 mProcessInputEventsScheduled = false; 2822 doProcessInputEvents(); 2823 break; 2824 case MSG_DISPATCH_APP_VISIBILITY: 2825 handleAppVisibility(msg.arg1 != 0); 2826 break; 2827 case MSG_DISPATCH_GET_NEW_SURFACE: 2828 handleGetNewSurface(); 2829 break; 2830 case MSG_RESIZED: { 2831 // Recycled in the fall through... 2832 SomeArgs args = (SomeArgs) msg.obj; 2833 if (mWinFrame.equals(args.arg1) 2834 && mPendingContentInsets.equals(args.arg2) 2835 && mPendingVisibleInsets.equals(args.arg3) 2836 && args.arg4 == null) { 2837 break; 2838 } 2839 } // fall through... 2840 case MSG_RESIZED_REPORT: 2841 if (mAdded) { 2842 SomeArgs args = (SomeArgs) msg.obj; 2843 2844 Configuration config = (Configuration) args.arg4; 2845 if (config != null) { 2846 updateConfiguration(config, false); 2847 } 2848 2849 mWinFrame.set((Rect) args.arg1); 2850 mPendingContentInsets.set((Rect) args.arg2); 2851 mPendingVisibleInsets.set((Rect) args.arg3); 2852 2853 args.recycle(); 2854 2855 if (msg.what == MSG_RESIZED_REPORT) { 2856 mReportNextDraw = true; 2857 } 2858 2859 if (mView != null) { 2860 forceLayout(mView); 2861 } 2862 2863 requestLayout(); 2864 } 2865 break; 2866 case MSG_WINDOW_MOVED: 2867 if (mAdded) { 2868 final int w = mWinFrame.width(); 2869 final int h = mWinFrame.height(); 2870 final int l = msg.arg1; 2871 final int t = msg.arg2; 2872 mWinFrame.left = l; 2873 mWinFrame.right = l + w; 2874 mWinFrame.top = t; 2875 mWinFrame.bottom = t + h; 2876 2877 if (mView != null) { 2878 forceLayout(mView); 2879 } 2880 requestLayout(); 2881 } 2882 break; 2883 case MSG_WINDOW_FOCUS_CHANGED: { 2884 if (mAdded) { 2885 boolean hasWindowFocus = msg.arg1 != 0; 2886 mAttachInfo.mHasWindowFocus = hasWindowFocus; 2887 2888 profileRendering(hasWindowFocus); 2889 2890 if (hasWindowFocus) { 2891 boolean inTouchMode = msg.arg2 != 0; 2892 ensureTouchModeLocally(inTouchMode); 2893 2894 if (mAttachInfo.mHardwareRenderer != null && 2895 mSurface != null && mSurface.isValid()) { 2896 mFullRedrawNeeded = true; 2897 try { 2898 if (mAttachInfo.mHardwareRenderer.initializeIfNeeded( 2899 mWidth, mHeight, mHolder.getSurface())) { 2900 mFullRedrawNeeded = true; 2901 } 2902 } catch (Surface.OutOfResourcesException e) { 2903 Log.e(TAG, "OutOfResourcesException locking surface", e); 2904 try { 2905 if (!mWindowSession.outOfMemory(mWindow)) { 2906 Slog.w(TAG, "No processes killed for memory; killing self"); 2907 Process.killProcess(Process.myPid()); 2908 } 2909 } catch (RemoteException ex) { 2910 } 2911 // Retry in a bit. 2912 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500); 2913 return; 2914 } 2915 } 2916 } 2917 2918 mLastWasImTarget = WindowManager.LayoutParams 2919 .mayUseInputMethod(mWindowAttributes.flags); 2920 2921 InputMethodManager imm = InputMethodManager.peekInstance(); 2922 if (mView != null) { 2923 if (hasWindowFocus && imm != null && mLastWasImTarget) { 2924 imm.startGettingWindowFocus(mView); 2925 } 2926 mAttachInfo.mKeyDispatchState.reset(); 2927 mView.dispatchWindowFocusChanged(hasWindowFocus); 2928 } 2929 2930 // Note: must be done after the focus change callbacks, 2931 // so all of the view state is set up correctly. 2932 if (hasWindowFocus) { 2933 if (imm != null && mLastWasImTarget) { 2934 imm.onWindowFocus(mView, mView.findFocus(), 2935 mWindowAttributes.softInputMode, 2936 !mHasHadWindowFocus, mWindowAttributes.flags); 2937 } 2938 // Clear the forward bit. We can just do this directly, since 2939 // the window manager doesn't care about it. 2940 mWindowAttributes.softInputMode &= 2941 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; 2942 ((WindowManager.LayoutParams)mView.getLayoutParams()) 2943 .softInputMode &= 2944 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; 2945 mHasHadWindowFocus = true; 2946 } 2947 2948 setAccessibilityFocus(null, null); 2949 2950 if (mView != null && mAccessibilityManager.isEnabled()) { 2951 if (hasWindowFocus) { 2952 mView.sendAccessibilityEvent( 2953 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 2954 } 2955 } 2956 } 2957 } break; 2958 case MSG_DIE: 2959 doDie(); 2960 break; 2961 case MSG_DISPATCH_KEY: { 2962 KeyEvent event = (KeyEvent)msg.obj; 2963 enqueueInputEvent(event, null, 0, true); 2964 } break; 2965 case MSG_DISPATCH_KEY_FROM_IME: { 2966 if (LOCAL_LOGV) Log.v( 2967 TAG, "Dispatching key " 2968 + msg.obj + " from IME to " + mView); 2969 KeyEvent event = (KeyEvent)msg.obj; 2970 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) { 2971 // The IME is trying to say this event is from the 2972 // system! Bad bad bad! 2973 //noinspection UnusedAssignment 2974 event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM); 2975 } 2976 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true); 2977 } break; 2978 case MSG_FINISH_INPUT_CONNECTION: { 2979 InputMethodManager imm = InputMethodManager.peekInstance(); 2980 if (imm != null) { 2981 imm.reportFinishInputConnection((InputConnection)msg.obj); 2982 } 2983 } break; 2984 case MSG_CHECK_FOCUS: { 2985 InputMethodManager imm = InputMethodManager.peekInstance(); 2986 if (imm != null) { 2987 imm.checkFocus(); 2988 } 2989 } break; 2990 case MSG_CLOSE_SYSTEM_DIALOGS: { 2991 if (mView != null) { 2992 mView.onCloseSystemDialogs((String)msg.obj); 2993 } 2994 } break; 2995 case MSG_DISPATCH_DRAG_EVENT: 2996 case MSG_DISPATCH_DRAG_LOCATION_EVENT: { 2997 DragEvent event = (DragEvent)msg.obj; 2998 event.mLocalState = mLocalDragState; // only present when this app called startDrag() 2999 handleDragEvent(event); 3000 } break; 3001 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: { 3002 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo)msg.obj); 3003 } break; 3004 case MSG_UPDATE_CONFIGURATION: { 3005 Configuration config = (Configuration)msg.obj; 3006 if (config.isOtherSeqNewer(mLastConfiguration)) { 3007 config = mLastConfiguration; 3008 } 3009 updateConfiguration(config, false); 3010 } break; 3011 case MSG_DISPATCH_SCREEN_STATE: { 3012 if (mView != null) { 3013 handleScreenStateChange(msg.arg1 == 1); 3014 } 3015 } break; 3016 case MSG_INVALIDATE_DISPLAY_LIST: { 3017 invalidateDisplayLists(); 3018 } break; 3019 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: { 3020 setAccessibilityFocus(null, null); 3021 } break; 3022 case MSG_DISPATCH_DONE_ANIMATING: { 3023 handleDispatchDoneAnimating(); 3024 } break; 3025 case MSG_INVALIDATE_WORLD: { 3026 if (mView != null) { 3027 invalidateWorld(mView); 3028 } 3029 } break; 3030 } 3031 } 3032 } 3033 3034 final ViewRootHandler mHandler = new ViewRootHandler(); 3035 3036 /** 3037 * Something in the current window tells us we need to change the touch mode. For 3038 * example, we are not in touch mode, and the user touches the screen. 3039 * 3040 * If the touch mode has changed, tell the window manager, and handle it locally. 3041 * 3042 * @param inTouchMode Whether we want to be in touch mode. 3043 * @return True if the touch mode changed and focus changed was changed as a result 3044 */ ensureTouchMode(boolean inTouchMode)3045 boolean ensureTouchMode(boolean inTouchMode) { 3046 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current " 3047 + "touch mode is " + mAttachInfo.mInTouchMode); 3048 if (mAttachInfo.mInTouchMode == inTouchMode) return false; 3049 3050 // tell the window manager 3051 try { 3052 mWindowSession.setInTouchMode(inTouchMode); 3053 } catch (RemoteException e) { 3054 throw new RuntimeException(e); 3055 } 3056 3057 // handle the change 3058 return ensureTouchModeLocally(inTouchMode); 3059 } 3060 3061 /** 3062 * Ensure that the touch mode for this window is set, and if it is changing, 3063 * take the appropriate action. 3064 * @param inTouchMode Whether we want to be in touch mode. 3065 * @return True if the touch mode changed and focus changed was changed as a result 3066 */ ensureTouchModeLocally(boolean inTouchMode)3067 private boolean ensureTouchModeLocally(boolean inTouchMode) { 3068 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current " 3069 + "touch mode is " + mAttachInfo.mInTouchMode); 3070 3071 if (mAttachInfo.mInTouchMode == inTouchMode) return false; 3072 3073 mAttachInfo.mInTouchMode = inTouchMode; 3074 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode); 3075 3076 return (inTouchMode) ? enterTouchMode() : leaveTouchMode(); 3077 } 3078 enterTouchMode()3079 private boolean enterTouchMode() { 3080 if (mView != null) { 3081 if (mView.hasFocus()) { 3082 // note: not relying on mFocusedView here because this could 3083 // be when the window is first being added, and mFocused isn't 3084 // set yet. 3085 final View focused = mView.findFocus(); 3086 if (focused != null && !focused.isFocusableInTouchMode()) { 3087 3088 final ViewGroup ancestorToTakeFocus = 3089 findAncestorToTakeFocusInTouchMode(focused); 3090 if (ancestorToTakeFocus != null) { 3091 // there is an ancestor that wants focus after its descendants that 3092 // is focusable in touch mode.. give it focus 3093 return ancestorToTakeFocus.requestFocus(); 3094 } else { 3095 // nothing appropriate to have focus in touch mode, clear it out 3096 mView.unFocus(); 3097 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null); 3098 mFocusedView = null; 3099 mOldFocusedView = null; 3100 return true; 3101 } 3102 } 3103 } 3104 } 3105 return false; 3106 } 3107 3108 /** 3109 * Find an ancestor of focused that wants focus after its descendants and is 3110 * focusable in touch mode. 3111 * @param focused The currently focused view. 3112 * @return An appropriate view, or null if no such view exists. 3113 */ findAncestorToTakeFocusInTouchMode(View focused)3114 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) { 3115 ViewParent parent = focused.getParent(); 3116 while (parent instanceof ViewGroup) { 3117 final ViewGroup vgParent = (ViewGroup) parent; 3118 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS 3119 && vgParent.isFocusableInTouchMode()) { 3120 return vgParent; 3121 } 3122 if (vgParent.isRootNamespace()) { 3123 return null; 3124 } else { 3125 parent = vgParent.getParent(); 3126 } 3127 } 3128 return null; 3129 } 3130 leaveTouchMode()3131 private boolean leaveTouchMode() { 3132 if (mView != null) { 3133 if (mView.hasFocus()) { 3134 // i learned the hard way to not trust mFocusedView :) 3135 mFocusedView = mView.findFocus(); 3136 if (!(mFocusedView instanceof ViewGroup)) { 3137 // some view has focus, let it keep it 3138 return false; 3139 } else if (((ViewGroup)mFocusedView).getDescendantFocusability() != 3140 ViewGroup.FOCUS_AFTER_DESCENDANTS) { 3141 // some view group has focus, and doesn't prefer its children 3142 // over itself for focus, so let them keep it. 3143 return false; 3144 } 3145 } 3146 3147 // find the best view to give focus to in this brave new non-touch-mode 3148 // world 3149 final View focused = focusSearch(null, View.FOCUS_DOWN); 3150 if (focused != null) { 3151 return focused.requestFocus(View.FOCUS_DOWN); 3152 } 3153 } 3154 return false; 3155 } 3156 deliverInputEvent(QueuedInputEvent q)3157 private void deliverInputEvent(QueuedInputEvent q) { 3158 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent"); 3159 try { 3160 if (q.mEvent instanceof KeyEvent) { 3161 deliverKeyEvent(q); 3162 } else { 3163 final int source = q.mEvent.getSource(); 3164 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 3165 deliverPointerEvent(q); 3166 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 3167 deliverTrackballEvent(q); 3168 } else { 3169 deliverGenericMotionEvent(q); 3170 } 3171 } 3172 } finally { 3173 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 3174 } 3175 } 3176 deliverPointerEvent(QueuedInputEvent q)3177 private void deliverPointerEvent(QueuedInputEvent q) { 3178 final MotionEvent event = (MotionEvent)q.mEvent; 3179 final boolean isTouchEvent = event.isTouchEvent(); 3180 if (mInputEventConsistencyVerifier != null) { 3181 if (isTouchEvent) { 3182 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 3183 } else { 3184 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 3185 } 3186 } 3187 3188 // If there is no view, then the event will not be handled. 3189 if (mView == null || !mAdded) { 3190 finishInputEvent(q, false); 3191 return; 3192 } 3193 3194 // Translate the pointer event for compatibility, if needed. 3195 if (mTranslator != null) { 3196 mTranslator.translateEventInScreenToAppWindow(event); 3197 } 3198 3199 // Enter touch mode on down or scroll. 3200 final int action = event.getAction(); 3201 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) { 3202 ensureTouchMode(true); 3203 } 3204 3205 // Offset the scroll position. 3206 if (mCurScrollY != 0) { 3207 event.offsetLocation(0, mCurScrollY); 3208 } 3209 if (MEASURE_LATENCY) { 3210 lt.sample("A Dispatching PointerEvents", System.nanoTime() - event.getEventTimeNano()); 3211 } 3212 3213 // Remember the touch position for possible drag-initiation. 3214 if (isTouchEvent) { 3215 mLastTouchPoint.x = event.getRawX(); 3216 mLastTouchPoint.y = event.getRawY(); 3217 } 3218 3219 // Dispatch touch to view hierarchy. 3220 boolean handled = mView.dispatchPointerEvent(event); 3221 if (MEASURE_LATENCY) { 3222 lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano()); 3223 } 3224 if (handled) { 3225 finishInputEvent(q, true); 3226 return; 3227 } 3228 3229 // Pointer event was unhandled. 3230 finishInputEvent(q, false); 3231 } 3232 deliverTrackballEvent(QueuedInputEvent q)3233 private void deliverTrackballEvent(QueuedInputEvent q) { 3234 final MotionEvent event = (MotionEvent)q.mEvent; 3235 if (mInputEventConsistencyVerifier != null) { 3236 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 3237 } 3238 3239 if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) { 3240 if (LOCAL_LOGV) 3241 Log.v(TAG, "Dispatching trackball " + event + " to " + mView); 3242 3243 // Dispatch to the IME before propagating down the view hierarchy. 3244 // The IME will eventually call back into handleImeFinishedEvent. 3245 if (mLastWasImTarget) { 3246 InputMethodManager imm = InputMethodManager.peekInstance(); 3247 if (imm != null) { 3248 final int seq = event.getSequenceNumber(); 3249 if (DEBUG_IMF) 3250 Log.v(TAG, "Sending trackball event to IME: seq=" 3251 + seq + " event=" + event); 3252 imm.dispatchTrackballEvent(mView.getContext(), seq, event, 3253 mInputMethodCallback); 3254 return; 3255 } 3256 } 3257 } 3258 3259 // Not dispatching to IME, continue with post IME actions. 3260 deliverTrackballEventPostIme(q); 3261 } 3262 deliverTrackballEventPostIme(QueuedInputEvent q)3263 private void deliverTrackballEventPostIme(QueuedInputEvent q) { 3264 final MotionEvent event = (MotionEvent) q.mEvent; 3265 3266 // If there is no view, then the event will not be handled. 3267 if (mView == null || !mAdded) { 3268 finishInputEvent(q, false); 3269 return; 3270 } 3271 3272 // Deliver the trackball event to the view. 3273 if (mView.dispatchTrackballEvent(event)) { 3274 // If we reach this, we delivered a trackball event to mView and 3275 // mView consumed it. Because we will not translate the trackball 3276 // event into a key event, touch mode will not exit, so we exit 3277 // touch mode here. 3278 ensureTouchMode(false); 3279 3280 finishInputEvent(q, true); 3281 mLastTrackballTime = Integer.MIN_VALUE; 3282 return; 3283 } 3284 3285 // Translate the trackball event into DPAD keys and try to deliver those. 3286 final TrackballAxis x = mTrackballAxisX; 3287 final TrackballAxis y = mTrackballAxisY; 3288 3289 long curTime = SystemClock.uptimeMillis(); 3290 if ((mLastTrackballTime + MAX_TRACKBALL_DELAY) < curTime) { 3291 // It has been too long since the last movement, 3292 // so restart at the beginning. 3293 x.reset(0); 3294 y.reset(0); 3295 mLastTrackballTime = curTime; 3296 } 3297 3298 final int action = event.getAction(); 3299 final int metaState = event.getMetaState(); 3300 switch (action) { 3301 case MotionEvent.ACTION_DOWN: 3302 x.reset(2); 3303 y.reset(2); 3304 enqueueInputEvent(new KeyEvent(curTime, curTime, 3305 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState, 3306 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 3307 InputDevice.SOURCE_KEYBOARD)); 3308 break; 3309 case MotionEvent.ACTION_UP: 3310 x.reset(2); 3311 y.reset(2); 3312 enqueueInputEvent(new KeyEvent(curTime, curTime, 3313 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState, 3314 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 3315 InputDevice.SOURCE_KEYBOARD)); 3316 break; 3317 } 3318 3319 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step=" 3320 + x.step + " dir=" + x.dir + " acc=" + x.acceleration 3321 + " move=" + event.getX() 3322 + " / Y=" + y.position + " step=" 3323 + y.step + " dir=" + y.dir + " acc=" + y.acceleration 3324 + " move=" + event.getY()); 3325 final float xOff = x.collect(event.getX(), event.getEventTime(), "X"); 3326 final float yOff = y.collect(event.getY(), event.getEventTime(), "Y"); 3327 3328 // Generate DPAD events based on the trackball movement. 3329 // We pick the axis that has moved the most as the direction of 3330 // the DPAD. When we generate DPAD events for one axis, then the 3331 // other axis is reset -- we don't want to perform DPAD jumps due 3332 // to slight movements in the trackball when making major movements 3333 // along the other axis. 3334 int keycode = 0; 3335 int movement = 0; 3336 float accel = 1; 3337 if (xOff > yOff) { 3338 movement = x.generate((2/event.getXPrecision())); 3339 if (movement != 0) { 3340 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT 3341 : KeyEvent.KEYCODE_DPAD_LEFT; 3342 accel = x.acceleration; 3343 y.reset(2); 3344 } 3345 } else if (yOff > 0) { 3346 movement = y.generate((2/event.getYPrecision())); 3347 if (movement != 0) { 3348 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN 3349 : KeyEvent.KEYCODE_DPAD_UP; 3350 accel = y.acceleration; 3351 x.reset(2); 3352 } 3353 } 3354 3355 if (keycode != 0) { 3356 if (movement < 0) movement = -movement; 3357 int accelMovement = (int)(movement * accel); 3358 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement 3359 + " accelMovement=" + accelMovement 3360 + " accel=" + accel); 3361 if (accelMovement > movement) { 3362 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: " 3363 + keycode); 3364 movement--; 3365 int repeatCount = accelMovement - movement; 3366 enqueueInputEvent(new KeyEvent(curTime, curTime, 3367 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState, 3368 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 3369 InputDevice.SOURCE_KEYBOARD)); 3370 } 3371 while (movement > 0) { 3372 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: " 3373 + keycode); 3374 movement--; 3375 curTime = SystemClock.uptimeMillis(); 3376 enqueueInputEvent(new KeyEvent(curTime, curTime, 3377 KeyEvent.ACTION_DOWN, keycode, 0, metaState, 3378 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 3379 InputDevice.SOURCE_KEYBOARD)); 3380 enqueueInputEvent(new KeyEvent(curTime, curTime, 3381 KeyEvent.ACTION_UP, keycode, 0, metaState, 3382 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 3383 InputDevice.SOURCE_KEYBOARD)); 3384 } 3385 mLastTrackballTime = curTime; 3386 } 3387 3388 // Unfortunately we can't tell whether the application consumed the keys, so 3389 // we always consider the trackball event handled. 3390 finishInputEvent(q, true); 3391 } 3392 deliverGenericMotionEvent(QueuedInputEvent q)3393 private void deliverGenericMotionEvent(QueuedInputEvent q) { 3394 final MotionEvent event = (MotionEvent)q.mEvent; 3395 if (mInputEventConsistencyVerifier != null) { 3396 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 3397 } 3398 3399 if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) { 3400 if (LOCAL_LOGV) 3401 Log.v(TAG, "Dispatching generic motion " + event + " to " + mView); 3402 3403 // Dispatch to the IME before propagating down the view hierarchy. 3404 // The IME will eventually call back into handleImeFinishedEvent. 3405 if (mLastWasImTarget) { 3406 InputMethodManager imm = InputMethodManager.peekInstance(); 3407 if (imm != null) { 3408 final int seq = event.getSequenceNumber(); 3409 if (DEBUG_IMF) 3410 Log.v(TAG, "Sending generic motion event to IME: seq=" 3411 + seq + " event=" + event); 3412 imm.dispatchGenericMotionEvent(mView.getContext(), seq, event, 3413 mInputMethodCallback); 3414 return; 3415 } 3416 } 3417 } 3418 3419 // Not dispatching to IME, continue with post IME actions. 3420 deliverGenericMotionEventPostIme(q); 3421 } 3422 deliverGenericMotionEventPostIme(QueuedInputEvent q)3423 private void deliverGenericMotionEventPostIme(QueuedInputEvent q) { 3424 final MotionEvent event = (MotionEvent) q.mEvent; 3425 final boolean isJoystick = (event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0; 3426 3427 // If there is no view, then the event will not be handled. 3428 if (mView == null || !mAdded) { 3429 if (isJoystick) { 3430 updateJoystickDirection(event, false); 3431 } 3432 finishInputEvent(q, false); 3433 return; 3434 } 3435 3436 // Deliver the event to the view. 3437 if (mView.dispatchGenericMotionEvent(event)) { 3438 if (isJoystick) { 3439 updateJoystickDirection(event, false); 3440 } 3441 finishInputEvent(q, true); 3442 return; 3443 } 3444 3445 if (isJoystick) { 3446 // Translate the joystick event into DPAD keys and try to deliver 3447 // those. 3448 updateJoystickDirection(event, true); 3449 finishInputEvent(q, true); 3450 } else { 3451 finishInputEvent(q, false); 3452 } 3453 } 3454 updateJoystickDirection(MotionEvent event, boolean synthesizeNewKeys)3455 private void updateJoystickDirection(MotionEvent event, boolean synthesizeNewKeys) { 3456 final long time = event.getEventTime(); 3457 final int metaState = event.getMetaState(); 3458 final int deviceId = event.getDeviceId(); 3459 final int source = event.getSource(); 3460 3461 int xDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_X)); 3462 if (xDirection == 0) { 3463 xDirection = joystickAxisValueToDirection(event.getX()); 3464 } 3465 3466 int yDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_Y)); 3467 if (yDirection == 0) { 3468 yDirection = joystickAxisValueToDirection(event.getY()); 3469 } 3470 3471 if (xDirection != mLastJoystickXDirection) { 3472 if (mLastJoystickXKeyCode != 0) { 3473 enqueueInputEvent(new KeyEvent(time, time, 3474 KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState, 3475 deviceId, 0, KeyEvent.FLAG_FALLBACK, source)); 3476 mLastJoystickXKeyCode = 0; 3477 } 3478 3479 mLastJoystickXDirection = xDirection; 3480 3481 if (xDirection != 0 && synthesizeNewKeys) { 3482 mLastJoystickXKeyCode = xDirection > 0 3483 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT; 3484 enqueueInputEvent(new KeyEvent(time, time, 3485 KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState, 3486 deviceId, 0, KeyEvent.FLAG_FALLBACK, source)); 3487 } 3488 } 3489 3490 if (yDirection != mLastJoystickYDirection) { 3491 if (mLastJoystickYKeyCode != 0) { 3492 enqueueInputEvent(new KeyEvent(time, time, 3493 KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState, 3494 deviceId, 0, KeyEvent.FLAG_FALLBACK, source)); 3495 mLastJoystickYKeyCode = 0; 3496 } 3497 3498 mLastJoystickYDirection = yDirection; 3499 3500 if (yDirection != 0 && synthesizeNewKeys) { 3501 mLastJoystickYKeyCode = yDirection > 0 3502 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP; 3503 enqueueInputEvent(new KeyEvent(time, time, 3504 KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState, 3505 deviceId, 0, KeyEvent.FLAG_FALLBACK, source)); 3506 } 3507 } 3508 } 3509 joystickAxisValueToDirection(float value)3510 private static int joystickAxisValueToDirection(float value) { 3511 if (value >= 0.5f) { 3512 return 1; 3513 } else if (value <= -0.5f) { 3514 return -1; 3515 } else { 3516 return 0; 3517 } 3518 } 3519 3520 /** 3521 * Returns true if the key is used for keyboard navigation. 3522 * @param keyEvent The key event. 3523 * @return True if the key is used for keyboard navigation. 3524 */ isNavigationKey(KeyEvent keyEvent)3525 private static boolean isNavigationKey(KeyEvent keyEvent) { 3526 switch (keyEvent.getKeyCode()) { 3527 case KeyEvent.KEYCODE_DPAD_LEFT: 3528 case KeyEvent.KEYCODE_DPAD_RIGHT: 3529 case KeyEvent.KEYCODE_DPAD_UP: 3530 case KeyEvent.KEYCODE_DPAD_DOWN: 3531 case KeyEvent.KEYCODE_DPAD_CENTER: 3532 case KeyEvent.KEYCODE_PAGE_UP: 3533 case KeyEvent.KEYCODE_PAGE_DOWN: 3534 case KeyEvent.KEYCODE_MOVE_HOME: 3535 case KeyEvent.KEYCODE_MOVE_END: 3536 case KeyEvent.KEYCODE_TAB: 3537 case KeyEvent.KEYCODE_SPACE: 3538 case KeyEvent.KEYCODE_ENTER: 3539 return true; 3540 } 3541 return false; 3542 } 3543 3544 /** 3545 * Returns true if the key is used for typing. 3546 * @param keyEvent The key event. 3547 * @return True if the key is used for typing. 3548 */ isTypingKey(KeyEvent keyEvent)3549 private static boolean isTypingKey(KeyEvent keyEvent) { 3550 return keyEvent.getUnicodeChar() > 0; 3551 } 3552 3553 /** 3554 * See if the key event means we should leave touch mode (and leave touch mode if so). 3555 * @param event The key event. 3556 * @return Whether this key event should be consumed (meaning the act of 3557 * leaving touch mode alone is considered the event). 3558 */ checkForLeavingTouchModeAndConsume(KeyEvent event)3559 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) { 3560 // Only relevant in touch mode. 3561 if (!mAttachInfo.mInTouchMode) { 3562 return false; 3563 } 3564 3565 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP. 3566 final int action = event.getAction(); 3567 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) { 3568 return false; 3569 } 3570 3571 // Don't leave touch mode if the IME told us not to. 3572 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) { 3573 return false; 3574 } 3575 3576 // If the key can be used for keyboard navigation then leave touch mode 3577 // and select a focused view if needed (in ensureTouchMode). 3578 // When a new focused view is selected, we consume the navigation key because 3579 // navigation doesn't make much sense unless a view already has focus so 3580 // the key's purpose is to set focus. 3581 if (isNavigationKey(event)) { 3582 return ensureTouchMode(false); 3583 } 3584 3585 // If the key can be used for typing then leave touch mode 3586 // and select a focused view if needed (in ensureTouchMode). 3587 // Always allow the view to process the typing key. 3588 if (isTypingKey(event)) { 3589 ensureTouchMode(false); 3590 return false; 3591 } 3592 3593 return false; 3594 } 3595 deliverKeyEvent(QueuedInputEvent q)3596 private void deliverKeyEvent(QueuedInputEvent q) { 3597 final KeyEvent event = (KeyEvent)q.mEvent; 3598 if (mInputEventConsistencyVerifier != null) { 3599 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 3600 } 3601 3602 if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) { 3603 if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView); 3604 3605 // Perform predispatching before the IME. 3606 if (mView.dispatchKeyEventPreIme(event)) { 3607 finishInputEvent(q, true); 3608 return; 3609 } 3610 3611 // Dispatch to the IME before propagating down the view hierarchy. 3612 // The IME will eventually call back into handleImeFinishedEvent. 3613 if (mLastWasImTarget) { 3614 InputMethodManager imm = InputMethodManager.peekInstance(); 3615 if (imm != null) { 3616 final int seq = event.getSequenceNumber(); 3617 if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq=" 3618 + seq + " event=" + event); 3619 imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback); 3620 return; 3621 } 3622 } 3623 } 3624 3625 // Not dispatching to IME, continue with post IME actions. 3626 deliverKeyEventPostIme(q); 3627 } 3628 handleImeFinishedEvent(int seq, boolean handled)3629 void handleImeFinishedEvent(int seq, boolean handled) { 3630 final QueuedInputEvent q = mCurrentInputEvent; 3631 if (q != null && q.mEvent.getSequenceNumber() == seq) { 3632 if (DEBUG_IMF) { 3633 Log.v(TAG, "IME finished event: seq=" + seq 3634 + " handled=" + handled + " event=" + q); 3635 } 3636 if (handled) { 3637 finishInputEvent(q, true); 3638 } else { 3639 if (q.mEvent instanceof KeyEvent) { 3640 KeyEvent event = (KeyEvent)q.mEvent; 3641 if (event.getAction() != KeyEvent.ACTION_UP) { 3642 // If the window doesn't currently have input focus, then drop 3643 // this event. This could be an event that came back from the 3644 // IME dispatch but the window has lost focus in the meantime. 3645 if (!mAttachInfo.mHasWindowFocus) { 3646 Slog.w(TAG, "Dropping event due to no window focus: " + event); 3647 finishInputEvent(q, true); 3648 return; 3649 } 3650 } 3651 deliverKeyEventPostIme(q); 3652 } else { 3653 MotionEvent event = (MotionEvent)q.mEvent; 3654 if (event.getAction() != MotionEvent.ACTION_CANCEL 3655 && event.getAction() != MotionEvent.ACTION_UP) { 3656 // If the window doesn't currently have input focus, then drop 3657 // this event. This could be an event that came back from the 3658 // IME dispatch but the window has lost focus in the meantime. 3659 if (!mAttachInfo.mHasWindowFocus) { 3660 Slog.w(TAG, "Dropping event due to no window focus: " + event); 3661 finishInputEvent(q, true); 3662 return; 3663 } 3664 } 3665 final int source = q.mEvent.getSource(); 3666 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 3667 deliverTrackballEventPostIme(q); 3668 } else { 3669 deliverGenericMotionEventPostIme(q); 3670 } 3671 } 3672 } 3673 } else { 3674 if (DEBUG_IMF) { 3675 Log.v(TAG, "IME finished event: seq=" + seq 3676 + " handled=" + handled + ", event not found!"); 3677 } 3678 } 3679 } 3680 deliverKeyEventPostIme(QueuedInputEvent q)3681 private void deliverKeyEventPostIme(QueuedInputEvent q) { 3682 final KeyEvent event = (KeyEvent)q.mEvent; 3683 3684 // If the view went away, then the event will not be handled. 3685 if (mView == null || !mAdded) { 3686 finishInputEvent(q, false); 3687 return; 3688 } 3689 3690 // If the key's purpose is to exit touch mode then we consume it and consider it handled. 3691 if (checkForLeavingTouchModeAndConsume(event)) { 3692 finishInputEvent(q, true); 3693 return; 3694 } 3695 3696 // Make sure the fallback event policy sees all keys that will be delivered to the 3697 // view hierarchy. 3698 mFallbackEventHandler.preDispatchKeyEvent(event); 3699 3700 // Deliver the key to the view hierarchy. 3701 if (mView.dispatchKeyEvent(event)) { 3702 finishInputEvent(q, true); 3703 return; 3704 } 3705 3706 // If the Control modifier is held, try to interpret the key as a shortcut. 3707 if (event.getAction() == KeyEvent.ACTION_DOWN 3708 && event.isCtrlPressed() 3709 && event.getRepeatCount() == 0 3710 && !KeyEvent.isModifierKey(event.getKeyCode())) { 3711 if (mView.dispatchKeyShortcutEvent(event)) { 3712 finishInputEvent(q, true); 3713 return; 3714 } 3715 } 3716 3717 // Apply the fallback event policy. 3718 if (mFallbackEventHandler.dispatchKeyEvent(event)) { 3719 finishInputEvent(q, true); 3720 return; 3721 } 3722 3723 // Handle automatic focus changes. 3724 if (event.getAction() == KeyEvent.ACTION_DOWN) { 3725 int direction = 0; 3726 switch (event.getKeyCode()) { 3727 case KeyEvent.KEYCODE_DPAD_LEFT: 3728 if (event.hasNoModifiers()) { 3729 direction = View.FOCUS_LEFT; 3730 } 3731 break; 3732 case KeyEvent.KEYCODE_DPAD_RIGHT: 3733 if (event.hasNoModifiers()) { 3734 direction = View.FOCUS_RIGHT; 3735 } 3736 break; 3737 case KeyEvent.KEYCODE_DPAD_UP: 3738 if (event.hasNoModifiers()) { 3739 direction = View.FOCUS_UP; 3740 } 3741 break; 3742 case KeyEvent.KEYCODE_DPAD_DOWN: 3743 if (event.hasNoModifiers()) { 3744 direction = View.FOCUS_DOWN; 3745 } 3746 break; 3747 case KeyEvent.KEYCODE_TAB: 3748 if (event.hasNoModifiers()) { 3749 direction = View.FOCUS_FORWARD; 3750 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) { 3751 direction = View.FOCUS_BACKWARD; 3752 } 3753 break; 3754 } 3755 if (direction != 0) { 3756 View focused = mView.findFocus(); 3757 if (focused != null) { 3758 View v = focused.focusSearch(direction); 3759 if (v != null && v != focused) { 3760 // do the math the get the interesting rect 3761 // of previous focused into the coord system of 3762 // newly focused view 3763 focused.getFocusedRect(mTempRect); 3764 if (mView instanceof ViewGroup) { 3765 ((ViewGroup) mView).offsetDescendantRectToMyCoords( 3766 focused, mTempRect); 3767 ((ViewGroup) mView).offsetRectIntoDescendantCoords( 3768 v, mTempRect); 3769 } 3770 if (v.requestFocus(direction, mTempRect)) { 3771 playSoundEffect(SoundEffectConstants 3772 .getContantForFocusDirection(direction)); 3773 finishInputEvent(q, true); 3774 return; 3775 } 3776 } 3777 3778 // Give the focused view a last chance to handle the dpad key. 3779 if (mView.dispatchUnhandledMove(focused, direction)) { 3780 finishInputEvent(q, true); 3781 return; 3782 } 3783 } 3784 } 3785 } 3786 3787 // Key was unhandled. 3788 finishInputEvent(q, false); 3789 } 3790 3791 /* drag/drop */ setLocalDragState(Object obj)3792 void setLocalDragState(Object obj) { 3793 mLocalDragState = obj; 3794 } 3795 handleDragEvent(DragEvent event)3796 private void handleDragEvent(DragEvent event) { 3797 // From the root, only drag start/end/location are dispatched. entered/exited 3798 // are determined and dispatched by the viewgroup hierarchy, who then report 3799 // that back here for ultimate reporting back to the framework. 3800 if (mView != null && mAdded) { 3801 final int what = event.mAction; 3802 3803 if (what == DragEvent.ACTION_DRAG_EXITED) { 3804 // A direct EXITED event means that the window manager knows we've just crossed 3805 // a window boundary, so the current drag target within this one must have 3806 // just been exited. Send it the usual notifications and then we're done 3807 // for now. 3808 mView.dispatchDragEvent(event); 3809 } else { 3810 // Cache the drag description when the operation starts, then fill it in 3811 // on subsequent calls as a convenience 3812 if (what == DragEvent.ACTION_DRAG_STARTED) { 3813 mCurrentDragView = null; // Start the current-recipient tracking 3814 mDragDescription = event.mClipDescription; 3815 } else { 3816 event.mClipDescription = mDragDescription; 3817 } 3818 3819 // For events with a [screen] location, translate into window coordinates 3820 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) { 3821 mDragPoint.set(event.mX, event.mY); 3822 if (mTranslator != null) { 3823 mTranslator.translatePointInScreenToAppWindow(mDragPoint); 3824 } 3825 3826 if (mCurScrollY != 0) { 3827 mDragPoint.offset(0, mCurScrollY); 3828 } 3829 3830 event.mX = mDragPoint.x; 3831 event.mY = mDragPoint.y; 3832 } 3833 3834 // Remember who the current drag target is pre-dispatch 3835 final View prevDragView = mCurrentDragView; 3836 3837 // Now dispatch the drag/drop event 3838 boolean result = mView.dispatchDragEvent(event); 3839 3840 // If we changed apparent drag target, tell the OS about it 3841 if (prevDragView != mCurrentDragView) { 3842 try { 3843 if (prevDragView != null) { 3844 mWindowSession.dragRecipientExited(mWindow); 3845 } 3846 if (mCurrentDragView != null) { 3847 mWindowSession.dragRecipientEntered(mWindow); 3848 } 3849 } catch (RemoteException e) { 3850 Slog.e(TAG, "Unable to note drag target change"); 3851 } 3852 } 3853 3854 // Report the drop result when we're done 3855 if (what == DragEvent.ACTION_DROP) { 3856 mDragDescription = null; 3857 try { 3858 Log.i(TAG, "Reporting drop result: " + result); 3859 mWindowSession.reportDropResult(mWindow, result); 3860 } catch (RemoteException e) { 3861 Log.e(TAG, "Unable to report drop result"); 3862 } 3863 } 3864 3865 // When the drag operation ends, release any local state object 3866 // that may have been in use 3867 if (what == DragEvent.ACTION_DRAG_ENDED) { 3868 setLocalDragState(null); 3869 } 3870 } 3871 } 3872 event.recycle(); 3873 } 3874 handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args)3875 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) { 3876 if (mSeq != args.seq) { 3877 // The sequence has changed, so we need to update our value and make 3878 // sure to do a traversal afterward so the window manager is given our 3879 // most recent data. 3880 mSeq = args.seq; 3881 mAttachInfo.mForceReportNewAttributes = true; 3882 scheduleTraversals(); 3883 } 3884 if (mView == null) return; 3885 if (args.localChanges != 0) { 3886 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges); 3887 } 3888 if (mAttachInfo != null) { 3889 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS; 3890 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) { 3891 mAttachInfo.mGlobalSystemUiVisibility = visibility; 3892 mView.dispatchSystemUiVisibilityChanged(visibility); 3893 } 3894 } 3895 } 3896 handleDispatchDoneAnimating()3897 public void handleDispatchDoneAnimating() { 3898 if (mWindowsAnimating) { 3899 mWindowsAnimating = false; 3900 if (!mDirty.isEmpty() || mIsAnimating) { 3901 scheduleTraversals(); 3902 } 3903 } 3904 } 3905 getLastTouchPoint(Point outLocation)3906 public void getLastTouchPoint(Point outLocation) { 3907 outLocation.x = (int) mLastTouchPoint.x; 3908 outLocation.y = (int) mLastTouchPoint.y; 3909 } 3910 setDragFocus(View newDragTarget)3911 public void setDragFocus(View newDragTarget) { 3912 if (mCurrentDragView != newDragTarget) { 3913 mCurrentDragView = newDragTarget; 3914 } 3915 } 3916 getAudioManager()3917 private AudioManager getAudioManager() { 3918 if (mView == null) { 3919 throw new IllegalStateException("getAudioManager called when there is no mView"); 3920 } 3921 if (mAudioManager == null) { 3922 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE); 3923 } 3924 return mAudioManager; 3925 } 3926 getAccessibilityInteractionController()3927 public AccessibilityInteractionController getAccessibilityInteractionController() { 3928 if (mView == null) { 3929 throw new IllegalStateException("getAccessibilityInteractionController" 3930 + " called when there is no mView"); 3931 } 3932 if (mAccessibilityInteractionController == null) { 3933 mAccessibilityInteractionController = new AccessibilityInteractionController(this); 3934 } 3935 return mAccessibilityInteractionController; 3936 } 3937 relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending)3938 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, 3939 boolean insetsPending) throws RemoteException { 3940 3941 float appScale = mAttachInfo.mApplicationScale; 3942 boolean restore = false; 3943 if (params != null && mTranslator != null) { 3944 restore = true; 3945 params.backup(); 3946 mTranslator.translateWindowLayout(params); 3947 } 3948 if (params != null) { 3949 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params); 3950 } 3951 mPendingConfiguration.seq = 0; 3952 //Log.d(TAG, ">>>>>> CALLING relayout"); 3953 if (params != null && mOrigWindowType != params.type) { 3954 // For compatibility with old apps, don't crash here. 3955 if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 3956 Slog.w(TAG, "Window type can not be changed after " 3957 + "the window is added; ignoring change of " + mView); 3958 params.type = mOrigWindowType; 3959 } 3960 } 3961 int relayoutResult = mWindowSession.relayout( 3962 mWindow, mSeq, params, 3963 (int) (mView.getMeasuredWidth() * appScale + 0.5f), 3964 (int) (mView.getMeasuredHeight() * appScale + 0.5f), 3965 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, 3966 mWinFrame, mPendingContentInsets, mPendingVisibleInsets, 3967 mPendingConfiguration, mSurface); 3968 //Log.d(TAG, "<<<<<< BACK FROM relayout"); 3969 if (restore) { 3970 params.restore(); 3971 } 3972 3973 if (mTranslator != null) { 3974 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame); 3975 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets); 3976 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets); 3977 } 3978 return relayoutResult; 3979 } 3980 3981 /** 3982 * {@inheritDoc} 3983 */ playSoundEffect(int effectId)3984 public void playSoundEffect(int effectId) { 3985 checkThread(); 3986 3987 try { 3988 final AudioManager audioManager = getAudioManager(); 3989 3990 switch (effectId) { 3991 case SoundEffectConstants.CLICK: 3992 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); 3993 return; 3994 case SoundEffectConstants.NAVIGATION_DOWN: 3995 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN); 3996 return; 3997 case SoundEffectConstants.NAVIGATION_LEFT: 3998 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT); 3999 return; 4000 case SoundEffectConstants.NAVIGATION_RIGHT: 4001 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT); 4002 return; 4003 case SoundEffectConstants.NAVIGATION_UP: 4004 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP); 4005 return; 4006 default: 4007 throw new IllegalArgumentException("unknown effect id " + effectId + 4008 " not defined in " + SoundEffectConstants.class.getCanonicalName()); 4009 } 4010 } catch (IllegalStateException e) { 4011 // Exception thrown by getAudioManager() when mView is null 4012 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e); 4013 e.printStackTrace(); 4014 } 4015 } 4016 4017 /** 4018 * {@inheritDoc} 4019 */ performHapticFeedback(int effectId, boolean always)4020 public boolean performHapticFeedback(int effectId, boolean always) { 4021 try { 4022 return mWindowSession.performHapticFeedback(mWindow, effectId, always); 4023 } catch (RemoteException e) { 4024 return false; 4025 } 4026 } 4027 4028 /** 4029 * {@inheritDoc} 4030 */ focusSearch(View focused, int direction)4031 public View focusSearch(View focused, int direction) { 4032 checkThread(); 4033 if (!(mView instanceof ViewGroup)) { 4034 return null; 4035 } 4036 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction); 4037 } 4038 debug()4039 public void debug() { 4040 mView.debug(); 4041 } 4042 dumpGfxInfo(int[] info)4043 public void dumpGfxInfo(int[] info) { 4044 info[0] = info[1] = 0; 4045 if (mView != null) { 4046 getGfxInfo(mView, info); 4047 } 4048 } 4049 getGfxInfo(View view, int[] info)4050 private static void getGfxInfo(View view, int[] info) { 4051 DisplayList displayList = view.mDisplayList; 4052 info[0]++; 4053 if (displayList != null) { 4054 info[1] += displayList.getSize(); 4055 } 4056 4057 if (view instanceof ViewGroup) { 4058 ViewGroup group = (ViewGroup) view; 4059 4060 int count = group.getChildCount(); 4061 for (int i = 0; i < count; i++) { 4062 getGfxInfo(group.getChildAt(i), info); 4063 } 4064 } 4065 } 4066 die(boolean immediate)4067 public void die(boolean immediate) { 4068 // Make sure we do execute immediately if we are in the middle of a traversal or the damage 4069 // done by dispatchDetachedFromWindow will cause havoc on return. 4070 if (immediate && !mIsInTraversal) { 4071 doDie(); 4072 } else { 4073 if (!mIsDrawing) { 4074 destroyHardwareRenderer(); 4075 } else { 4076 Log.e(TAG, "Attempting to destroy the window while drawing!\n" + 4077 " window=" + this + ", title=" + mWindowAttributes.getTitle()); 4078 } 4079 mHandler.sendEmptyMessage(MSG_DIE); 4080 } 4081 } 4082 doDie()4083 void doDie() { 4084 checkThread(); 4085 if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface); 4086 synchronized (this) { 4087 if (mAdded) { 4088 dispatchDetachedFromWindow(); 4089 } 4090 4091 if (mAdded && !mFirst) { 4092 destroyHardwareRenderer(); 4093 4094 if (mView != null) { 4095 int viewVisibility = mView.getVisibility(); 4096 boolean viewVisibilityChanged = mViewVisibility != viewVisibility; 4097 if (mWindowAttributesChanged || viewVisibilityChanged) { 4098 // If layout params have been changed, first give them 4099 // to the window manager to make sure it has the correct 4100 // animation info. 4101 try { 4102 if ((relayoutWindow(mWindowAttributes, viewVisibility, false) 4103 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { 4104 mWindowSession.finishDrawing(mWindow); 4105 } 4106 } catch (RemoteException e) { 4107 } 4108 } 4109 4110 mSurface.release(); 4111 } 4112 } 4113 4114 mAdded = false; 4115 } 4116 } 4117 requestUpdateConfiguration(Configuration config)4118 public void requestUpdateConfiguration(Configuration config) { 4119 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config); 4120 mHandler.sendMessage(msg); 4121 } 4122 loadSystemProperties()4123 public void loadSystemProperties() { 4124 boolean layout = SystemProperties.getBoolean( 4125 View.DEBUG_LAYOUT_PROPERTY, false); 4126 if (layout != mAttachInfo.mDebugLayout) { 4127 mAttachInfo.mDebugLayout = layout; 4128 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) { 4129 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200); 4130 } 4131 } 4132 } 4133 destroyHardwareRenderer()4134 private void destroyHardwareRenderer() { 4135 AttachInfo attachInfo = mAttachInfo; 4136 HardwareRenderer hardwareRenderer = attachInfo.mHardwareRenderer; 4137 4138 if (hardwareRenderer != null) { 4139 if (mView != null) { 4140 hardwareRenderer.destroyHardwareResources(mView); 4141 } 4142 hardwareRenderer.destroy(true); 4143 hardwareRenderer.setRequested(false); 4144 4145 attachInfo.mHardwareRenderer = null; 4146 attachInfo.mHardwareAccelerated = false; 4147 } 4148 } 4149 dispatchImeFinishedEvent(int seq, boolean handled)4150 void dispatchImeFinishedEvent(int seq, boolean handled) { 4151 Message msg = mHandler.obtainMessage(MSG_IME_FINISHED_EVENT); 4152 msg.arg1 = seq; 4153 msg.arg2 = handled ? 1 : 0; 4154 msg.setAsynchronous(true); 4155 mHandler.sendMessage(msg); 4156 } 4157 dispatchFinishInputConnection(InputConnection connection)4158 public void dispatchFinishInputConnection(InputConnection connection) { 4159 Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection); 4160 mHandler.sendMessage(msg); 4161 } 4162 dispatchResized(Rect frame, Rect contentInsets, Rect visibleInsets, boolean reportDraw, Configuration newConfig)4163 public void dispatchResized(Rect frame, Rect contentInsets, 4164 Rect visibleInsets, boolean reportDraw, Configuration newConfig) { 4165 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString() 4166 + " contentInsets=" + contentInsets.toShortString() 4167 + " visibleInsets=" + visibleInsets.toShortString() 4168 + " reportDraw=" + reportDraw); 4169 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED); 4170 if (mTranslator != null) { 4171 mTranslator.translateRectInScreenToAppWindow(frame); 4172 mTranslator.translateRectInScreenToAppWindow(contentInsets); 4173 mTranslator.translateRectInScreenToAppWindow(visibleInsets); 4174 } 4175 SomeArgs args = SomeArgs.obtain(); 4176 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid()); 4177 args.arg1 = sameProcessCall ? new Rect(frame) : frame; 4178 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets; 4179 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets; 4180 args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig; 4181 msg.obj = args; 4182 mHandler.sendMessage(msg); 4183 } 4184 dispatchMoved(int newX, int newY)4185 public void dispatchMoved(int newX, int newY) { 4186 if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY); 4187 if (mTranslator != null) { 4188 PointF point = new PointF(newX, newY); 4189 mTranslator.translatePointInScreenToAppWindow(point); 4190 newX = (int) (point.x + 0.5); 4191 newY = (int) (point.y + 0.5); 4192 } 4193 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY); 4194 mHandler.sendMessage(msg); 4195 } 4196 4197 /** 4198 * Represents a pending input event that is waiting in a queue. 4199 * 4200 * Input events are processed in serial order by the timestamp specified by 4201 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers 4202 * one input event to the application at a time and waits for the application 4203 * to finish handling it before delivering the next one. 4204 * 4205 * However, because the application or IME can synthesize and inject multiple 4206 * key events at a time without going through the input dispatcher, we end up 4207 * needing a queue on the application's side. 4208 */ 4209 private static final class QueuedInputEvent { 4210 public static final int FLAG_DELIVER_POST_IME = 1; 4211 4212 public QueuedInputEvent mNext; 4213 4214 public InputEvent mEvent; 4215 public InputEventReceiver mReceiver; 4216 public int mFlags; 4217 } 4218 obtainQueuedInputEvent(InputEvent event, InputEventReceiver receiver, int flags)4219 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event, 4220 InputEventReceiver receiver, int flags) { 4221 QueuedInputEvent q = mQueuedInputEventPool; 4222 if (q != null) { 4223 mQueuedInputEventPoolSize -= 1; 4224 mQueuedInputEventPool = q.mNext; 4225 q.mNext = null; 4226 } else { 4227 q = new QueuedInputEvent(); 4228 } 4229 4230 q.mEvent = event; 4231 q.mReceiver = receiver; 4232 q.mFlags = flags; 4233 return q; 4234 } 4235 recycleQueuedInputEvent(QueuedInputEvent q)4236 private void recycleQueuedInputEvent(QueuedInputEvent q) { 4237 q.mEvent = null; 4238 q.mReceiver = null; 4239 4240 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) { 4241 mQueuedInputEventPoolSize += 1; 4242 q.mNext = mQueuedInputEventPool; 4243 mQueuedInputEventPool = q; 4244 } 4245 } 4246 enqueueInputEvent(InputEvent event)4247 void enqueueInputEvent(InputEvent event) { 4248 enqueueInputEvent(event, null, 0, false); 4249 } 4250 enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately)4251 void enqueueInputEvent(InputEvent event, 4252 InputEventReceiver receiver, int flags, boolean processImmediately) { 4253 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); 4254 4255 // Always enqueue the input event in order, regardless of its time stamp. 4256 // We do this because the application or the IME may inject key events 4257 // in response to touch events and we want to ensure that the injected keys 4258 // are processed in the order they were received and we cannot trust that 4259 // the time stamp of injected events are monotonic. 4260 QueuedInputEvent last = mFirstPendingInputEvent; 4261 if (last == null) { 4262 mFirstPendingInputEvent = q; 4263 } else { 4264 while (last.mNext != null) { 4265 last = last.mNext; 4266 } 4267 last.mNext = q; 4268 } 4269 4270 if (processImmediately) { 4271 doProcessInputEvents(); 4272 } else { 4273 scheduleProcessInputEvents(); 4274 } 4275 } 4276 scheduleProcessInputEvents()4277 private void scheduleProcessInputEvents() { 4278 if (!mProcessInputEventsScheduled) { 4279 mProcessInputEventsScheduled = true; 4280 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS); 4281 msg.setAsynchronous(true); 4282 mHandler.sendMessage(msg); 4283 } 4284 } 4285 doProcessInputEvents()4286 void doProcessInputEvents() { 4287 while (mCurrentInputEvent == null && mFirstPendingInputEvent != null) { 4288 QueuedInputEvent q = mFirstPendingInputEvent; 4289 mFirstPendingInputEvent = q.mNext; 4290 q.mNext = null; 4291 mCurrentInputEvent = q; 4292 deliverInputEvent(q); 4293 } 4294 4295 // We are done processing all input events that we can process right now 4296 // so we can clear the pending flag immediately. 4297 if (mProcessInputEventsScheduled) { 4298 mProcessInputEventsScheduled = false; 4299 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS); 4300 } 4301 } 4302 finishInputEvent(QueuedInputEvent q, boolean handled)4303 private void finishInputEvent(QueuedInputEvent q, boolean handled) { 4304 if (q != mCurrentInputEvent) { 4305 throw new IllegalStateException("finished input event out of order"); 4306 } 4307 4308 if (q.mReceiver != null) { 4309 q.mReceiver.finishInputEvent(q.mEvent, handled); 4310 } else { 4311 q.mEvent.recycleIfNeededAfterDispatch(); 4312 } 4313 4314 recycleQueuedInputEvent(q); 4315 4316 mCurrentInputEvent = null; 4317 if (mFirstPendingInputEvent != null) { 4318 scheduleProcessInputEvents(); 4319 } 4320 } 4321 scheduleConsumeBatchedInput()4322 void scheduleConsumeBatchedInput() { 4323 if (!mConsumeBatchedInputScheduled) { 4324 mConsumeBatchedInputScheduled = true; 4325 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, 4326 mConsumedBatchedInputRunnable, null); 4327 } 4328 } 4329 unscheduleConsumeBatchedInput()4330 void unscheduleConsumeBatchedInput() { 4331 if (mConsumeBatchedInputScheduled) { 4332 mConsumeBatchedInputScheduled = false; 4333 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT, 4334 mConsumedBatchedInputRunnable, null); 4335 } 4336 } 4337 doConsumeBatchedInput(long frameTimeNanos)4338 void doConsumeBatchedInput(long frameTimeNanos) { 4339 if (mConsumeBatchedInputScheduled) { 4340 mConsumeBatchedInputScheduled = false; 4341 if (mInputEventReceiver != null) { 4342 mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos); 4343 } 4344 doProcessInputEvents(); 4345 } 4346 } 4347 4348 final class TraversalRunnable implements Runnable { 4349 @Override run()4350 public void run() { 4351 doTraversal(); 4352 } 4353 } 4354 final TraversalRunnable mTraversalRunnable = new TraversalRunnable(); 4355 4356 final class WindowInputEventReceiver extends InputEventReceiver { WindowInputEventReceiver(InputChannel inputChannel, Looper looper)4357 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { 4358 super(inputChannel, looper); 4359 } 4360 4361 @Override onInputEvent(InputEvent event)4362 public void onInputEvent(InputEvent event) { 4363 enqueueInputEvent(event, this, 0, true); 4364 } 4365 4366 @Override onBatchedInputEventPending()4367 public void onBatchedInputEventPending() { 4368 scheduleConsumeBatchedInput(); 4369 } 4370 4371 @Override dispose()4372 public void dispose() { 4373 unscheduleConsumeBatchedInput(); 4374 super.dispose(); 4375 } 4376 } 4377 WindowInputEventReceiver mInputEventReceiver; 4378 4379 final class ConsumeBatchedInputRunnable implements Runnable { 4380 @Override run()4381 public void run() { 4382 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos()); 4383 } 4384 } 4385 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable = 4386 new ConsumeBatchedInputRunnable(); 4387 boolean mConsumeBatchedInputScheduled; 4388 4389 final class InvalidateOnAnimationRunnable implements Runnable { 4390 private boolean mPosted; 4391 private ArrayList<View> mViews = new ArrayList<View>(); 4392 private ArrayList<AttachInfo.InvalidateInfo> mViewRects = 4393 new ArrayList<AttachInfo.InvalidateInfo>(); 4394 private View[] mTempViews; 4395 private AttachInfo.InvalidateInfo[] mTempViewRects; 4396 addView(View view)4397 public void addView(View view) { 4398 synchronized (this) { 4399 mViews.add(view); 4400 postIfNeededLocked(); 4401 } 4402 } 4403 addViewRect(AttachInfo.InvalidateInfo info)4404 public void addViewRect(AttachInfo.InvalidateInfo info) { 4405 synchronized (this) { 4406 mViewRects.add(info); 4407 postIfNeededLocked(); 4408 } 4409 } 4410 removeView(View view)4411 public void removeView(View view) { 4412 synchronized (this) { 4413 mViews.remove(view); 4414 4415 for (int i = mViewRects.size(); i-- > 0; ) { 4416 AttachInfo.InvalidateInfo info = mViewRects.get(i); 4417 if (info.target == view) { 4418 mViewRects.remove(i); 4419 info.release(); 4420 } 4421 } 4422 4423 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) { 4424 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null); 4425 mPosted = false; 4426 } 4427 } 4428 } 4429 4430 @Override run()4431 public void run() { 4432 final int viewCount; 4433 final int viewRectCount; 4434 synchronized (this) { 4435 mPosted = false; 4436 4437 viewCount = mViews.size(); 4438 if (viewCount != 0) { 4439 mTempViews = mViews.toArray(mTempViews != null 4440 ? mTempViews : new View[viewCount]); 4441 mViews.clear(); 4442 } 4443 4444 viewRectCount = mViewRects.size(); 4445 if (viewRectCount != 0) { 4446 mTempViewRects = mViewRects.toArray(mTempViewRects != null 4447 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]); 4448 mViewRects.clear(); 4449 } 4450 } 4451 4452 for (int i = 0; i < viewCount; i++) { 4453 mTempViews[i].invalidate(); 4454 mTempViews[i] = null; 4455 } 4456 4457 for (int i = 0; i < viewRectCount; i++) { 4458 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i]; 4459 info.target.invalidate(info.left, info.top, info.right, info.bottom); 4460 info.release(); 4461 } 4462 } 4463 postIfNeededLocked()4464 private void postIfNeededLocked() { 4465 if (!mPosted) { 4466 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null); 4467 mPosted = true; 4468 } 4469 } 4470 } 4471 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable = 4472 new InvalidateOnAnimationRunnable(); 4473 dispatchInvalidateDelayed(View view, long delayMilliseconds)4474 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) { 4475 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view); 4476 mHandler.sendMessageDelayed(msg, delayMilliseconds); 4477 } 4478 dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, long delayMilliseconds)4479 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, 4480 long delayMilliseconds) { 4481 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info); 4482 mHandler.sendMessageDelayed(msg, delayMilliseconds); 4483 } 4484 dispatchInvalidateOnAnimation(View view)4485 public void dispatchInvalidateOnAnimation(View view) { 4486 mInvalidateOnAnimationRunnable.addView(view); 4487 } 4488 dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info)4489 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) { 4490 mInvalidateOnAnimationRunnable.addViewRect(info); 4491 } 4492 enqueueDisplayList(DisplayList displayList)4493 public void enqueueDisplayList(DisplayList displayList) { 4494 mDisplayLists.add(displayList); 4495 4496 mHandler.removeMessages(MSG_INVALIDATE_DISPLAY_LIST); 4497 Message msg = mHandler.obtainMessage(MSG_INVALIDATE_DISPLAY_LIST); 4498 mHandler.sendMessage(msg); 4499 } 4500 dequeueDisplayList(DisplayList displayList)4501 public void dequeueDisplayList(DisplayList displayList) { 4502 if (mDisplayLists.remove(displayList)) { 4503 displayList.invalidate(); 4504 if (mDisplayLists.size() == 0) { 4505 mHandler.removeMessages(MSG_INVALIDATE_DISPLAY_LIST); 4506 } 4507 } 4508 } 4509 cancelInvalidate(View view)4510 public void cancelInvalidate(View view) { 4511 mHandler.removeMessages(MSG_INVALIDATE, view); 4512 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning 4513 // them to the pool 4514 mHandler.removeMessages(MSG_INVALIDATE_RECT, view); 4515 mInvalidateOnAnimationRunnable.removeView(view); 4516 } 4517 dispatchKey(KeyEvent event)4518 public void dispatchKey(KeyEvent event) { 4519 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY, event); 4520 msg.setAsynchronous(true); 4521 mHandler.sendMessage(msg); 4522 } 4523 dispatchKeyFromIme(KeyEvent event)4524 public void dispatchKeyFromIme(KeyEvent event) { 4525 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event); 4526 msg.setAsynchronous(true); 4527 mHandler.sendMessage(msg); 4528 } 4529 dispatchUnhandledKey(KeyEvent event)4530 public void dispatchUnhandledKey(KeyEvent event) { 4531 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { 4532 final KeyCharacterMap kcm = event.getKeyCharacterMap(); 4533 final int keyCode = event.getKeyCode(); 4534 final int metaState = event.getMetaState(); 4535 4536 // Check for fallback actions specified by the key character map. 4537 KeyCharacterMap.FallbackAction fallbackAction = 4538 kcm.getFallbackAction(keyCode, metaState); 4539 if (fallbackAction != null) { 4540 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK; 4541 KeyEvent fallbackEvent = KeyEvent.obtain( 4542 event.getDownTime(), event.getEventTime(), 4543 event.getAction(), fallbackAction.keyCode, 4544 event.getRepeatCount(), fallbackAction.metaState, 4545 event.getDeviceId(), event.getScanCode(), 4546 flags, event.getSource(), null); 4547 fallbackAction.recycle(); 4548 4549 dispatchKey(fallbackEvent); 4550 } 4551 } 4552 } 4553 dispatchAppVisibility(boolean visible)4554 public void dispatchAppVisibility(boolean visible) { 4555 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY); 4556 msg.arg1 = visible ? 1 : 0; 4557 mHandler.sendMessage(msg); 4558 } 4559 dispatchScreenStateChange(boolean on)4560 public void dispatchScreenStateChange(boolean on) { 4561 Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATE); 4562 msg.arg1 = on ? 1 : 0; 4563 mHandler.sendMessage(msg); 4564 } 4565 dispatchGetNewSurface()4566 public void dispatchGetNewSurface() { 4567 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE); 4568 mHandler.sendMessage(msg); 4569 } 4570 windowFocusChanged(boolean hasFocus, boolean inTouchMode)4571 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) { 4572 Message msg = Message.obtain(); 4573 msg.what = MSG_WINDOW_FOCUS_CHANGED; 4574 msg.arg1 = hasFocus ? 1 : 0; 4575 msg.arg2 = inTouchMode ? 1 : 0; 4576 mHandler.sendMessage(msg); 4577 } 4578 dispatchCloseSystemDialogs(String reason)4579 public void dispatchCloseSystemDialogs(String reason) { 4580 Message msg = Message.obtain(); 4581 msg.what = MSG_CLOSE_SYSTEM_DIALOGS; 4582 msg.obj = reason; 4583 mHandler.sendMessage(msg); 4584 } 4585 dispatchDragEvent(DragEvent event)4586 public void dispatchDragEvent(DragEvent event) { 4587 final int what; 4588 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) { 4589 what = MSG_DISPATCH_DRAG_LOCATION_EVENT; 4590 mHandler.removeMessages(what); 4591 } else { 4592 what = MSG_DISPATCH_DRAG_EVENT; 4593 } 4594 Message msg = mHandler.obtainMessage(what, event); 4595 mHandler.sendMessage(msg); 4596 } 4597 dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue, int localChanges)4598 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, 4599 int localValue, int localChanges) { 4600 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo(); 4601 args.seq = seq; 4602 args.globalVisibility = globalVisibility; 4603 args.localValue = localValue; 4604 args.localChanges = localChanges; 4605 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args)); 4606 } 4607 dispatchDoneAnimating()4608 public void dispatchDoneAnimating() { 4609 mHandler.sendEmptyMessage(MSG_DISPATCH_DONE_ANIMATING); 4610 } 4611 dispatchCheckFocus()4612 public void dispatchCheckFocus() { 4613 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) { 4614 // This will result in a call to checkFocus() below. 4615 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS); 4616 } 4617 } 4618 4619 /** 4620 * Post a callback to send a 4621 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event. 4622 * This event is send at most once every 4623 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 4624 */ postSendWindowContentChangedCallback(View source)4625 private void postSendWindowContentChangedCallback(View source) { 4626 if (mSendWindowContentChangedAccessibilityEvent == null) { 4627 mSendWindowContentChangedAccessibilityEvent = 4628 new SendWindowContentChangedAccessibilityEvent(); 4629 } 4630 View oldSource = mSendWindowContentChangedAccessibilityEvent.mSource; 4631 if (oldSource == null) { 4632 mSendWindowContentChangedAccessibilityEvent.mSource = source; 4633 mHandler.postDelayed(mSendWindowContentChangedAccessibilityEvent, 4634 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 4635 } else { 4636 mSendWindowContentChangedAccessibilityEvent.mSource = 4637 getCommonPredecessor(oldSource, source); 4638 } 4639 } 4640 4641 /** 4642 * Remove a posted callback to send a 4643 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event. 4644 */ removeSendWindowContentChangedCallback()4645 private void removeSendWindowContentChangedCallback() { 4646 if (mSendWindowContentChangedAccessibilityEvent != null) { 4647 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent); 4648 } 4649 } 4650 showContextMenuForChild(View originalView)4651 public boolean showContextMenuForChild(View originalView) { 4652 return false; 4653 } 4654 startActionModeForChild(View originalView, ActionMode.Callback callback)4655 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { 4656 return null; 4657 } 4658 createContextMenu(ContextMenu menu)4659 public void createContextMenu(ContextMenu menu) { 4660 } 4661 childDrawableStateChanged(View child)4662 public void childDrawableStateChanged(View child) { 4663 } 4664 requestSendAccessibilityEvent(View child, AccessibilityEvent event)4665 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) { 4666 if (mView == null) { 4667 return false; 4668 } 4669 // Intercept accessibility focus events fired by virtual nodes to keep 4670 // track of accessibility focus position in such nodes. 4671 final int eventType = event.getEventType(); 4672 switch (eventType) { 4673 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { 4674 final long sourceNodeId = event.getSourceNodeId(); 4675 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId( 4676 sourceNodeId); 4677 View source = mView.findViewByAccessibilityId(accessibilityViewId); 4678 if (source != null) { 4679 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider(); 4680 if (provider != null) { 4681 AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo( 4682 AccessibilityNodeInfo.getVirtualDescendantId(sourceNodeId)); 4683 setAccessibilityFocus(source, node); 4684 } 4685 } 4686 } break; 4687 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { 4688 final long sourceNodeId = event.getSourceNodeId(); 4689 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId( 4690 sourceNodeId); 4691 View source = mView.findViewByAccessibilityId(accessibilityViewId); 4692 if (source != null) { 4693 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider(); 4694 if (provider != null) { 4695 setAccessibilityFocus(null, null); 4696 } 4697 } 4698 } break; 4699 } 4700 mAccessibilityManager.sendAccessibilityEvent(event); 4701 return true; 4702 } 4703 4704 @Override childAccessibilityStateChanged(View child)4705 public void childAccessibilityStateChanged(View child) { 4706 postSendWindowContentChangedCallback(child); 4707 } 4708 getCommonPredecessor(View first, View second)4709 private View getCommonPredecessor(View first, View second) { 4710 if (mAttachInfo != null) { 4711 if (mTempHashSet == null) { 4712 mTempHashSet = new HashSet<View>(); 4713 } 4714 HashSet<View> seen = mTempHashSet; 4715 seen.clear(); 4716 View firstCurrent = first; 4717 while (firstCurrent != null) { 4718 seen.add(firstCurrent); 4719 ViewParent firstCurrentParent = firstCurrent.mParent; 4720 if (firstCurrentParent instanceof View) { 4721 firstCurrent = (View) firstCurrentParent; 4722 } else { 4723 firstCurrent = null; 4724 } 4725 } 4726 View secondCurrent = second; 4727 while (secondCurrent != null) { 4728 if (seen.contains(secondCurrent)) { 4729 seen.clear(); 4730 return secondCurrent; 4731 } 4732 ViewParent secondCurrentParent = secondCurrent.mParent; 4733 if (secondCurrentParent instanceof View) { 4734 secondCurrent = (View) secondCurrentParent; 4735 } else { 4736 secondCurrent = null; 4737 } 4738 } 4739 seen.clear(); 4740 } 4741 return null; 4742 } 4743 checkThread()4744 void checkThread() { 4745 if (mThread != Thread.currentThread()) { 4746 throw new CalledFromWrongThreadException( 4747 "Only the original thread that created a view hierarchy can touch its views."); 4748 } 4749 } 4750 requestDisallowInterceptTouchEvent(boolean disallowIntercept)4751 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 4752 // ViewAncestor never intercepts touch event, so this can be a no-op 4753 } 4754 requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate)4755 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { 4756 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate); 4757 if (rectangle != null) { 4758 mTempRect.set(rectangle); 4759 mTempRect.offset(0, -mCurScrollY); 4760 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 4761 try { 4762 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate); 4763 } catch (RemoteException re) { 4764 /* ignore */ 4765 } 4766 } 4767 return scrolled; 4768 } 4769 childHasTransientStateChanged(View child, boolean hasTransientState)4770 public void childHasTransientStateChanged(View child, boolean hasTransientState) { 4771 // Do nothing. 4772 } 4773 4774 class TakenSurfaceHolder extends BaseSurfaceHolder { 4775 @Override onAllowLockCanvas()4776 public boolean onAllowLockCanvas() { 4777 return mDrawingAllowed; 4778 } 4779 4780 @Override onRelayoutContainer()4781 public void onRelayoutContainer() { 4782 // Not currently interesting -- from changing between fixed and layout size. 4783 } 4784 setFormat(int format)4785 public void setFormat(int format) { 4786 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format); 4787 } 4788 setType(int type)4789 public void setType(int type) { 4790 ((RootViewSurfaceTaker)mView).setSurfaceType(type); 4791 } 4792 4793 @Override onUpdateSurface()4794 public void onUpdateSurface() { 4795 // We take care of format and type changes on our own. 4796 throw new IllegalStateException("Shouldn't be here"); 4797 } 4798 isCreating()4799 public boolean isCreating() { 4800 return mIsCreating; 4801 } 4802 4803 @Override setFixedSize(int width, int height)4804 public void setFixedSize(int width, int height) { 4805 throw new UnsupportedOperationException( 4806 "Currently only support sizing from layout"); 4807 } 4808 setKeepScreenOn(boolean screenOn)4809 public void setKeepScreenOn(boolean screenOn) { 4810 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn); 4811 } 4812 } 4813 4814 static final class InputMethodCallback implements InputMethodManager.FinishedEventCallback { 4815 private WeakReference<ViewRootImpl> mViewAncestor; 4816 InputMethodCallback(ViewRootImpl viewAncestor)4817 public InputMethodCallback(ViewRootImpl viewAncestor) { 4818 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); 4819 } 4820 4821 @Override finishedEvent(int seq, boolean handled)4822 public void finishedEvent(int seq, boolean handled) { 4823 final ViewRootImpl viewAncestor = mViewAncestor.get(); 4824 if (viewAncestor != null) { 4825 viewAncestor.dispatchImeFinishedEvent(seq, handled); 4826 } 4827 } 4828 } 4829 4830 static class W extends IWindow.Stub { 4831 private final WeakReference<ViewRootImpl> mViewAncestor; 4832 private final IWindowSession mWindowSession; 4833 W(ViewRootImpl viewAncestor)4834 W(ViewRootImpl viewAncestor) { 4835 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); 4836 mWindowSession = viewAncestor.mWindowSession; 4837 } 4838 resized(Rect frame, Rect contentInsets, Rect visibleInsets, boolean reportDraw, Configuration newConfig)4839 public void resized(Rect frame, Rect contentInsets, 4840 Rect visibleInsets, boolean reportDraw, Configuration newConfig) { 4841 final ViewRootImpl viewAncestor = mViewAncestor.get(); 4842 if (viewAncestor != null) { 4843 viewAncestor.dispatchResized(frame, contentInsets, 4844 visibleInsets, reportDraw, newConfig); 4845 } 4846 } 4847 4848 @Override moved(int newX, int newY)4849 public void moved(int newX, int newY) { 4850 final ViewRootImpl viewAncestor = mViewAncestor.get(); 4851 if (viewAncestor != null) { 4852 viewAncestor.dispatchMoved(newX, newY); 4853 } 4854 } 4855 dispatchAppVisibility(boolean visible)4856 public void dispatchAppVisibility(boolean visible) { 4857 final ViewRootImpl viewAncestor = mViewAncestor.get(); 4858 if (viewAncestor != null) { 4859 viewAncestor.dispatchAppVisibility(visible); 4860 } 4861 } 4862 dispatchScreenState(boolean on)4863 public void dispatchScreenState(boolean on) { 4864 final ViewRootImpl viewAncestor = mViewAncestor.get(); 4865 if (viewAncestor != null) { 4866 viewAncestor.dispatchScreenStateChange(on); 4867 } 4868 } 4869 dispatchGetNewSurface()4870 public void dispatchGetNewSurface() { 4871 final ViewRootImpl viewAncestor = mViewAncestor.get(); 4872 if (viewAncestor != null) { 4873 viewAncestor.dispatchGetNewSurface(); 4874 } 4875 } 4876 windowFocusChanged(boolean hasFocus, boolean inTouchMode)4877 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) { 4878 final ViewRootImpl viewAncestor = mViewAncestor.get(); 4879 if (viewAncestor != null) { 4880 viewAncestor.windowFocusChanged(hasFocus, inTouchMode); 4881 } 4882 } 4883 checkCallingPermission(String permission)4884 private static int checkCallingPermission(String permission) { 4885 try { 4886 return ActivityManagerNative.getDefault().checkPermission( 4887 permission, Binder.getCallingPid(), Binder.getCallingUid()); 4888 } catch (RemoteException e) { 4889 return PackageManager.PERMISSION_DENIED; 4890 } 4891 } 4892 executeCommand(String command, String parameters, ParcelFileDescriptor out)4893 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) { 4894 final ViewRootImpl viewAncestor = mViewAncestor.get(); 4895 if (viewAncestor != null) { 4896 final View view = viewAncestor.mView; 4897 if (view != null) { 4898 if (checkCallingPermission(Manifest.permission.DUMP) != 4899 PackageManager.PERMISSION_GRANTED) { 4900 throw new SecurityException("Insufficient permissions to invoke" 4901 + " executeCommand() from pid=" + Binder.getCallingPid() 4902 + ", uid=" + Binder.getCallingUid()); 4903 } 4904 4905 OutputStream clientStream = null; 4906 try { 4907 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out); 4908 ViewDebug.dispatchCommand(view, command, parameters, clientStream); 4909 } catch (IOException e) { 4910 e.printStackTrace(); 4911 } finally { 4912 if (clientStream != null) { 4913 try { 4914 clientStream.close(); 4915 } catch (IOException e) { 4916 e.printStackTrace(); 4917 } 4918 } 4919 } 4920 } 4921 } 4922 } 4923 closeSystemDialogs(String reason)4924 public void closeSystemDialogs(String reason) { 4925 final ViewRootImpl viewAncestor = mViewAncestor.get(); 4926 if (viewAncestor != null) { 4927 viewAncestor.dispatchCloseSystemDialogs(reason); 4928 } 4929 } 4930 dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync)4931 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, 4932 boolean sync) { 4933 if (sync) { 4934 try { 4935 mWindowSession.wallpaperOffsetsComplete(asBinder()); 4936 } catch (RemoteException e) { 4937 } 4938 } 4939 } 4940 dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras, boolean sync)4941 public void dispatchWallpaperCommand(String action, int x, int y, 4942 int z, Bundle extras, boolean sync) { 4943 if (sync) { 4944 try { 4945 mWindowSession.wallpaperCommandComplete(asBinder(), null); 4946 } catch (RemoteException e) { 4947 } 4948 } 4949 } 4950 4951 /* Drag/drop */ dispatchDragEvent(DragEvent event)4952 public void dispatchDragEvent(DragEvent event) { 4953 final ViewRootImpl viewAncestor = mViewAncestor.get(); 4954 if (viewAncestor != null) { 4955 viewAncestor.dispatchDragEvent(event); 4956 } 4957 } 4958 dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue, int localChanges)4959 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, 4960 int localValue, int localChanges) { 4961 final ViewRootImpl viewAncestor = mViewAncestor.get(); 4962 if (viewAncestor != null) { 4963 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility, 4964 localValue, localChanges); 4965 } 4966 } 4967 doneAnimating()4968 public void doneAnimating() { 4969 final ViewRootImpl viewAncestor = mViewAncestor.get(); 4970 if (viewAncestor != null) { 4971 viewAncestor.dispatchDoneAnimating(); 4972 } 4973 } 4974 } 4975 4976 /** 4977 * Maintains state information for a single trackball axis, generating 4978 * discrete (DPAD) movements based on raw trackball motion. 4979 */ 4980 static final class TrackballAxis { 4981 /** 4982 * The maximum amount of acceleration we will apply. 4983 */ 4984 static final float MAX_ACCELERATION = 20; 4985 4986 /** 4987 * The maximum amount of time (in milliseconds) between events in order 4988 * for us to consider the user to be doing fast trackball movements, 4989 * and thus apply an acceleration. 4990 */ 4991 static final long FAST_MOVE_TIME = 150; 4992 4993 /** 4994 * Scaling factor to the time (in milliseconds) between events to how 4995 * much to multiple/divide the current acceleration. When movement 4996 * is < FAST_MOVE_TIME this multiplies the acceleration; when > 4997 * FAST_MOVE_TIME it divides it. 4998 */ 4999 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40); 5000 5001 float position; 5002 float absPosition; 5003 float acceleration = 1; 5004 long lastMoveTime = 0; 5005 int step; 5006 int dir; 5007 int nonAccelMovement; 5008 reset(int _step)5009 void reset(int _step) { 5010 position = 0; 5011 acceleration = 1; 5012 lastMoveTime = 0; 5013 step = _step; 5014 dir = 0; 5015 } 5016 5017 /** 5018 * Add trackball movement into the state. If the direction of movement 5019 * has been reversed, the state is reset before adding the 5020 * movement (so that you don't have to compensate for any previously 5021 * collected movement before see the result of the movement in the 5022 * new direction). 5023 * 5024 * @return Returns the absolute value of the amount of movement 5025 * collected so far. 5026 */ collect(float off, long time, String axis)5027 float collect(float off, long time, String axis) { 5028 long normTime; 5029 if (off > 0) { 5030 normTime = (long)(off * FAST_MOVE_TIME); 5031 if (dir < 0) { 5032 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!"); 5033 position = 0; 5034 step = 0; 5035 acceleration = 1; 5036 lastMoveTime = 0; 5037 } 5038 dir = 1; 5039 } else if (off < 0) { 5040 normTime = (long)((-off) * FAST_MOVE_TIME); 5041 if (dir > 0) { 5042 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!"); 5043 position = 0; 5044 step = 0; 5045 acceleration = 1; 5046 lastMoveTime = 0; 5047 } 5048 dir = -1; 5049 } else { 5050 normTime = 0; 5051 } 5052 5053 // The number of milliseconds between each movement that is 5054 // considered "normal" and will not result in any acceleration 5055 // or deceleration, scaled by the offset we have here. 5056 if (normTime > 0) { 5057 long delta = time - lastMoveTime; 5058 lastMoveTime = time; 5059 float acc = acceleration; 5060 if (delta < normTime) { 5061 // The user is scrolling rapidly, so increase acceleration. 5062 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR; 5063 if (scale > 1) acc *= scale; 5064 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off=" 5065 + off + " normTime=" + normTime + " delta=" + delta 5066 + " scale=" + scale + " acc=" + acc); 5067 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION; 5068 } else { 5069 // The user is scrolling slowly, so decrease acceleration. 5070 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR; 5071 if (scale > 1) acc /= scale; 5072 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off=" 5073 + off + " normTime=" + normTime + " delta=" + delta 5074 + " scale=" + scale + " acc=" + acc); 5075 acceleration = acc > 1 ? acc : 1; 5076 } 5077 } 5078 position += off; 5079 return (absPosition = Math.abs(position)); 5080 } 5081 5082 /** 5083 * Generate the number of discrete movement events appropriate for 5084 * the currently collected trackball movement. 5085 * 5086 * @param precision The minimum movement required to generate the 5087 * first discrete movement. 5088 * 5089 * @return Returns the number of discrete movements, either positive 5090 * or negative, or 0 if there is not enough trackball movement yet 5091 * for a discrete movement. 5092 */ generate(float precision)5093 int generate(float precision) { 5094 int movement = 0; 5095 nonAccelMovement = 0; 5096 do { 5097 final int dir = position >= 0 ? 1 : -1; 5098 switch (step) { 5099 // If we are going to execute the first step, then we want 5100 // to do this as soon as possible instead of waiting for 5101 // a full movement, in order to make things look responsive. 5102 case 0: 5103 if (absPosition < precision) { 5104 return movement; 5105 } 5106 movement += dir; 5107 nonAccelMovement += dir; 5108 step = 1; 5109 break; 5110 // If we have generated the first movement, then we need 5111 // to wait for the second complete trackball motion before 5112 // generating the second discrete movement. 5113 case 1: 5114 if (absPosition < 2) { 5115 return movement; 5116 } 5117 movement += dir; 5118 nonAccelMovement += dir; 5119 position += dir > 0 ? -2 : 2; 5120 absPosition = Math.abs(position); 5121 step = 2; 5122 break; 5123 // After the first two, we generate discrete movements 5124 // consistently with the trackball, applying an acceleration 5125 // if the trackball is moving quickly. This is a simple 5126 // acceleration on top of what we already compute based 5127 // on how quickly the wheel is being turned, to apply 5128 // a longer increasing acceleration to continuous movement 5129 // in one direction. 5130 default: 5131 if (absPosition < 1) { 5132 return movement; 5133 } 5134 movement += dir; 5135 position += dir >= 0 ? -1 : 1; 5136 absPosition = Math.abs(position); 5137 float acc = acceleration; 5138 acc *= 1.1f; 5139 acceleration = acc < MAX_ACCELERATION ? acc : acceleration; 5140 break; 5141 } 5142 } while (true); 5143 } 5144 } 5145 5146 public static final class CalledFromWrongThreadException extends AndroidRuntimeException { 5147 public CalledFromWrongThreadException(String msg) { 5148 super(msg); 5149 } 5150 } 5151 5152 private SurfaceHolder mHolder = new SurfaceHolder() { 5153 // we only need a SurfaceHolder for opengl. it would be nice 5154 // to implement everything else though, especially the callback 5155 // support (opengl doesn't make use of it right now, but eventually 5156 // will). 5157 public Surface getSurface() { 5158 return mSurface; 5159 } 5160 5161 public boolean isCreating() { 5162 return false; 5163 } 5164 5165 public void addCallback(Callback callback) { 5166 } 5167 5168 public void removeCallback(Callback callback) { 5169 } 5170 5171 public void setFixedSize(int width, int height) { 5172 } 5173 5174 public void setSizeFromLayout() { 5175 } 5176 5177 public void setFormat(int format) { 5178 } 5179 5180 public void setType(int type) { 5181 } 5182 5183 public void setKeepScreenOn(boolean screenOn) { 5184 } 5185 5186 public Canvas lockCanvas() { 5187 return null; 5188 } 5189 5190 public Canvas lockCanvas(Rect dirty) { 5191 return null; 5192 } 5193 5194 public void unlockCanvasAndPost(Canvas canvas) { 5195 } 5196 public Rect getSurfaceFrame() { 5197 return null; 5198 } 5199 }; 5200 5201 static RunQueue getRunQueue() { 5202 RunQueue rq = sRunQueues.get(); 5203 if (rq != null) { 5204 return rq; 5205 } 5206 rq = new RunQueue(); 5207 sRunQueues.set(rq); 5208 return rq; 5209 } 5210 5211 /** 5212 * The run queue is used to enqueue pending work from Views when no Handler is 5213 * attached. The work is executed during the next call to performTraversals on 5214 * the thread. 5215 * @hide 5216 */ 5217 static final class RunQueue { 5218 private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>(); 5219 5220 void post(Runnable action) { 5221 postDelayed(action, 0); 5222 } 5223 5224 void postDelayed(Runnable action, long delayMillis) { 5225 HandlerAction handlerAction = new HandlerAction(); 5226 handlerAction.action = action; 5227 handlerAction.delay = delayMillis; 5228 5229 synchronized (mActions) { 5230 mActions.add(handlerAction); 5231 } 5232 } 5233 5234 void removeCallbacks(Runnable action) { 5235 final HandlerAction handlerAction = new HandlerAction(); 5236 handlerAction.action = action; 5237 5238 synchronized (mActions) { 5239 final ArrayList<HandlerAction> actions = mActions; 5240 5241 while (actions.remove(handlerAction)) { 5242 // Keep going 5243 } 5244 } 5245 } 5246 5247 void executeActions(Handler handler) { 5248 synchronized (mActions) { 5249 final ArrayList<HandlerAction> actions = mActions; 5250 final int count = actions.size(); 5251 5252 for (int i = 0; i < count; i++) { 5253 final HandlerAction handlerAction = actions.get(i); 5254 handler.postDelayed(handlerAction.action, handlerAction.delay); 5255 } 5256 5257 actions.clear(); 5258 } 5259 } 5260 5261 private static class HandlerAction { 5262 Runnable action; 5263 long delay; 5264 5265 @Override 5266 public boolean equals(Object o) { 5267 if (this == o) return true; 5268 if (o == null || getClass() != o.getClass()) return false; 5269 5270 HandlerAction that = (HandlerAction) o; 5271 return !(action != null ? !action.equals(that.action) : that.action != null); 5272 5273 } 5274 5275 @Override 5276 public int hashCode() { 5277 int result = action != null ? action.hashCode() : 0; 5278 result = 31 * result + (int) (delay ^ (delay >>> 32)); 5279 return result; 5280 } 5281 } 5282 } 5283 5284 /** 5285 * Class for managing the accessibility interaction connection 5286 * based on the global accessibility state. 5287 */ 5288 final class AccessibilityInteractionConnectionManager 5289 implements AccessibilityStateChangeListener { onAccessibilityStateChanged(boolean enabled)5290 public void onAccessibilityStateChanged(boolean enabled) { 5291 if (enabled) { 5292 ensureConnection(); 5293 if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 5294 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 5295 View focusedView = mView.findFocus(); 5296 if (focusedView != null && focusedView != mView) { 5297 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 5298 } 5299 } 5300 } else { 5301 ensureNoConnection(); 5302 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget(); 5303 } 5304 } 5305 ensureConnection()5306 public void ensureConnection() { 5307 if (mAttachInfo != null) { 5308 final boolean registered = 5309 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED; 5310 if (!registered) { 5311 mAttachInfo.mAccessibilityWindowId = 5312 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow, 5313 new AccessibilityInteractionConnection(ViewRootImpl.this)); 5314 } 5315 } 5316 } 5317 ensureNoConnection()5318 public void ensureNoConnection() { 5319 final boolean registered = 5320 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED; 5321 if (registered) { 5322 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED; 5323 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow); 5324 } 5325 } 5326 } 5327 5328 /** 5329 * This class is an interface this ViewAncestor provides to the 5330 * AccessibilityManagerService to the latter can interact with 5331 * the view hierarchy in this ViewAncestor. 5332 */ 5333 static final class AccessibilityInteractionConnection 5334 extends IAccessibilityInteractionConnection.Stub { 5335 private final WeakReference<ViewRootImpl> mViewRootImpl; 5336 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl)5337 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) { 5338 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl); 5339 } 5340 5341 @Override findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)5342 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, 5343 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, 5344 int interrogatingPid, long interrogatingTid) { 5345 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 5346 if (viewRootImpl != null && viewRootImpl.mView != null) { 5347 viewRootImpl.getAccessibilityInteractionController() 5348 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId, 5349 interactionId, callback, flags, interrogatingPid, interrogatingTid); 5350 } else { 5351 // We cannot make the call and notify the caller so it does not wait. 5352 try { 5353 callback.setFindAccessibilityNodeInfosResult(null, interactionId); 5354 } catch (RemoteException re) { 5355 /* best effort - ignore */ 5356 } 5357 } 5358 } 5359 5360 @Override performAccessibilityAction(long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid, long interrogatingTid)5361 public void performAccessibilityAction(long accessibilityNodeId, int action, 5362 Bundle arguments, int interactionId, 5363 IAccessibilityInteractionConnectionCallback callback, int flags, 5364 int interogatingPid, long interrogatingTid) { 5365 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 5366 if (viewRootImpl != null && viewRootImpl.mView != null) { 5367 viewRootImpl.getAccessibilityInteractionController() 5368 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments, 5369 interactionId, callback, flags, interogatingPid, interrogatingTid); 5370 } else { 5371 // We cannot make the call and notify the caller so it does not wait. 5372 try { 5373 callback.setPerformAccessibilityActionResult(false, interactionId); 5374 } catch (RemoteException re) { 5375 /* best effort - ignore */ 5376 } 5377 } 5378 } 5379 5380 @Override findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)5381 public void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int viewId, 5382 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, 5383 int interrogatingPid, long interrogatingTid) { 5384 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 5385 if (viewRootImpl != null && viewRootImpl.mView != null) { 5386 viewRootImpl.getAccessibilityInteractionController() 5387 .findAccessibilityNodeInfoByViewIdClientThread(accessibilityNodeId, viewId, 5388 interactionId, callback, flags, interrogatingPid, interrogatingTid); 5389 } else { 5390 // We cannot make the call and notify the caller so it does not wait. 5391 try { 5392 callback.setFindAccessibilityNodeInfoResult(null, interactionId); 5393 } catch (RemoteException re) { 5394 /* best effort - ignore */ 5395 } 5396 } 5397 } 5398 5399 @Override findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)5400 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, 5401 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, 5402 int interrogatingPid, long interrogatingTid) { 5403 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 5404 if (viewRootImpl != null && viewRootImpl.mView != null) { 5405 viewRootImpl.getAccessibilityInteractionController() 5406 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text, 5407 interactionId, callback, flags, interrogatingPid, interrogatingTid); 5408 } else { 5409 // We cannot make the call and notify the caller so it does not wait. 5410 try { 5411 callback.setFindAccessibilityNodeInfosResult(null, interactionId); 5412 } catch (RemoteException re) { 5413 /* best effort - ignore */ 5414 } 5415 } 5416 } 5417 5418 @Override findFocus(long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)5419 public void findFocus(long accessibilityNodeId, int focusType, int interactionId, 5420 IAccessibilityInteractionConnectionCallback callback, int flags, 5421 int interrogatingPid, long interrogatingTid) { 5422 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 5423 if (viewRootImpl != null && viewRootImpl.mView != null) { 5424 viewRootImpl.getAccessibilityInteractionController() 5425 .findFocusClientThread(accessibilityNodeId, focusType, interactionId, callback, 5426 flags, interrogatingPid, interrogatingTid); 5427 } else { 5428 // We cannot make the call and notify the caller so it does not wait. 5429 try { 5430 callback.setFindAccessibilityNodeInfoResult(null, interactionId); 5431 } catch (RemoteException re) { 5432 /* best effort - ignore */ 5433 } 5434 } 5435 } 5436 5437 @Override focusSearch(long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)5438 public void focusSearch(long accessibilityNodeId, int direction, int interactionId, 5439 IAccessibilityInteractionConnectionCallback callback, int flags, 5440 int interrogatingPid, long interrogatingTid) { 5441 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 5442 if (viewRootImpl != null && viewRootImpl.mView != null) { 5443 viewRootImpl.getAccessibilityInteractionController() 5444 .focusSearchClientThread(accessibilityNodeId, direction, interactionId, 5445 callback, flags, interrogatingPid, interrogatingTid); 5446 } else { 5447 // We cannot make the call and notify the caller so it does not wait. 5448 try { 5449 callback.setFindAccessibilityNodeInfoResult(null, interactionId); 5450 } catch (RemoteException re) { 5451 /* best effort - ignore */ 5452 } 5453 } 5454 } 5455 } 5456 5457 private class SendWindowContentChangedAccessibilityEvent implements Runnable { 5458 public View mSource; 5459 run()5460 public void run() { 5461 if (mSource != null) { 5462 mSource.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 5463 mSource.resetAccessibilityStateChanged(); 5464 mSource = null; 5465 } 5466 } 5467 } 5468 } 5469