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