From c6cc0f8c19d9eccf408a443fa2bf668af261dcd0 Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Tue, 12 Apr 2011 11:53:13 -0700 Subject: Rename ViewRoot to ViewAncestor. ViewRoot is about to be a new public class for poking at ViewAncestor. Change-Id: Ie95d707c6d8bbb48f78d093d7b2667851812a7d5 --- core/java/android/view/ViewRoot.java | 4046 ---------------------------------- 1 file changed, 4046 deletions(-) delete mode 100644 core/java/android/view/ViewRoot.java (limited to 'core/java/android/view/ViewRoot.java') diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java deleted file mode 100644 index f02dabac340d..000000000000 --- a/core/java/android/view/ViewRoot.java +++ /dev/null @@ -1,4046 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.view; - -import android.Manifest; -import android.app.ActivityManagerNative; -import android.content.ClipDescription; -import android.content.ComponentCallbacks; -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.CompatibilityInfo; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.Point; -import android.graphics.PointF; -import android.graphics.PorterDuff; -import android.graphics.Rect; -import android.graphics.Region; -import android.media.AudioManager; -import android.os.Binder; -import android.os.Bundle; -import android.os.Debug; -import android.os.Handler; -import android.os.LatencyTimer; -import android.os.Looper; -import android.os.Message; -import android.os.ParcelFileDescriptor; -import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.util.AndroidRuntimeException; -import android.util.DisplayMetrics; -import android.util.EventLog; -import android.util.Log; -import android.util.Slog; -import android.util.SparseArray; -import android.util.TypedValue; -import android.view.View.MeasureSpec; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; -import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.Interpolator; -import android.view.inputmethod.InputConnection; -import android.view.inputmethod.InputMethodManager; -import android.widget.Scroller; -import com.android.internal.policy.PolicyManager; -import com.android.internal.view.BaseSurfaceHolder; -import com.android.internal.view.IInputMethodCallback; -import com.android.internal.view.IInputMethodSession; -import com.android.internal.view.RootViewSurfaceTaker; - -import java.io.IOException; -import java.io.OutputStream; -import java.lang.ref.WeakReference; -import java.util.ArrayList; - -/** - * The top of a view hierarchy, implementing the needed protocol between View - * and the WindowManager. This is for the most part an internal implementation - * detail of {@link WindowManagerImpl}. - * - * {@hide} - */ -@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"}) -public final class ViewRoot extends Handler implements ViewParent, - View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { - private static final String TAG = "ViewRoot"; - private static final boolean DBG = false; - private static final boolean SHOW_FPS = false; - private static final boolean LOCAL_LOGV = false; - /** @noinspection PointlessBooleanExpression*/ - private static final boolean DEBUG_DRAW = false || LOCAL_LOGV; - private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV; - private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV; - private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV; - private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV; - private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV; - private static final boolean DEBUG_IMF = false || LOCAL_LOGV; - private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV; - private static final boolean WATCH_POINTER = false; - - private static final boolean MEASURE_LATENCY = false; - private static LatencyTimer lt; - - /** - * Maximum time we allow the user to roll the trackball enough to generate - * a key event, before resetting the counters. - */ - static final int MAX_TRACKBALL_DELAY = 250; - - static IWindowSession sWindowSession; - - static final Object mStaticInit = new Object(); - static boolean mInitialized = false; - - static final ThreadLocal sRunQueues = new ThreadLocal(); - - static final ArrayList sFirstDrawHandlers = new ArrayList(); - static boolean sFirstDrawComplete = false; - - static final ArrayList sConfigCallbacks - = new ArrayList(); - - private static int sDrawTime; - - long mLastTrackballTime = 0; - final TrackballAxis mTrackballAxisX = new TrackballAxis(); - final TrackballAxis mTrackballAxisY = new TrackballAxis(); - - int mLastJoystickXDirection; - int mLastJoystickYDirection; - int mLastJoystickXKeyCode; - int mLastJoystickYKeyCode; - - final int[] mTmpLocation = new int[2]; - - final TypedValue mTmpValue = new TypedValue(); - - final InputMethodCallback mInputMethodCallback; - final SparseArray mPendingEvents = new SparseArray(); - int mPendingEventSeq = 0; - - final Thread mThread; - - final WindowLeaked mLocation; - - final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams(); - - final W mWindow; - - View mView; - View mFocusedView; - View mRealFocusedView; // this is not set to null in touch mode - int mViewVisibility; - boolean mAppVisible = true; - - // Set to true if the owner of this window is in the stopped state, - // so the window should no longer be active. - boolean mStopped = false; - - SurfaceHolder.Callback2 mSurfaceHolderCallback; - BaseSurfaceHolder mSurfaceHolder; - boolean mIsCreating; - boolean mDrawingAllowed; - - final Region mTransparentRegion; - final Region mPreviousTransparentRegion; - - int mWidth; - int mHeight; - Rect mDirty; - final Rect mCurrentDirty = new Rect(); - final Rect mPreviousDirty = new Rect(); - boolean mIsAnimating; - - CompatibilityInfo.Translator mTranslator; - - final View.AttachInfo mAttachInfo; - InputChannel mInputChannel; - InputQueue.Callback mInputQueueCallback; - InputQueue mInputQueue; - FallbackEventHandler mFallbackEventHandler; - - final Rect mTempRect; // used in the transaction to not thrash the heap. - final Rect mVisRect; // used to retrieve visible rect of focused view. - - boolean mTraversalScheduled; - long mLastTraversalFinishedTimeNanos; - long mLastDrawDurationNanos; - boolean mWillDrawSoon; - boolean mLayoutRequested; - boolean mFirst; - boolean mReportNextDraw; - boolean mFullRedrawNeeded; - boolean mNewSurfaceNeeded; - boolean mHasHadWindowFocus; - boolean mLastWasImTarget; - - boolean mWindowAttributesChanged = false; - - // These can be accessed by any thread, must be protected with a lock. - // Surface can never be reassigned or cleared (use Surface.clear()). - private final Surface mSurface = new Surface(); - - boolean mAdded; - boolean mAddedTouchMode; - - /*package*/ int mAddNesting; - - // These are accessed by multiple threads. - final Rect mWinFrame; // frame given by window manager. - - final Rect mPendingVisibleInsets = new Rect(); - final Rect mPendingContentInsets = new Rect(); - final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets - = new ViewTreeObserver.InternalInsetsInfo(); - - final Configuration mLastConfiguration = new Configuration(); - final Configuration mPendingConfiguration = new Configuration(); - - class ResizedInfo { - Rect coveredInsets; - Rect visibleInsets; - Configuration newConfig; - } - - boolean mScrollMayChange; - int mSoftInputMode; - View mLastScrolledFocus; - int mScrollY; - int mCurScrollY; - Scroller mScroller; - Bitmap mResizeBitmap; - long mResizeBitmapStartTime; - int mResizeBitmapDuration; - static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator(); - - final ViewConfiguration mViewConfiguration; - - /* Drag/drop */ - ClipDescription mDragDescription; - View mCurrentDragView; - volatile Object mLocalDragState; - final PointF mDragPoint = new PointF(); - final PointF mLastTouchPoint = new PointF(); - - /** - * see {@link #playSoundEffect(int)} - */ - AudioManager mAudioManager; - - private final int mDensity; - - /** - * Consistency verifier for debugging purposes. - */ - protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = - InputEventConsistencyVerifier.isInstrumentationEnabled() ? - new InputEventConsistencyVerifier(this, 0) : null; - - public static IWindowSession getWindowSession(Looper mainLooper) { - synchronized (mStaticInit) { - if (!mInitialized) { - try { - InputMethodManager imm = InputMethodManager.getInstance(mainLooper); - sWindowSession = Display.getWindowManager().openSession( - imm.getClient(), imm.getInputContext()); - mInitialized = true; - } catch (RemoteException e) { - } - } - return sWindowSession; - } - } - - public ViewRoot(Context context) { - super(); - - if (MEASURE_LATENCY) { - if (lt == null) { - lt = new LatencyTimer(100, 1000); - } - } - - // Initialize the statics when this class is first instantiated. This is - // done here instead of in the static block because Zygote does not - // allow the spawning of threads. - getWindowSession(context.getMainLooper()); - - mThread = Thread.currentThread(); - mLocation = new WindowLeaked(null); - mLocation.fillInStackTrace(); - mWidth = -1; - mHeight = -1; - mDirty = new Rect(); - mTempRect = new Rect(); - mVisRect = new Rect(); - mWinFrame = new Rect(); - mWindow = new W(this); - mInputMethodCallback = new InputMethodCallback(this); - mViewVisibility = View.GONE; - mTransparentRegion = new Region(); - mPreviousTransparentRegion = new Region(); - mFirst = true; // true for the first time the view is added - mAdded = false; - mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this); - mViewConfiguration = ViewConfiguration.get(context); - mDensity = context.getResources().getDisplayMetrics().densityDpi; - mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context); - } - - public static void addFirstDrawHandler(Runnable callback) { - synchronized (sFirstDrawHandlers) { - if (!sFirstDrawComplete) { - sFirstDrawHandlers.add(callback); - } - } - } - - public static void addConfigCallback(ComponentCallbacks callback) { - synchronized (sConfigCallbacks) { - sConfigCallbacks.add(callback); - } - } - - // FIXME for perf testing only - private boolean mProfile = false; - - /** - * Call this to profile the next traversal call. - * FIXME for perf testing only. Remove eventually - */ - public void profile() { - mProfile = true; - } - - /** - * Indicates whether we are in touch mode. Calling this method triggers an IPC - * call and should be avoided whenever possible. - * - * @return True, if the device is in touch mode, false otherwise. - * - * @hide - */ - static boolean isInTouchMode() { - if (mInitialized) { - try { - return sWindowSession.getInTouchMode(); - } catch (RemoteException e) { - } - } - return false; - } - - /** - * We have one child - */ - public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { - synchronized (this) { - if (mView == null) { - mView = view; - mFallbackEventHandler.setView(view); - mWindowAttributes.copyFrom(attrs); - attrs = mWindowAttributes; - - if (view instanceof RootViewSurfaceTaker) { - mSurfaceHolderCallback = - ((RootViewSurfaceTaker)view).willYouTakeTheSurface(); - if (mSurfaceHolderCallback != null) { - mSurfaceHolder = new TakenSurfaceHolder(); - mSurfaceHolder.setFormat(PixelFormat.UNKNOWN); - } - } - - // If the application owns the surface, don't enable hardware acceleration - if (mSurfaceHolder == null) { - enableHardwareAcceleration(attrs); - } - - Resources resources = mView.getContext().getResources(); - CompatibilityInfo compatibilityInfo = resources.getCompatibilityInfo(); - mTranslator = compatibilityInfo.getTranslator(); - - if (mTranslator != null || !compatibilityInfo.supportsScreen()) { - mSurface.setCompatibleDisplayMetrics(resources.getDisplayMetrics(), - mTranslator); - } - - boolean restore = false; - if (mTranslator != null) { - restore = true; - attrs.backup(); - mTranslator.translateWindowLayout(attrs); - } - if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs); - - if (!compatibilityInfo.supportsScreen()) { - attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; - } - - mSoftInputMode = attrs.softInputMode; - mWindowAttributesChanged = true; - mAttachInfo.mRootView = view; - mAttachInfo.mScalingRequired = mTranslator != null; - mAttachInfo.mApplicationScale = - mTranslator == null ? 1.0f : mTranslator.applicationScale; - if (panelParentView != null) { - mAttachInfo.mPanelParentWindowToken - = panelParentView.getApplicationWindowToken(); - } - mAdded = true; - int res; /* = WindowManagerImpl.ADD_OKAY; */ - - // Schedule the first layout -before- adding to the window - // manager, to make sure we do the relayout before receiving - // any other events from the system. - requestLayout(); - mInputChannel = new InputChannel(); - try { - res = sWindowSession.add(mWindow, mWindowAttributes, - getHostVisibility(), mAttachInfo.mContentInsets, - mInputChannel); - } catch (RemoteException e) { - mAdded = false; - mView = null; - mAttachInfo.mRootView = null; - mInputChannel = null; - mFallbackEventHandler.setView(null); - unscheduleTraversals(); - throw new RuntimeException("Adding window failed", e); - } finally { - if (restore) { - attrs.restore(); - } - } - - if (mTranslator != null) { - mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets); - } - mPendingContentInsets.set(mAttachInfo.mContentInsets); - mPendingVisibleInsets.set(0, 0, 0, 0); - if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow); - if (res < WindowManagerImpl.ADD_OKAY) { - mView = null; - mAttachInfo.mRootView = null; - mAdded = false; - mFallbackEventHandler.setView(null); - unscheduleTraversals(); - switch (res) { - case WindowManagerImpl.ADD_BAD_APP_TOKEN: - case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN: - throw new WindowManagerImpl.BadTokenException( - "Unable to add window -- token " + attrs.token - + " is not valid; is your activity running?"); - case WindowManagerImpl.ADD_NOT_APP_TOKEN: - throw new WindowManagerImpl.BadTokenException( - "Unable to add window -- token " + attrs.token - + " is not for an application"); - case WindowManagerImpl.ADD_APP_EXITING: - throw new WindowManagerImpl.BadTokenException( - "Unable to add window -- app for token " + attrs.token - + " is exiting"); - case WindowManagerImpl.ADD_DUPLICATE_ADD: - throw new WindowManagerImpl.BadTokenException( - "Unable to add window -- window " + mWindow - + " has already been added"); - case WindowManagerImpl.ADD_STARTING_NOT_NEEDED: - // Silently ignore -- we would have just removed it - // right away, anyway. - return; - case WindowManagerImpl.ADD_MULTIPLE_SINGLETON: - throw new WindowManagerImpl.BadTokenException( - "Unable to add window " + mWindow + - " -- another window of this type already exists"); - case WindowManagerImpl.ADD_PERMISSION_DENIED: - throw new WindowManagerImpl.BadTokenException( - "Unable to add window " + mWindow + - " -- permission denied for this window type"); - } - throw new RuntimeException( - "Unable to add window -- unknown error code " + res); - } - - if (view instanceof RootViewSurfaceTaker) { - mInputQueueCallback = - ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue(); - } - if (mInputQueueCallback != null) { - mInputQueue = new InputQueue(mInputChannel); - mInputQueueCallback.onInputQueueCreated(mInputQueue); - } else { - InputQueue.registerInputChannel(mInputChannel, mInputHandler, - Looper.myQueue()); - } - - view.assignParent(this); - mAddedTouchMode = (res&WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE) != 0; - mAppVisible = (res&WindowManagerImpl.ADD_FLAG_APP_VISIBLE) != 0; - } - } - } - - private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) { - mAttachInfo.mHardwareAccelerated = false; - mAttachInfo.mHardwareAccelerationRequested = false; - - // Try to enable hardware acceleration if requested - final boolean hardwareAccelerated = - (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; - - if (hardwareAccelerated) { - if (!HardwareRenderer.isAvailable()) { - mAttachInfo.mHardwareAccelerationRequested = true; - return; - } - - // Only enable hardware acceleration if we are not in the system process - // The window manager creates ViewRoots to display animated preview windows - // of launching apps and we don't want those to be hardware accelerated - - final boolean systemHwAccelerated = - (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED_SYSTEM) != 0; - - if (!HardwareRenderer.sRendererDisabled || systemHwAccelerated) { - // Don't enable hardware acceleration when we're not on the main thread - if (!systemHwAccelerated && Looper.getMainLooper() != Looper.myLooper()) { - Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware " - + "acceleration outside of the main thread, aborting"); - return; - } - - final boolean translucent = attrs.format != PixelFormat.OPAQUE; - if (mAttachInfo.mHardwareRenderer != null) { - mAttachInfo.mHardwareRenderer.destroy(true); - } - mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent); - mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested - = mAttachInfo.mHardwareRenderer != null; - } - } - } - - public View getView() { - return mView; - } - - final WindowLeaked getLocation() { - return mLocation; - } - - void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) { - synchronized (this) { - int oldSoftInputMode = mWindowAttributes.softInputMode; - // preserve compatible window flag if exists. - int compatibleWindowFlag = - mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; - mWindowAttributes.copyFrom(attrs); - mWindowAttributes.flags |= compatibleWindowFlag; - - if (newView) { - mSoftInputMode = attrs.softInputMode; - requestLayout(); - } - // Don't lose the mode we last auto-computed. - if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) - == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { - mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode - & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) - | (oldSoftInputMode - & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST); - } - mWindowAttributesChanged = true; - scheduleTraversals(); - } - } - - void handleAppVisibility(boolean visible) { - if (mAppVisible != visible) { - mAppVisible = visible; - scheduleTraversals(); - } - } - - void handleGetNewSurface() { - mNewSurfaceNeeded = true; - mFullRedrawNeeded = true; - scheduleTraversals(); - } - - /** - * {@inheritDoc} - */ - public void requestLayout() { - checkThread(); - mLayoutRequested = true; - scheduleTraversals(); - } - - /** - * {@inheritDoc} - */ - public boolean isLayoutRequested() { - return mLayoutRequested; - } - - public void invalidateChild(View child, Rect dirty) { - checkThread(); - if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty); - if (dirty == null) { - // Fast invalidation for GL-enabled applications; GL must redraw everything - invalidate(); - return; - } - if (mCurScrollY != 0 || mTranslator != null) { - mTempRect.set(dirty); - dirty = mTempRect; - if (mCurScrollY != 0) { - dirty.offset(0, -mCurScrollY); - } - if (mTranslator != null) { - mTranslator.translateRectInAppWindowToScreen(dirty); - } - if (mAttachInfo.mScalingRequired) { - dirty.inset(-1, -1); - } - } - if (!mDirty.isEmpty() && !mDirty.contains(dirty)) { - mAttachInfo.mIgnoreDirtyState = true; - } - mDirty.union(dirty); - if (!mWillDrawSoon) { - scheduleTraversals(); - } - } - - void invalidate() { - mDirty.set(0, 0, mWidth, mHeight); - scheduleTraversals(); - } - - void setStopped(boolean stopped) { - if (mStopped != stopped) { - mStopped = stopped; - if (!stopped) { - scheduleTraversals(); - } - } - } - - public ViewParent getParent() { - return null; - } - - public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) { - invalidateChild(null, dirty); - return null; - } - - public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) { - if (child != mView) { - throw new RuntimeException("child is not mine, honest!"); - } - // Note: don't apply scroll offset, because we want to know its - // visibility in the virtual canvas being given to the view hierarchy. - return r.intersect(0, 0, mWidth, mHeight); - } - - public void bringChildToFront(View child) { - } - - public void scheduleTraversals() { - if (!mTraversalScheduled) { - mTraversalScheduled = true; - - if (ViewDebug.DEBUG_LATENCY && mLastTraversalFinishedTimeNanos != 0) { - final long now = System.nanoTime(); - Log.d(TAG, "Latency: Scheduled traversal, it has been " - + ((now - mLastTraversalFinishedTimeNanos) * 0.000001f) - + "ms since the last traversal finished."); - } - - sendEmptyMessage(DO_TRAVERSAL); - } - } - - public void unscheduleTraversals() { - if (mTraversalScheduled) { - mTraversalScheduled = false; - removeMessages(DO_TRAVERSAL); - } - } - - int getHostVisibility() { - return mAppVisible ? mView.getVisibility() : View.GONE; - } - - void disposeResizeBitmap() { - if (mResizeBitmap != null) { - mResizeBitmap.recycle(); - mResizeBitmap = null; - } - } - - private void performTraversals() { - // cache mView since it is used so much below... - final View host = mView; - - if (DBG) { - System.out.println("======================================"); - System.out.println("performTraversals"); - host.debug(); - } - - if (host == null || !mAdded) - return; - - mTraversalScheduled = false; - mWillDrawSoon = true; - boolean windowSizeMayChange = false; - boolean fullRedrawNeeded = mFullRedrawNeeded; - boolean newSurface = false; - boolean surfaceChanged = false; - WindowManager.LayoutParams lp = mWindowAttributes; - - int desiredWindowWidth; - int desiredWindowHeight; - int childWidthMeasureSpec; - int childHeightMeasureSpec; - - final View.AttachInfo attachInfo = mAttachInfo; - - final int viewVisibility = getHostVisibility(); - boolean viewVisibilityChanged = mViewVisibility != viewVisibility - || mNewSurfaceNeeded; - - WindowManager.LayoutParams params = null; - if (mWindowAttributesChanged) { - mWindowAttributesChanged = false; - surfaceChanged = true; - params = lp; - } - Rect frame = mWinFrame; - if (mFirst) { - fullRedrawNeeded = true; - mLayoutRequested = true; - - DisplayMetrics packageMetrics = - mView.getContext().getResources().getDisplayMetrics(); - desiredWindowWidth = packageMetrics.widthPixels; - desiredWindowHeight = packageMetrics.heightPixels; - - // For the very first time, tell the view hierarchy that it - // is attached to the window. Note that at this point the surface - // object is not initialized to its backing store, but soon it - // will be (assuming the window is visible). - attachInfo.mSurface = mSurface; - // We used to use the following condition to choose 32 bits drawing caches: - // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888 - // However, windows are now always 32 bits by default, so choose 32 bits - attachInfo.mUse32BitDrawingCache = true; - attachInfo.mHasWindowFocus = false; - attachInfo.mWindowVisibility = viewVisibility; - attachInfo.mRecomputeGlobalAttributes = false; - attachInfo.mKeepScreenOn = false; - attachInfo.mSystemUiVisibility = 0; - viewVisibilityChanged = false; - mLastConfiguration.setTo(host.getResources().getConfiguration()); - host.dispatchAttachedToWindow(attachInfo, 0); - //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn); - - } else { - desiredWindowWidth = frame.width(); - desiredWindowHeight = frame.height(); - if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) { - if (DEBUG_ORIENTATION) Log.v(TAG, - "View " + host + " resized to: " + frame); - fullRedrawNeeded = true; - mLayoutRequested = true; - windowSizeMayChange = true; - } - } - - if (viewVisibilityChanged) { - attachInfo.mWindowVisibility = viewVisibility; - host.dispatchWindowVisibilityChanged(viewVisibility); - if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) { - if (mAttachInfo.mHardwareRenderer != null) { - mAttachInfo.mHardwareRenderer.destroy(false); - } - } - if (viewVisibility == View.GONE) { - // After making a window gone, we will count it as being - // shown for the first time the next time it gets focus. - mHasHadWindowFocus = false; - } - } - - boolean insetsChanged = false; - - if (mLayoutRequested && !mStopped) { - // Execute enqueued actions on every layout in case a view that was detached - // enqueued an action after being detached - getRunQueue().executeActions(attachInfo.mHandler); - - final Resources res = mView.getContext().getResources(); - - if (mFirst) { - host.fitSystemWindows(mAttachInfo.mContentInsets); - // make sure touch mode code executes by setting cached value - // to opposite of the added touch mode. - mAttachInfo.mInTouchMode = !mAddedTouchMode; - ensureTouchModeLocally(mAddedTouchMode); - } else { - if (!mAttachInfo.mContentInsets.equals(mPendingContentInsets)) { - if (mWidth > 0 && mHeight > 0 && - mSurface != null && mSurface.isValid() && - !mAttachInfo.mTurnOffWindowResizeAnim && - mAttachInfo.mHardwareRenderer != null && - mAttachInfo.mHardwareRenderer.isEnabled() && - lp != null && !PixelFormat.formatHasAlpha(lp.format)) { - - disposeResizeBitmap(); - - boolean completed = false; - try { - mResizeBitmap = Bitmap.createBitmap(mWidth, mHeight, - Bitmap.Config.ARGB_8888); - mResizeBitmap.setHasAlpha(false); - Canvas canvas = new Canvas(mResizeBitmap); - canvas.drawColor(0xff000000, PorterDuff.Mode.SRC); - int yoff; - final boolean scrolling = mScroller != null - && mScroller.computeScrollOffset(); - if (scrolling) { - yoff = mScroller.getCurrY(); - mScroller.abortAnimation(); - } else { - yoff = mScrollY; - } - canvas.translate(0, -yoff); - if (mTranslator != null) { - mTranslator.translateCanvas(canvas); - } - canvas.setScreenDensity(mAttachInfo.mScalingRequired - ? DisplayMetrics.DENSITY_DEVICE : 0); - mView.draw(canvas); - mResizeBitmapStartTime = SystemClock.uptimeMillis(); - mResizeBitmapDuration = mView.getResources().getInteger( - com.android.internal.R.integer.config_mediumAnimTime); - completed = true; - } catch (OutOfMemoryError e) { - Log.w(TAG, "Not enough memory for content change anim buffer", e); - } finally { - if (!completed) { - mResizeBitmap = null; - } - } - } - mAttachInfo.mContentInsets.set(mPendingContentInsets); - host.fitSystemWindows(mAttachInfo.mContentInsets); - insetsChanged = true; - if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: " - + mAttachInfo.mContentInsets); - } - if (!mAttachInfo.mVisibleInsets.equals(mPendingVisibleInsets)) { - mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets); - if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: " - + mAttachInfo.mVisibleInsets); - } - if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT - || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { - windowSizeMayChange = true; - - DisplayMetrics packageMetrics = res.getDisplayMetrics(); - desiredWindowWidth = packageMetrics.widthPixels; - desiredWindowHeight = packageMetrics.heightPixels; - } - } - - // Ask host how big it wants to be - if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG, - "Measuring " + host + " in display " + desiredWindowWidth - + "x" + desiredWindowHeight + "..."); - - boolean goodMeasure = false; - if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT - || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { - // On large screens, we don't want to allow dialogs to just - // stretch to fill the entire width of the screen to display - // one line of text. First try doing the layout at a smaller - // size to see if it will fit. - final DisplayMetrics packageMetrics = res.getDisplayMetrics(); - res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true); - int baseSize = 0; - if (mTmpValue.type == TypedValue.TYPE_DIMENSION) { - baseSize = (int)mTmpValue.getDimension(packageMetrics); - } - if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize); - if (baseSize != 0 && desiredWindowWidth > baseSize) { - childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width); - childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); - host.measure(childWidthMeasureSpec, childHeightMeasureSpec); - if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured (" - + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")"); - if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) { - goodMeasure = true; - } else { - // Didn't fit in that size... try expanding a bit. - baseSize = (baseSize+desiredWindowWidth)/2; - if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize=" - + baseSize); - childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width); - host.measure(childWidthMeasureSpec, childHeightMeasureSpec); - if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured (" - + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")"); - if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) { - if (DEBUG_DIALOG) Log.v(TAG, "Good!"); - goodMeasure = true; - } - } - } - } - - if (!goodMeasure) { - childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width); - childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); - host.measure(childWidthMeasureSpec, childHeightMeasureSpec); - if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) { - windowSizeMayChange = true; - } - } - - if (DBG) { - System.out.println("======================================"); - System.out.println("performTraversals -- after measure"); - host.debug(); - } - } - - if (attachInfo.mRecomputeGlobalAttributes && host.mAttachInfo != null) { - //Log.i(TAG, "Computing view hierarchy attributes!"); - attachInfo.mRecomputeGlobalAttributes = false; - boolean oldScreenOn = attachInfo.mKeepScreenOn; - int oldVis = attachInfo.mSystemUiVisibility; - attachInfo.mKeepScreenOn = false; - attachInfo.mSystemUiVisibility = 0; - attachInfo.mHasSystemUiListeners = false; - host.dispatchCollectViewAttributes(0); - if (attachInfo.mKeepScreenOn != oldScreenOn - || attachInfo.mSystemUiVisibility != oldVis - || attachInfo.mHasSystemUiListeners) { - params = lp; - } - } - - if (mFirst || attachInfo.mViewVisibilityChanged) { - attachInfo.mViewVisibilityChanged = false; - int resizeMode = mSoftInputMode & - WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; - // If we are in auto resize mode, then we need to determine - // what mode to use now. - if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { - final int N = attachInfo.mScrollContainers.size(); - for (int i=0; i ci.left || vi.top > ci.top - || vi.right > ci.right || vi.bottom > ci.bottom) { - // We'll assume that we aren't going to change the scroll - // offset, since we want to avoid that unless it is actually - // going to make the focus visible... otherwise we scroll - // all over the place. - scrollY = mScrollY; - // We can be called for two different situations: during a draw, - // to update the scroll position if the focus has changed (in which - // case 'rectangle' is null), or in response to a - // requestChildRectangleOnScreen() call (in which case 'rectangle' - // is non-null and we just want to scroll to whatever that - // rectangle is). - View focus = mRealFocusedView; - - // When in touch mode, focus points to the previously focused view, - // which may have been removed from the view hierarchy. The following - // line checks whether the view is still in our hierarchy. - if (focus == null || focus.mAttachInfo != mAttachInfo) { - mRealFocusedView = null; - return false; - } - - if (focus != mLastScrolledFocus) { - // If the focus has changed, then ignore any requests to scroll - // to a rectangle; first we want to make sure the entire focus - // view is visible. - rectangle = null; - } - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus - + " rectangle=" + rectangle + " ci=" + ci - + " vi=" + vi); - if (focus == mLastScrolledFocus && !mScrollMayChange - && rectangle == null) { - // Optimization: if the focus hasn't changed since last - // time, and no layout has happened, then just leave things - // as they are. - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y=" - + mScrollY + " vi=" + vi.toShortString()); - } else if (focus != null) { - // We need to determine if the currently focused view is - // within the visible part of the window and, if not, apply - // a pan so it can be seen. - mLastScrolledFocus = focus; - mScrollMayChange = false; - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?"); - // Try to find the rectangle from the focus view. - if (focus.getGlobalVisibleRect(mVisRect, null)) { - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w=" - + mView.getWidth() + " h=" + mView.getHeight() - + " ci=" + ci.toShortString() - + " vi=" + vi.toShortString()); - if (rectangle == null) { - focus.getFocusedRect(mTempRect); - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus - + ": focusRect=" + mTempRect.toShortString()); - if (mView instanceof ViewGroup) { - ((ViewGroup) mView).offsetDescendantRectToMyCoords( - focus, mTempRect); - } - if (DEBUG_INPUT_RESIZE) Log.v(TAG, - "Focus in window: focusRect=" - + mTempRect.toShortString() - + " visRect=" + mVisRect.toShortString()); - } else { - mTempRect.set(rectangle); - if (DEBUG_INPUT_RESIZE) Log.v(TAG, - "Request scroll to rect: " - + mTempRect.toShortString() - + " visRect=" + mVisRect.toShortString()); - } - if (mTempRect.intersect(mVisRect)) { - if (DEBUG_INPUT_RESIZE) Log.v(TAG, - "Focus window visible rect: " - + mTempRect.toShortString()); - if (mTempRect.height() > - (mView.getHeight()-vi.top-vi.bottom)) { - // If the focus simply is not going to fit, then - // best is probably just to leave things as-is. - if (DEBUG_INPUT_RESIZE) Log.v(TAG, - "Too tall; leaving scrollY=" + scrollY); - } else if ((mTempRect.top-scrollY) < vi.top) { - scrollY -= vi.top - (mTempRect.top-scrollY); - if (DEBUG_INPUT_RESIZE) Log.v(TAG, - "Top covered; scrollY=" + scrollY); - } else if ((mTempRect.bottom-scrollY) - > (mView.getHeight()-vi.bottom)) { - scrollY += (mTempRect.bottom-scrollY) - - (mView.getHeight()-vi.bottom); - if (DEBUG_INPUT_RESIZE) Log.v(TAG, - "Bottom covered; scrollY=" + scrollY); - } - handled = true; - } - } - } - } - - if (scrollY != mScrollY) { - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old=" - + mScrollY + " , new=" + scrollY); - if (!immediate && mResizeBitmap == null) { - if (mScroller == null) { - mScroller = new Scroller(mView.getContext()); - } - mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY); - } else if (mScroller != null) { - mScroller.abortAnimation(); - } - mScrollY = scrollY; - } - - return handled; - } - - public void requestChildFocus(View child, View focused) { - checkThread(); - if (mFocusedView != focused) { - mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused); - scheduleTraversals(); - } - mFocusedView = mRealFocusedView = focused; - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Request child focus: focus now " - + mFocusedView); - } - - public void clearChildFocus(View child) { - checkThread(); - - View oldFocus = mFocusedView; - - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Clearing child focus"); - mFocusedView = mRealFocusedView = null; - if (mView != null && !mView.hasFocus()) { - // If a view gets the focus, the listener will be invoked from requestChildFocus() - if (!mView.requestFocus(View.FOCUS_FORWARD)) { - mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); - } - } else if (oldFocus != null) { - mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); - } - } - - - public void focusableViewAvailable(View v) { - checkThread(); - - if (mView != null && !mView.hasFocus()) { - v.requestFocus(); - } else { - // the one case where will transfer focus away from the current one - // is if the current view is a view group that prefers to give focus - // to its children first AND the view is a descendant of it. - mFocusedView = mView.findFocus(); - boolean descendantsHaveDibsOnFocus = - (mFocusedView instanceof ViewGroup) && - (((ViewGroup) mFocusedView).getDescendantFocusability() == - ViewGroup.FOCUS_AFTER_DESCENDANTS); - if (descendantsHaveDibsOnFocus && isViewDescendantOf(v, mFocusedView)) { - // If a view gets the focus, the listener will be invoked from requestChildFocus() - v.requestFocus(); - } - } - } - - public void recomputeViewAttributes(View child) { - checkThread(); - if (mView == child) { - mAttachInfo.mRecomputeGlobalAttributes = true; - if (!mWillDrawSoon) { - scheduleTraversals(); - } - } - } - - void dispatchDetachedFromWindow() { - if (mView != null && mView.mAttachInfo != null) { - mView.dispatchDetachedFromWindow(); - } - - mView = null; - mAttachInfo.mRootView = null; - mAttachInfo.mSurface = null; - - destroyHardwareRenderer(); - - mSurface.release(); - - if (mInputChannel != null) { - if (mInputQueueCallback != null) { - mInputQueueCallback.onInputQueueDestroyed(mInputQueue); - mInputQueueCallback = null; - } else { - InputQueue.unregisterInputChannel(mInputChannel); - } - } - - try { - sWindowSession.remove(mWindow); - } catch (RemoteException e) { - } - - // Dispose the input channel after removing the window so the Window Manager - // doesn't interpret the input channel being closed as an abnormal termination. - if (mInputChannel != null) { - mInputChannel.dispose(); - mInputChannel = null; - } - } - - void updateConfiguration(Configuration config, boolean force) { - if (DEBUG_CONFIGURATION) Log.v(TAG, - "Applying new config to window " - + mWindowAttributes.getTitle() - + ": " + config); - synchronized (sConfigCallbacks) { - for (int i=sConfigCallbacks.size()-1; i>=0; i--) { - sConfigCallbacks.get(i).onConfigurationChanged(config); - } - } - if (mView != null) { - // At this point the resources have been updated to - // have the most recent config, whatever that is. Use - // the on in them which may be newer. - if (mView != null) { - config = mView.getResources().getConfiguration(); - } - if (force || mLastConfiguration.diff(config) != 0) { - mLastConfiguration.setTo(config); - mView.dispatchConfigurationChanged(config); - } - } - } - - /** - * Return true if child is an ancestor of parent, (or equal to the parent). - */ - private static boolean isViewDescendantOf(View child, View parent) { - if (child == parent) { - return true; - } - - final ViewParent theParent = child.getParent(); - return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent); - } - - private static void forceLayout(View view) { - view.forceLayout(); - if (view instanceof ViewGroup) { - ViewGroup group = (ViewGroup) view; - final int count = group.getChildCount(); - for (int i = 0; i < count; i++) { - forceLayout(group.getChildAt(i)); - } - } - } - - public final static int DO_TRAVERSAL = 1000; - public final static int DIE = 1001; - public final static int RESIZED = 1002; - public final static int RESIZED_REPORT = 1003; - public final static int WINDOW_FOCUS_CHANGED = 1004; - public final static int DISPATCH_KEY = 1005; - public final static int DISPATCH_POINTER = 1006; - public final static int DISPATCH_TRACKBALL = 1007; - public final static int DISPATCH_APP_VISIBILITY = 1008; - public final static int DISPATCH_GET_NEW_SURFACE = 1009; - public final static int FINISHED_EVENT = 1010; - public final static int DISPATCH_KEY_FROM_IME = 1011; - public final static int FINISH_INPUT_CONNECTION = 1012; - public final static int CHECK_FOCUS = 1013; - public final static int CLOSE_SYSTEM_DIALOGS = 1014; - public final static int DISPATCH_DRAG_EVENT = 1015; - public final static int DISPATCH_DRAG_LOCATION_EVENT = 1016; - public final static int DISPATCH_SYSTEM_UI_VISIBILITY = 1017; - public final static int DISPATCH_GENERIC_MOTION = 1018; - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case View.AttachInfo.INVALIDATE_MSG: - ((View) msg.obj).invalidate(); - break; - case View.AttachInfo.INVALIDATE_RECT_MSG: - final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj; - info.target.invalidate(info.left, info.top, info.right, info.bottom); - info.release(); - break; - case DO_TRAVERSAL: - if (mProfile) { - Debug.startMethodTracing("ViewRoot"); - } - - final long traversalStartTime; - if (ViewDebug.DEBUG_LATENCY) { - traversalStartTime = System.nanoTime(); - mLastDrawDurationNanos = 0; - } - - performTraversals(); - - if (ViewDebug.DEBUG_LATENCY) { - long now = System.nanoTime(); - Log.d(TAG, "Latency: Spent " - + ((now - traversalStartTime) * 0.000001f) - + "ms in performTraversals(), with " - + (mLastDrawDurationNanos * 0.000001f) - + "ms of that time in draw()"); - mLastTraversalFinishedTimeNanos = now; - } - - if (mProfile) { - Debug.stopMethodTracing(); - mProfile = false; - } - break; - case FINISHED_EVENT: - handleFinishedEvent(msg.arg1, msg.arg2 != 0); - break; - case DISPATCH_KEY: - deliverKeyEvent((KeyEvent)msg.obj, msg.arg1 != 0); - break; - case DISPATCH_POINTER: - deliverPointerEvent((MotionEvent) msg.obj, msg.arg1 != 0); - break; - case DISPATCH_TRACKBALL: - deliverTrackballEvent((MotionEvent) msg.obj, msg.arg1 != 0); - break; - case DISPATCH_GENERIC_MOTION: - deliverGenericMotionEvent((MotionEvent) msg.obj, msg.arg1 != 0); - break; - case DISPATCH_APP_VISIBILITY: - handleAppVisibility(msg.arg1 != 0); - break; - case DISPATCH_GET_NEW_SURFACE: - handleGetNewSurface(); - break; - case RESIZED: - ResizedInfo ri = (ResizedInfo)msg.obj; - - if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2 - && mPendingContentInsets.equals(ri.coveredInsets) - && mPendingVisibleInsets.equals(ri.visibleInsets) - && ((ResizedInfo)msg.obj).newConfig == null) { - break; - } - // fall through... - case RESIZED_REPORT: - if (mAdded) { - Configuration config = ((ResizedInfo)msg.obj).newConfig; - if (config != null) { - updateConfiguration(config, false); - } - mWinFrame.left = 0; - mWinFrame.right = msg.arg1; - mWinFrame.top = 0; - mWinFrame.bottom = msg.arg2; - mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets); - mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets); - if (msg.what == RESIZED_REPORT) { - mReportNextDraw = true; - } - - if (mView != null) { - forceLayout(mView); - } - requestLayout(); - } - break; - case WINDOW_FOCUS_CHANGED: { - if (mAdded) { - boolean hasWindowFocus = msg.arg1 != 0; - mAttachInfo.mHasWindowFocus = hasWindowFocus; - if (hasWindowFocus) { - boolean inTouchMode = msg.arg2 != 0; - ensureTouchModeLocally(inTouchMode); - - if (mAttachInfo.mHardwareRenderer != null && - mSurface != null && mSurface.isValid()) { - mFullRedrawNeeded = true; - try { - mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight, - mAttachInfo, mHolder); - } catch (Surface.OutOfResourcesException e) { - Log.e(TAG, "OutOfResourcesException locking surface", e); - try { - if (!sWindowSession.outOfMemory(mWindow)) { - Slog.w(TAG, "No processes killed for memory; killing self"); - Process.killProcess(Process.myPid()); - } - } catch (RemoteException ex) { - } - // Retry in a bit. - sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500); - return; - } - } - } - - mLastWasImTarget = WindowManager.LayoutParams - .mayUseInputMethod(mWindowAttributes.flags); - - InputMethodManager imm = InputMethodManager.peekInstance(); - if (mView != null) { - if (hasWindowFocus && imm != null && mLastWasImTarget) { - imm.startGettingWindowFocus(mView); - } - mAttachInfo.mKeyDispatchState.reset(); - mView.dispatchWindowFocusChanged(hasWindowFocus); - } - - // Note: must be done after the focus change callbacks, - // so all of the view state is set up correctly. - if (hasWindowFocus) { - if (imm != null && mLastWasImTarget) { - imm.onWindowFocus(mView, mView.findFocus(), - mWindowAttributes.softInputMode, - !mHasHadWindowFocus, mWindowAttributes.flags); - } - // Clear the forward bit. We can just do this directly, since - // the window manager doesn't care about it. - mWindowAttributes.softInputMode &= - ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; - ((WindowManager.LayoutParams)mView.getLayoutParams()) - .softInputMode &= - ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; - mHasHadWindowFocus = true; - } - - if (hasWindowFocus && mView != null) { - sendAccessibilityEvents(); - } - } - } break; - case DIE: - doDie(); - break; - case DISPATCH_KEY_FROM_IME: { - if (LOCAL_LOGV) Log.v( - TAG, "Dispatching key " - + msg.obj + " from IME to " + mView); - KeyEvent event = (KeyEvent)msg.obj; - if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) { - // The IME is trying to say this event is from the - // system! Bad bad bad! - event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM); - } - deliverKeyEventPostIme((KeyEvent)msg.obj, false); - } break; - case FINISH_INPUT_CONNECTION: { - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null) { - imm.reportFinishInputConnection((InputConnection)msg.obj); - } - } break; - case CHECK_FOCUS: { - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null) { - imm.checkFocus(); - } - } break; - case CLOSE_SYSTEM_DIALOGS: { - if (mView != null) { - mView.onCloseSystemDialogs((String)msg.obj); - } - } break; - case DISPATCH_DRAG_EVENT: - case DISPATCH_DRAG_LOCATION_EVENT: { - DragEvent event = (DragEvent)msg.obj; - event.mLocalState = mLocalDragState; // only present when this app called startDrag() - handleDragEvent(event); - } break; - case DISPATCH_SYSTEM_UI_VISIBILITY: { - handleDispatchSystemUiVisibilityChanged(msg.arg1); - } break; - } - } - - private void startInputEvent(InputEvent event, InputQueue.FinishedCallback finishedCallback) { - if (mFinishedCallback != null) { - Slog.w(TAG, "Received a new input event from the input queue but there is " - + "already an unfinished input event in progress."); - } - - if (ViewDebug.DEBUG_LATENCY) { - mInputEventReceiveTimeNanos = System.nanoTime(); - mInputEventDeliverTimeNanos = 0; - mInputEventDeliverPostImeTimeNanos = 0; - } - - mFinishedCallback = finishedCallback; - } - - private void finishInputEvent(InputEvent event, boolean handled) { - if (LOCAL_LOGV) Log.v(TAG, "Telling window manager input event is finished"); - - if (mFinishedCallback == null) { - Slog.w(TAG, "Attempted to tell the input queue that the current input event " - + "is finished but there is no input event actually in progress."); - return; - } - - if (ViewDebug.DEBUG_LATENCY) { - final long now = System.nanoTime(); - final long eventTime = event.getEventTimeNano(); - final StringBuilder msg = new StringBuilder(); - msg.append("Latency: Spent "); - msg.append((now - mInputEventReceiveTimeNanos) * 0.000001f); - msg.append("ms processing "); - if (event instanceof KeyEvent) { - final KeyEvent keyEvent = (KeyEvent)event; - msg.append("key event, action="); - msg.append(KeyEvent.actionToString(keyEvent.getAction())); - } else { - final MotionEvent motionEvent = (MotionEvent)event; - msg.append("motion event, action="); - msg.append(MotionEvent.actionToString(motionEvent.getAction())); - msg.append(", historySize="); - msg.append(motionEvent.getHistorySize()); - } - msg.append(", handled="); - msg.append(handled); - msg.append(", received at +"); - msg.append((mInputEventReceiveTimeNanos - eventTime) * 0.000001f); - if (mInputEventDeliverTimeNanos != 0) { - msg.append("ms, delivered at +"); - msg.append((mInputEventDeliverTimeNanos - eventTime) * 0.000001f); - } - if (mInputEventDeliverPostImeTimeNanos != 0) { - msg.append("ms, delivered post IME at +"); - msg.append((mInputEventDeliverPostImeTimeNanos - eventTime) * 0.000001f); - } - msg.append("ms, finished at +"); - msg.append((now - eventTime) * 0.000001f); - msg.append("ms."); - Log.d(TAG, msg.toString()); - } - - mFinishedCallback.finished(handled); - mFinishedCallback = null; - } - - /** - * Something in the current window tells us we need to change the touch mode. For - * example, we are not in touch mode, and the user touches the screen. - * - * If the touch mode has changed, tell the window manager, and handle it locally. - * - * @param inTouchMode Whether we want to be in touch mode. - * @return True if the touch mode changed and focus changed was changed as a result - */ - boolean ensureTouchMode(boolean inTouchMode) { - if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current " - + "touch mode is " + mAttachInfo.mInTouchMode); - if (mAttachInfo.mInTouchMode == inTouchMode) return false; - - // tell the window manager - try { - sWindowSession.setInTouchMode(inTouchMode); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - - // handle the change - return ensureTouchModeLocally(inTouchMode); - } - - /** - * Ensure that the touch mode for this window is set, and if it is changing, - * take the appropriate action. - * @param inTouchMode Whether we want to be in touch mode. - * @return True if the touch mode changed and focus changed was changed as a result - */ - private boolean ensureTouchModeLocally(boolean inTouchMode) { - if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current " - + "touch mode is " + mAttachInfo.mInTouchMode); - - if (mAttachInfo.mInTouchMode == inTouchMode) return false; - - mAttachInfo.mInTouchMode = inTouchMode; - mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode); - - return (inTouchMode) ? enterTouchMode() : leaveTouchMode(); - } - - private boolean enterTouchMode() { - if (mView != null) { - if (mView.hasFocus()) { - // note: not relying on mFocusedView here because this could - // be when the window is first being added, and mFocused isn't - // set yet. - final View focused = mView.findFocus(); - if (focused != null && !focused.isFocusableInTouchMode()) { - - final ViewGroup ancestorToTakeFocus = - findAncestorToTakeFocusInTouchMode(focused); - if (ancestorToTakeFocus != null) { - // there is an ancestor that wants focus after its descendants that - // is focusable in touch mode.. give it focus - return ancestorToTakeFocus.requestFocus(); - } else { - // nothing appropriate to have focus in touch mode, clear it out - mView.unFocus(); - mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null); - mFocusedView = null; - return true; - } - } - } - } - return false; - } - - - /** - * Find an ancestor of focused that wants focus after its descendants and is - * focusable in touch mode. - * @param focused The currently focused view. - * @return An appropriate view, or null if no such view exists. - */ - private ViewGroup findAncestorToTakeFocusInTouchMode(View focused) { - ViewParent parent = focused.getParent(); - while (parent instanceof ViewGroup) { - final ViewGroup vgParent = (ViewGroup) parent; - if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS - && vgParent.isFocusableInTouchMode()) { - return vgParent; - } - if (vgParent.isRootNamespace()) { - return null; - } else { - parent = vgParent.getParent(); - } - } - return null; - } - - private boolean leaveTouchMode() { - if (mView != null) { - if (mView.hasFocus()) { - // i learned the hard way to not trust mFocusedView :) - mFocusedView = mView.findFocus(); - if (!(mFocusedView instanceof ViewGroup)) { - // some view has focus, let it keep it - return false; - } else if (((ViewGroup)mFocusedView).getDescendantFocusability() != - ViewGroup.FOCUS_AFTER_DESCENDANTS) { - // some view group has focus, and doesn't prefer its children - // over itself for focus, so let them keep it. - return false; - } - } - - // find the best view to give focus to in this brave new non-touch-mode - // world - final View focused = focusSearch(null, View.FOCUS_DOWN); - if (focused != null) { - return focused.requestFocus(View.FOCUS_DOWN); - } - } - return false; - } - - private void deliverPointerEvent(MotionEvent event, boolean sendDone) { - if (ViewDebug.DEBUG_LATENCY) { - mInputEventDeliverTimeNanos = System.nanoTime(); - } - - if (mInputEventConsistencyVerifier != null) { - if (event.isTouchEvent()) { - mInputEventConsistencyVerifier.onTouchEvent(event, 0); - } else { - mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); - } - } - - // If there is no view, then the event will not be handled. - if (mView == null || !mAdded) { - finishMotionEvent(event, sendDone, false); - return; - } - - // Translate the pointer event for compatibility, if needed. - if (mTranslator != null) { - mTranslator.translateEventInScreenToAppWindow(event); - } - - // Enter touch mode on the down. - boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN; - if (isDown) { - ensureTouchMode(true); - } - if(false) { - captureMotionLog("captureDispatchPointer", event); - } - - // Offset the scroll position. - if (mCurScrollY != 0) { - event.offsetLocation(0, mCurScrollY); - } - if (MEASURE_LATENCY) { - lt.sample("A Dispatching PointerEvents", System.nanoTime() - event.getEventTimeNano()); - } - - // Remember the touch position for possible drag-initiation. - mLastTouchPoint.x = event.getRawX(); - mLastTouchPoint.y = event.getRawY(); - - // Dispatch touch to view hierarchy. - boolean handled = mView.dispatchPointerEvent(event); - if (MEASURE_LATENCY) { - lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano()); - } - if (handled) { - finishMotionEvent(event, sendDone, true); - return; - } - - // Apply edge slop and try again, if appropriate. - final int edgeFlags = event.getEdgeFlags(); - if (edgeFlags != 0 && mView instanceof ViewGroup) { - final int edgeSlop = mViewConfiguration.getScaledEdgeSlop(); - int direction = View.FOCUS_UP; - int x = (int)event.getX(); - int y = (int)event.getY(); - final int[] deltas = new int[2]; - - if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) { - direction = View.FOCUS_DOWN; - if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) { - deltas[0] = edgeSlop; - x += edgeSlop; - } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) { - deltas[0] = -edgeSlop; - x -= edgeSlop; - } - } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) { - direction = View.FOCUS_UP; - if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) { - deltas[0] = edgeSlop; - x += edgeSlop; - } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) { - deltas[0] = -edgeSlop; - x -= edgeSlop; - } - } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) { - direction = View.FOCUS_RIGHT; - } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) { - direction = View.FOCUS_LEFT; - } - - View nearest = FocusFinder.getInstance().findNearestTouchable( - ((ViewGroup) mView), x, y, direction, deltas); - if (nearest != null) { - event.offsetLocation(deltas[0], deltas[1]); - event.setEdgeFlags(0); - if (mView.dispatchPointerEvent(event)) { - finishMotionEvent(event, sendDone, true); - return; - } - } - } - - // Pointer event was unhandled. - finishMotionEvent(event, sendDone, false); - } - - private void finishMotionEvent(MotionEvent event, boolean sendDone, boolean handled) { - event.recycle(); - if (sendDone) { - finishInputEvent(event, handled); - } - if (LOCAL_LOGV || WATCH_POINTER) { - if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { - Log.i(TAG, "Done dispatching!"); - } - } - } - - private void deliverTrackballEvent(MotionEvent event, boolean sendDone) { - if (ViewDebug.DEBUG_LATENCY) { - mInputEventDeliverTimeNanos = System.nanoTime(); - } - - if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event); - - if (mInputEventConsistencyVerifier != null) { - mInputEventConsistencyVerifier.onTrackballEvent(event, 0); - } - - // If there is no view, then the event will not be handled. - if (mView == null || !mAdded) { - finishMotionEvent(event, sendDone, false); - return; - } - - // Deliver the trackball event to the view. - if (mView.dispatchTrackballEvent(event)) { - // If we reach this, we delivered a trackball event to mView and - // mView consumed it. Because we will not translate the trackball - // event into a key event, touch mode will not exit, so we exit - // touch mode here. - ensureTouchMode(false); - - finishMotionEvent(event, sendDone, true); - mLastTrackballTime = Integer.MIN_VALUE; - return; - } - - // Translate the trackball event into DPAD keys and try to deliver those. - final TrackballAxis x = mTrackballAxisX; - final TrackballAxis y = mTrackballAxisY; - - long curTime = SystemClock.uptimeMillis(); - if ((mLastTrackballTime + MAX_TRACKBALL_DELAY) < curTime) { - // It has been too long since the last movement, - // so restart at the beginning. - x.reset(0); - y.reset(0); - mLastTrackballTime = curTime; - } - - final int action = event.getAction(); - final int metaState = event.getMetaState(); - switch (action) { - case MotionEvent.ACTION_DOWN: - x.reset(2); - y.reset(2); - deliverKeyEvent(new KeyEvent(curTime, curTime, - KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState, - KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, - InputDevice.SOURCE_KEYBOARD), false); - break; - case MotionEvent.ACTION_UP: - x.reset(2); - y.reset(2); - deliverKeyEvent(new KeyEvent(curTime, curTime, - KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState, - KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, - InputDevice.SOURCE_KEYBOARD), false); - break; - } - - if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step=" - + x.step + " dir=" + x.dir + " acc=" + x.acceleration - + " move=" + event.getX() - + " / Y=" + y.position + " step=" - + y.step + " dir=" + y.dir + " acc=" + y.acceleration - + " move=" + event.getY()); - final float xOff = x.collect(event.getX(), event.getEventTime(), "X"); - final float yOff = y.collect(event.getY(), event.getEventTime(), "Y"); - - // Generate DPAD events based on the trackball movement. - // We pick the axis that has moved the most as the direction of - // the DPAD. When we generate DPAD events for one axis, then the - // other axis is reset -- we don't want to perform DPAD jumps due - // to slight movements in the trackball when making major movements - // along the other axis. - int keycode = 0; - int movement = 0; - float accel = 1; - if (xOff > yOff) { - movement = x.generate((2/event.getXPrecision())); - if (movement != 0) { - keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT - : KeyEvent.KEYCODE_DPAD_LEFT; - accel = x.acceleration; - y.reset(2); - } - } else if (yOff > 0) { - movement = y.generate((2/event.getYPrecision())); - if (movement != 0) { - keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN - : KeyEvent.KEYCODE_DPAD_UP; - accel = y.acceleration; - x.reset(2); - } - } - - if (keycode != 0) { - if (movement < 0) movement = -movement; - int accelMovement = (int)(movement * accel); - if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement - + " accelMovement=" + accelMovement - + " accel=" + accel); - if (accelMovement > movement) { - if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: " - + keycode); - movement--; - int repeatCount = accelMovement - movement; - deliverKeyEvent(new KeyEvent(curTime, curTime, - KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState, - KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, - InputDevice.SOURCE_KEYBOARD), false); - } - while (movement > 0) { - if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: " - + keycode); - movement--; - curTime = SystemClock.uptimeMillis(); - deliverKeyEvent(new KeyEvent(curTime, curTime, - KeyEvent.ACTION_DOWN, keycode, 0, metaState, - KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, - InputDevice.SOURCE_KEYBOARD), false); - deliverKeyEvent(new KeyEvent(curTime, curTime, - KeyEvent.ACTION_UP, keycode, 0, metaState, - KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, - InputDevice.SOURCE_KEYBOARD), false); - } - mLastTrackballTime = curTime; - } - - // Unfortunately we can't tell whether the application consumed the keys, so - // we always consider the trackball event handled. - finishMotionEvent(event, sendDone, true); - } - - private void deliverGenericMotionEvent(MotionEvent event, boolean sendDone) { - if (ViewDebug.DEBUG_LATENCY) { - mInputEventDeliverTimeNanos = System.nanoTime(); - } - - if (mInputEventConsistencyVerifier != null) { - mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); - } - - final int source = event.getSource(); - final boolean isJoystick = (source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0; - - // If there is no view, then the event will not be handled. - if (mView == null || !mAdded) { - if (isJoystick) { - updateJoystickDirection(event, false); - } - finishMotionEvent(event, sendDone, false); - return; - } - - // Deliver the event to the view. - if (mView.dispatchGenericMotionEvent(event)) { - if (isJoystick) { - updateJoystickDirection(event, false); - } - finishMotionEvent(event, sendDone, true); - return; - } - - if (isJoystick) { - // Translate the joystick event into DPAD keys and try to deliver those. - updateJoystickDirection(event, true); - finishMotionEvent(event, sendDone, true); - } else { - finishMotionEvent(event, sendDone, false); - } - } - - private void updateJoystickDirection(MotionEvent event, boolean synthesizeNewKeys) { - final long time = event.getEventTime(); - final int metaState = event.getMetaState(); - final int deviceId = event.getDeviceId(); - final int source = event.getSource(); - - int xDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_X)); - if (xDirection == 0) { - xDirection = joystickAxisValueToDirection(event.getX()); - } - - int yDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_Y)); - if (yDirection == 0) { - yDirection = joystickAxisValueToDirection(event.getY()); - } - - if (xDirection != mLastJoystickXDirection) { - if (mLastJoystickXKeyCode != 0) { - deliverKeyEvent(new KeyEvent(time, time, - KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState, - deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false); - mLastJoystickXKeyCode = 0; - } - - mLastJoystickXDirection = xDirection; - - if (xDirection != 0 && synthesizeNewKeys) { - mLastJoystickXKeyCode = xDirection > 0 - ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT; - deliverKeyEvent(new KeyEvent(time, time, - KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState, - deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false); - } - } - - if (yDirection != mLastJoystickYDirection) { - if (mLastJoystickYKeyCode != 0) { - deliverKeyEvent(new KeyEvent(time, time, - KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState, - deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false); - mLastJoystickYKeyCode = 0; - } - - mLastJoystickYDirection = yDirection; - - if (yDirection != 0 && synthesizeNewKeys) { - mLastJoystickYKeyCode = yDirection > 0 - ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP; - deliverKeyEvent(new KeyEvent(time, time, - KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState, - deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false); - } - } - } - - private static int joystickAxisValueToDirection(float value) { - if (value >= 0.5f) { - return 1; - } else if (value <= -0.5f) { - return -1; - } else { - return 0; - } - } - - /** - * Returns true if the key is used for keyboard navigation. - * @param keyEvent The key event. - * @return True if the key is used for keyboard navigation. - */ - private static boolean isNavigationKey(KeyEvent keyEvent) { - switch (keyEvent.getKeyCode()) { - case KeyEvent.KEYCODE_DPAD_LEFT: - case KeyEvent.KEYCODE_DPAD_RIGHT: - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_PAGE_UP: - case KeyEvent.KEYCODE_PAGE_DOWN: - case KeyEvent.KEYCODE_MOVE_HOME: - case KeyEvent.KEYCODE_MOVE_END: - case KeyEvent.KEYCODE_TAB: - case KeyEvent.KEYCODE_SPACE: - case KeyEvent.KEYCODE_ENTER: - return true; - } - return false; - } - - /** - * Returns true if the key is used for typing. - * @param keyEvent The key event. - * @return True if the key is used for typing. - */ - private static boolean isTypingKey(KeyEvent keyEvent) { - return keyEvent.getUnicodeChar() > 0; - } - - /** - * See if the key event means we should leave touch mode (and leave touch mode if so). - * @param event The key event. - * @return Whether this key event should be consumed (meaning the act of - * leaving touch mode alone is considered the event). - */ - private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) { - // Only relevant in touch mode. - if (!mAttachInfo.mInTouchMode) { - return false; - } - - // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP. - final int action = event.getAction(); - if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) { - return false; - } - - // Don't leave touch mode if the IME told us not to. - if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) { - return false; - } - - // If the key can be used for keyboard navigation then leave touch mode - // and select a focused view if needed (in ensureTouchMode). - // When a new focused view is selected, we consume the navigation key because - // navigation doesn't make much sense unless a view already has focus so - // the key's purpose is to set focus. - if (isNavigationKey(event)) { - return ensureTouchMode(false); - } - - // If the key can be used for typing then leave touch mode - // and select a focused view if needed (in ensureTouchMode). - // Always allow the view to process the typing key. - if (isTypingKey(event)) { - ensureTouchMode(false); - return false; - } - - return false; - } - - /** - * log motion events - */ - private static void captureMotionLog(String subTag, MotionEvent ev) { - //check dynamic switch - if (ev == null || - SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_EVENT, 0) == 0) { - return; - } - - StringBuilder sb = new StringBuilder(subTag + ": "); - sb.append(ev.getDownTime()).append(','); - sb.append(ev.getEventTime()).append(','); - sb.append(ev.getAction()).append(','); - sb.append(ev.getX()).append(','); - sb.append(ev.getY()).append(','); - sb.append(ev.getPressure()).append(','); - sb.append(ev.getSize()).append(','); - sb.append(ev.getMetaState()).append(','); - sb.append(ev.getXPrecision()).append(','); - sb.append(ev.getYPrecision()).append(','); - sb.append(ev.getDeviceId()).append(','); - sb.append(ev.getEdgeFlags()); - Log.d(TAG, sb.toString()); - } - /** - * log motion events - */ - private static void captureKeyLog(String subTag, KeyEvent ev) { - //check dynamic switch - if (ev == null || - SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_EVENT, 0) == 0) { - return; - } - StringBuilder sb = new StringBuilder(subTag + ": "); - sb.append(ev.getDownTime()).append(','); - sb.append(ev.getEventTime()).append(','); - sb.append(ev.getAction()).append(','); - sb.append(ev.getKeyCode()).append(','); - sb.append(ev.getRepeatCount()).append(','); - sb.append(ev.getMetaState()).append(','); - sb.append(ev.getDeviceId()).append(','); - sb.append(ev.getScanCode()); - Log.d(TAG, sb.toString()); - } - - int enqueuePendingEvent(Object event, boolean sendDone) { - int seq = mPendingEventSeq+1; - if (seq < 0) seq = 0; - mPendingEventSeq = seq; - mPendingEvents.put(seq, event); - return sendDone ? seq : -seq; - } - - Object retrievePendingEvent(int seq) { - if (seq < 0) seq = -seq; - Object event = mPendingEvents.get(seq); - if (event != null) { - mPendingEvents.remove(seq); - } - return event; - } - - private void deliverKeyEvent(KeyEvent event, boolean sendDone) { - if (ViewDebug.DEBUG_LATENCY) { - mInputEventDeliverTimeNanos = System.nanoTime(); - } - - if (mInputEventConsistencyVerifier != null) { - mInputEventConsistencyVerifier.onKeyEvent(event, 0); - } - - // If there is no view, then the event will not be handled. - if (mView == null || !mAdded) { - finishKeyEvent(event, sendDone, false); - return; - } - - if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView); - - // Perform predispatching before the IME. - if (mView.dispatchKeyEventPreIme(event)) { - finishKeyEvent(event, sendDone, true); - return; - } - - // Dispatch to the IME before propagating down the view hierarchy. - // The IME will eventually call back into handleFinishedEvent. - if (mLastWasImTarget) { - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null) { - int seq = enqueuePendingEvent(event, sendDone); - if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq=" - + seq + " event=" + event); - imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback); - return; - } - } - - // Not dispatching to IME, continue with post IME actions. - deliverKeyEventPostIme(event, sendDone); - } - - private void handleFinishedEvent(int seq, boolean handled) { - final KeyEvent event = (KeyEvent)retrievePendingEvent(seq); - if (DEBUG_IMF) Log.v(TAG, "IME finished event: seq=" + seq - + " handled=" + handled + " event=" + event); - if (event != null) { - final boolean sendDone = seq >= 0; - if (handled) { - finishKeyEvent(event, sendDone, true); - } else { - deliverKeyEventPostIme(event, sendDone); - } - } - } - - private void deliverKeyEventPostIme(KeyEvent event, boolean sendDone) { - if (ViewDebug.DEBUG_LATENCY) { - mInputEventDeliverPostImeTimeNanos = System.nanoTime(); - } - - // If the view went away, then the event will not be handled. - if (mView == null || !mAdded) { - finishKeyEvent(event, sendDone, false); - return; - } - - // If the key's purpose is to exit touch mode then we consume it and consider it handled. - if (checkForLeavingTouchModeAndConsume(event)) { - finishKeyEvent(event, sendDone, true); - return; - } - - if (false) { - captureKeyLog("captureDispatchKeyEvent", event); - } - - // Make sure the fallback event policy sees all keys that will be delivered to the - // view hierarchy. - mFallbackEventHandler.preDispatchKeyEvent(event); - - // Deliver the key to the view hierarchy. - if (mView.dispatchKeyEvent(event)) { - finishKeyEvent(event, sendDone, true); - return; - } - - // If the Control modifier is held, try to interpret the key as a shortcut. - if (event.getAction() == KeyEvent.ACTION_UP - && event.isCtrlPressed() - && !KeyEvent.isModifierKey(event.getKeyCode())) { - if (mView.dispatchKeyShortcutEvent(event)) { - finishKeyEvent(event, sendDone, true); - return; - } - } - - // Apply the fallback event policy. - if (mFallbackEventHandler.dispatchKeyEvent(event)) { - finishKeyEvent(event, sendDone, true); - return; - } - - // Handle automatic focus changes. - if (event.getAction() == KeyEvent.ACTION_DOWN) { - int direction = 0; - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_DPAD_LEFT: - if (event.hasNoModifiers()) { - direction = View.FOCUS_LEFT; - } - break; - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (event.hasNoModifiers()) { - direction = View.FOCUS_RIGHT; - } - break; - case KeyEvent.KEYCODE_DPAD_UP: - if (event.hasNoModifiers()) { - direction = View.FOCUS_UP; - } - break; - case KeyEvent.KEYCODE_DPAD_DOWN: - if (event.hasNoModifiers()) { - direction = View.FOCUS_DOWN; - } - break; - case KeyEvent.KEYCODE_TAB: - if (event.hasNoModifiers()) { - direction = View.FOCUS_FORWARD; - } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) { - direction = View.FOCUS_BACKWARD; - } - break; - } - - if (direction != 0) { - View focused = mView != null ? mView.findFocus() : null; - if (focused != null) { - View v = focused.focusSearch(direction); - if (v != null && v != focused) { - // do the math the get the interesting rect - // of previous focused into the coord system of - // newly focused view - focused.getFocusedRect(mTempRect); - if (mView instanceof ViewGroup) { - ((ViewGroup) mView).offsetDescendantRectToMyCoords( - focused, mTempRect); - ((ViewGroup) mView).offsetRectIntoDescendantCoords( - v, mTempRect); - } - if (v.requestFocus(direction, mTempRect)) { - playSoundEffect( - SoundEffectConstants.getContantForFocusDirection(direction)); - finishKeyEvent(event, sendDone, true); - return; - } - } - - // Give the focused view a last chance to handle the dpad key. - if (mView.dispatchUnhandledMove(focused, direction)) { - finishKeyEvent(event, sendDone, true); - return; - } - } - } - } - - // Key was unhandled. - finishKeyEvent(event, sendDone, false); - } - - private void finishKeyEvent(KeyEvent event, boolean sendDone, boolean handled) { - if (sendDone) { - finishInputEvent(event, handled); - } - } - - /* drag/drop */ - void setLocalDragState(Object obj) { - mLocalDragState = obj; - } - - private void handleDragEvent(DragEvent event) { - // From the root, only drag start/end/location are dispatched. entered/exited - // are determined and dispatched by the viewgroup hierarchy, who then report - // that back here for ultimate reporting back to the framework. - if (mView != null && mAdded) { - final int what = event.mAction; - - if (what == DragEvent.ACTION_DRAG_EXITED) { - // A direct EXITED event means that the window manager knows we've just crossed - // a window boundary, so the current drag target within this one must have - // just been exited. Send it the usual notifications and then we're done - // for now. - mView.dispatchDragEvent(event); - } else { - // Cache the drag description when the operation starts, then fill it in - // on subsequent calls as a convenience - if (what == DragEvent.ACTION_DRAG_STARTED) { - mCurrentDragView = null; // Start the current-recipient tracking - mDragDescription = event.mClipDescription; - } else { - event.mClipDescription = mDragDescription; - } - - // For events with a [screen] location, translate into window coordinates - if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) { - mDragPoint.set(event.mX, event.mY); - if (mTranslator != null) { - mTranslator.translatePointInScreenToAppWindow(mDragPoint); - } - - if (mCurScrollY != 0) { - mDragPoint.offset(0, mCurScrollY); - } - - event.mX = mDragPoint.x; - event.mY = mDragPoint.y; - } - - // Remember who the current drag target is pre-dispatch - final View prevDragView = mCurrentDragView; - - // Now dispatch the drag/drop event - boolean result = mView.dispatchDragEvent(event); - - // If we changed apparent drag target, tell the OS about it - if (prevDragView != mCurrentDragView) { - try { - if (prevDragView != null) { - sWindowSession.dragRecipientExited(mWindow); - } - if (mCurrentDragView != null) { - sWindowSession.dragRecipientEntered(mWindow); - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to note drag target change"); - } - } - - // Report the drop result when we're done - if (what == DragEvent.ACTION_DROP) { - mDragDescription = null; - try { - Log.i(TAG, "Reporting drop result: " + result); - sWindowSession.reportDropResult(mWindow, result); - } catch (RemoteException e) { - Log.e(TAG, "Unable to report drop result"); - } - } - - // When the drag operation ends, release any local state object - // that may have been in use - if (what == DragEvent.ACTION_DRAG_ENDED) { - setLocalDragState(null); - } - } - } - event.recycle(); - } - - public void handleDispatchSystemUiVisibilityChanged(int visibility) { - if (mView == null) return; - if (mAttachInfo != null) { - mAttachInfo.mSystemUiVisibility = visibility; - } - mView.dispatchSystemUiVisibilityChanged(visibility); - } - - public void getLastTouchPoint(Point outLocation) { - outLocation.x = (int) mLastTouchPoint.x; - outLocation.y = (int) mLastTouchPoint.y; - } - - public void setDragFocus(View newDragTarget) { - if (mCurrentDragView != newDragTarget) { - mCurrentDragView = newDragTarget; - } - } - - private AudioManager getAudioManager() { - if (mView == null) { - throw new IllegalStateException("getAudioManager called when there is no mView"); - } - if (mAudioManager == null) { - mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE); - } - return mAudioManager; - } - - private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, - boolean insetsPending) throws RemoteException { - - float appScale = mAttachInfo.mApplicationScale; - boolean restore = false; - if (params != null && mTranslator != null) { - restore = true; - params.backup(); - mTranslator.translateWindowLayout(params); - } - if (params != null) { - if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params); - } - mPendingConfiguration.seq = 0; - //Log.d(TAG, ">>>>>> CALLING relayout"); - int relayoutResult = sWindowSession.relayout( - mWindow, params, - (int) (mView.getMeasuredWidth() * appScale + 0.5f), - (int) (mView.getMeasuredHeight() * appScale + 0.5f), - viewVisibility, insetsPending, mWinFrame, - mPendingContentInsets, mPendingVisibleInsets, - mPendingConfiguration, mSurface); - //Log.d(TAG, "<<<<<< BACK FROM relayout"); - if (restore) { - params.restore(); - } - - if (mTranslator != null) { - mTranslator.translateRectInScreenToAppWinFrame(mWinFrame); - mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets); - mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets); - } - return relayoutResult; - } - - /** - * {@inheritDoc} - */ - public void playSoundEffect(int effectId) { - checkThread(); - - try { - final AudioManager audioManager = getAudioManager(); - - switch (effectId) { - case SoundEffectConstants.CLICK: - audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); - return; - case SoundEffectConstants.NAVIGATION_DOWN: - audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN); - return; - case SoundEffectConstants.NAVIGATION_LEFT: - audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT); - return; - case SoundEffectConstants.NAVIGATION_RIGHT: - audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT); - return; - case SoundEffectConstants.NAVIGATION_UP: - audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP); - return; - default: - throw new IllegalArgumentException("unknown effect id " + effectId + - " not defined in " + SoundEffectConstants.class.getCanonicalName()); - } - } catch (IllegalStateException e) { - // Exception thrown by getAudioManager() when mView is null - Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e); - e.printStackTrace(); - } - } - - /** - * {@inheritDoc} - */ - public boolean performHapticFeedback(int effectId, boolean always) { - try { - return sWindowSession.performHapticFeedback(mWindow, effectId, always); - } catch (RemoteException e) { - return false; - } - } - - /** - * {@inheritDoc} - */ - public View focusSearch(View focused, int direction) { - checkThread(); - if (!(mView instanceof ViewGroup)) { - return null; - } - return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction); - } - - public void debug() { - mView.debug(); - } - - public void die(boolean immediate) { - if (immediate) { - doDie(); - } else { - sendEmptyMessage(DIE); - } - } - - void doDie() { - checkThread(); - if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface); - synchronized (this) { - if (mAdded && !mFirst) { - destroyHardwareRenderer(); - - int viewVisibility = mView.getVisibility(); - boolean viewVisibilityChanged = mViewVisibility != viewVisibility; - if (mWindowAttributesChanged || viewVisibilityChanged) { - // If layout params have been changed, first give them - // to the window manager to make sure it has the correct - // animation info. - try { - if ((relayoutWindow(mWindowAttributes, viewVisibility, false) - & WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) { - sWindowSession.finishDrawing(mWindow); - } - } catch (RemoteException e) { - } - } - - mSurface.release(); - } - if (mAdded) { - mAdded = false; - dispatchDetachedFromWindow(); - } - } - } - - private void destroyHardwareRenderer() { - if (mAttachInfo.mHardwareRenderer != null) { - mAttachInfo.mHardwareRenderer.destroy(true); - mAttachInfo.mHardwareRenderer = null; - mAttachInfo.mHardwareAccelerated = false; - } - } - - public void dispatchFinishedEvent(int seq, boolean handled) { - Message msg = obtainMessage(FINISHED_EVENT); - msg.arg1 = seq; - msg.arg2 = handled ? 1 : 0; - sendMessage(msg); - } - - public void dispatchResized(int w, int h, Rect coveredInsets, - Rect visibleInsets, boolean reportDraw, Configuration newConfig) { - if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w - + " h=" + h + " coveredInsets=" + coveredInsets.toShortString() - + " visibleInsets=" + visibleInsets.toShortString() - + " reportDraw=" + reportDraw); - Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED); - if (mTranslator != null) { - mTranslator.translateRectInScreenToAppWindow(coveredInsets); - mTranslator.translateRectInScreenToAppWindow(visibleInsets); - w *= mTranslator.applicationInvertedScale; - h *= mTranslator.applicationInvertedScale; - } - msg.arg1 = w; - msg.arg2 = h; - ResizedInfo ri = new ResizedInfo(); - ri.coveredInsets = new Rect(coveredInsets); - ri.visibleInsets = new Rect(visibleInsets); - ri.newConfig = newConfig; - msg.obj = ri; - sendMessage(msg); - } - - private long mInputEventReceiveTimeNanos; - private long mInputEventDeliverTimeNanos; - private long mInputEventDeliverPostImeTimeNanos; - private InputQueue.FinishedCallback mFinishedCallback; - - private final InputHandler mInputHandler = new InputHandler() { - public void handleKey(KeyEvent event, InputQueue.FinishedCallback finishedCallback) { - startInputEvent(event, finishedCallback); - dispatchKey(event, true); - } - - public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) { - startInputEvent(event, finishedCallback); - dispatchMotion(event, true); - } - }; - - public void dispatchKey(KeyEvent event) { - dispatchKey(event, false); - } - - private void dispatchKey(KeyEvent event, boolean sendDone) { - //noinspection ConstantConditions - if (false && event.getAction() == KeyEvent.ACTION_DOWN) { - if (event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) { - if (DBG) Log.d("keydisp", "==================================================="); - if (DBG) Log.d("keydisp", "Focused view Hierarchy is:"); - - debug(); - - if (DBG) Log.d("keydisp", "==================================================="); - } - } - - Message msg = obtainMessage(DISPATCH_KEY); - msg.obj = event; - msg.arg1 = sendDone ? 1 : 0; - - if (LOCAL_LOGV) Log.v( - TAG, "sending key " + event + " to " + mView); - - sendMessageAtTime(msg, event.getEventTime()); - } - - public void dispatchMotion(MotionEvent event) { - dispatchMotion(event, false); - } - - private void dispatchMotion(MotionEvent event, boolean sendDone) { - int source = event.getSource(); - if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { - dispatchPointer(event, sendDone); - } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { - dispatchTrackball(event, sendDone); - } else { - dispatchGenericMotion(event, sendDone); - } - } - - public void dispatchPointer(MotionEvent event) { - dispatchPointer(event, false); - } - - private void dispatchPointer(MotionEvent event, boolean sendDone) { - Message msg = obtainMessage(DISPATCH_POINTER); - msg.obj = event; - msg.arg1 = sendDone ? 1 : 0; - sendMessageAtTime(msg, event.getEventTime()); - } - - public void dispatchTrackball(MotionEvent event) { - dispatchTrackball(event, false); - } - - private void dispatchTrackball(MotionEvent event, boolean sendDone) { - Message msg = obtainMessage(DISPATCH_TRACKBALL); - msg.obj = event; - msg.arg1 = sendDone ? 1 : 0; - sendMessageAtTime(msg, event.getEventTime()); - } - - private void dispatchGenericMotion(MotionEvent event, boolean sendDone) { - Message msg = obtainMessage(DISPATCH_GENERIC_MOTION); - msg.obj = event; - msg.arg1 = sendDone ? 1 : 0; - sendMessageAtTime(msg, event.getEventTime()); - } - - public void dispatchAppVisibility(boolean visible) { - Message msg = obtainMessage(DISPATCH_APP_VISIBILITY); - msg.arg1 = visible ? 1 : 0; - sendMessage(msg); - } - - public void dispatchGetNewSurface() { - Message msg = obtainMessage(DISPATCH_GET_NEW_SURFACE); - sendMessage(msg); - } - - public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) { - Message msg = Message.obtain(); - msg.what = WINDOW_FOCUS_CHANGED; - msg.arg1 = hasFocus ? 1 : 0; - msg.arg2 = inTouchMode ? 1 : 0; - sendMessage(msg); - } - - public void dispatchCloseSystemDialogs(String reason) { - Message msg = Message.obtain(); - msg.what = CLOSE_SYSTEM_DIALOGS; - msg.obj = reason; - sendMessage(msg); - } - - public void dispatchDragEvent(DragEvent event) { - final int what; - if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) { - what = DISPATCH_DRAG_LOCATION_EVENT; - removeMessages(what); - } else { - what = DISPATCH_DRAG_EVENT; - } - Message msg = obtainMessage(what, event); - sendMessage(msg); - } - - public void dispatchSystemUiVisibilityChanged(int visibility) { - sendMessage(obtainMessage(DISPATCH_SYSTEM_UI_VISIBILITY, visibility, 0)); - } - - /** - * The window is getting focus so if there is anything focused/selected - * send an {@link AccessibilityEvent} to announce that. - */ - private void sendAccessibilityEvents() { - if (!AccessibilityManager.getInstance(mView.getContext()).isEnabled()) { - return; - } - mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); - View focusedView = mView.findFocus(); - if (focusedView != null && focusedView != mView) { - focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); - } - } - - public boolean showContextMenuForChild(View originalView) { - return false; - } - - public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { - return null; - } - - public void createContextMenu(ContextMenu menu) { - } - - public void childDrawableStateChanged(View child) { - } - - public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) { - if (mView == null) { - return false; - } - AccessibilityManager.getInstance(child.mContext).sendAccessibilityEvent(event); - return true; - } - - void checkThread() { - if (mThread != Thread.currentThread()) { - throw new CalledFromWrongThreadException( - "Only the original thread that created a view hierarchy can touch its views."); - } - } - - public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { - // ViewRoot never intercepts touch event, so this can be a no-op - } - - public boolean requestChildRectangleOnScreen(View child, Rect rectangle, - boolean immediate) { - return scrollToRectOrFocus(rectangle, immediate); - } - - class TakenSurfaceHolder extends BaseSurfaceHolder { - @Override - public boolean onAllowLockCanvas() { - return mDrawingAllowed; - } - - @Override - public void onRelayoutContainer() { - // Not currently interesting -- from changing between fixed and layout size. - } - - public void setFormat(int format) { - ((RootViewSurfaceTaker)mView).setSurfaceFormat(format); - } - - public void setType(int type) { - ((RootViewSurfaceTaker)mView).setSurfaceType(type); - } - - @Override - public void onUpdateSurface() { - // We take care of format and type changes on our own. - throw new IllegalStateException("Shouldn't be here"); - } - - public boolean isCreating() { - return mIsCreating; - } - - @Override - public void setFixedSize(int width, int height) { - throw new UnsupportedOperationException( - "Currently only support sizing from layout"); - } - - public void setKeepScreenOn(boolean screenOn) { - ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn); - } - } - - static class InputMethodCallback extends IInputMethodCallback.Stub { - private WeakReference mViewRoot; - - public InputMethodCallback(ViewRoot viewRoot) { - mViewRoot = new WeakReference(viewRoot); - } - - public void finishedEvent(int seq, boolean handled) { - final ViewRoot viewRoot = mViewRoot.get(); - if (viewRoot != null) { - viewRoot.dispatchFinishedEvent(seq, handled); - } - } - - public void sessionCreated(IInputMethodSession session) throws RemoteException { - // Stub -- not for use in the client. - } - } - - static class W extends IWindow.Stub { - private final WeakReference mViewRoot; - - W(ViewRoot viewRoot) { - mViewRoot = new WeakReference(viewRoot); - } - - public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets, - boolean reportDraw, Configuration newConfig) { - final ViewRoot viewRoot = mViewRoot.get(); - if (viewRoot != null) { - viewRoot.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw, newConfig); - } - } - - public void dispatchAppVisibility(boolean visible) { - final ViewRoot viewRoot = mViewRoot.get(); - if (viewRoot != null) { - viewRoot.dispatchAppVisibility(visible); - } - } - - public void dispatchGetNewSurface() { - final ViewRoot viewRoot = mViewRoot.get(); - if (viewRoot != null) { - viewRoot.dispatchGetNewSurface(); - } - } - - public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) { - final ViewRoot viewRoot = mViewRoot.get(); - if (viewRoot != null) { - viewRoot.windowFocusChanged(hasFocus, inTouchMode); - } - } - - private static int checkCallingPermission(String permission) { - if (!Process.supportsProcesses()) { - return PackageManager.PERMISSION_GRANTED; - } - - try { - return ActivityManagerNative.getDefault().checkPermission( - permission, Binder.getCallingPid(), Binder.getCallingUid()); - } catch (RemoteException e) { - return PackageManager.PERMISSION_DENIED; - } - } - - public void executeCommand(String command, String parameters, ParcelFileDescriptor out) { - final ViewRoot viewRoot = mViewRoot.get(); - if (viewRoot != null) { - final View view = viewRoot.mView; - if (view != null) { - if (checkCallingPermission(Manifest.permission.DUMP) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Insufficient permissions to invoke" - + " executeCommand() from pid=" + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - } - - OutputStream clientStream = null; - try { - clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out); - ViewDebug.dispatchCommand(view, command, parameters, clientStream); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (clientStream != null) { - try { - clientStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - } - } - - public void closeSystemDialogs(String reason) { - final ViewRoot viewRoot = mViewRoot.get(); - if (viewRoot != null) { - viewRoot.dispatchCloseSystemDialogs(reason); - } - } - - public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, - boolean sync) { - if (sync) { - try { - sWindowSession.wallpaperOffsetsComplete(asBinder()); - } catch (RemoteException e) { - } - } - } - - public void dispatchWallpaperCommand(String action, int x, int y, - int z, Bundle extras, boolean sync) { - if (sync) { - try { - sWindowSession.wallpaperCommandComplete(asBinder(), null); - } catch (RemoteException e) { - } - } - } - - /* Drag/drop */ - public void dispatchDragEvent(DragEvent event) { - final ViewRoot viewRoot = mViewRoot.get(); - if (viewRoot != null) { - viewRoot.dispatchDragEvent(event); - } - } - - @Override - public void dispatchSystemUiVisibilityChanged(int visibility) { - final ViewRoot viewRoot = mViewRoot.get(); - if (viewRoot != null) { - viewRoot.dispatchSystemUiVisibilityChanged(visibility); - } - } - } - - /** - * Maintains state information for a single trackball axis, generating - * discrete (DPAD) movements based on raw trackball motion. - */ - static final class TrackballAxis { - /** - * The maximum amount of acceleration we will apply. - */ - static final float MAX_ACCELERATION = 20; - - /** - * The maximum amount of time (in milliseconds) between events in order - * for us to consider the user to be doing fast trackball movements, - * and thus apply an acceleration. - */ - static final long FAST_MOVE_TIME = 150; - - /** - * Scaling factor to the time (in milliseconds) between events to how - * much to multiple/divide the current acceleration. When movement - * is < FAST_MOVE_TIME this multiplies the acceleration; when > - * FAST_MOVE_TIME it divides it. - */ - static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40); - - float position; - float absPosition; - float acceleration = 1; - long lastMoveTime = 0; - int step; - int dir; - int nonAccelMovement; - - void reset(int _step) { - position = 0; - acceleration = 1; - lastMoveTime = 0; - step = _step; - dir = 0; - } - - /** - * Add trackball movement into the state. If the direction of movement - * has been reversed, the state is reset before adding the - * movement (so that you don't have to compensate for any previously - * collected movement before see the result of the movement in the - * new direction). - * - * @return Returns the absolute value of the amount of movement - * collected so far. - */ - float collect(float off, long time, String axis) { - long normTime; - if (off > 0) { - normTime = (long)(off * FAST_MOVE_TIME); - if (dir < 0) { - if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!"); - position = 0; - step = 0; - acceleration = 1; - lastMoveTime = 0; - } - dir = 1; - } else if (off < 0) { - normTime = (long)((-off) * FAST_MOVE_TIME); - if (dir > 0) { - if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!"); - position = 0; - step = 0; - acceleration = 1; - lastMoveTime = 0; - } - dir = -1; - } else { - normTime = 0; - } - - // The number of milliseconds between each movement that is - // considered "normal" and will not result in any acceleration - // or deceleration, scaled by the offset we have here. - if (normTime > 0) { - long delta = time - lastMoveTime; - lastMoveTime = time; - float acc = acceleration; - if (delta < normTime) { - // The user is scrolling rapidly, so increase acceleration. - float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR; - if (scale > 1) acc *= scale; - if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off=" - + off + " normTime=" + normTime + " delta=" + delta - + " scale=" + scale + " acc=" + acc); - acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION; - } else { - // The user is scrolling slowly, so decrease acceleration. - float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR; - if (scale > 1) acc /= scale; - if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off=" - + off + " normTime=" + normTime + " delta=" + delta - + " scale=" + scale + " acc=" + acc); - acceleration = acc > 1 ? acc : 1; - } - } - position += off; - return (absPosition = Math.abs(position)); - } - - /** - * Generate the number of discrete movement events appropriate for - * the currently collected trackball movement. - * - * @param precision The minimum movement required to generate the - * first discrete movement. - * - * @return Returns the number of discrete movements, either positive - * or negative, or 0 if there is not enough trackball movement yet - * for a discrete movement. - */ - int generate(float precision) { - int movement = 0; - nonAccelMovement = 0; - do { - final int dir = position >= 0 ? 1 : -1; - switch (step) { - // If we are going to execute the first step, then we want - // to do this as soon as possible instead of waiting for - // a full movement, in order to make things look responsive. - case 0: - if (absPosition < precision) { - return movement; - } - movement += dir; - nonAccelMovement += dir; - step = 1; - break; - // If we have generated the first movement, then we need - // to wait for the second complete trackball motion before - // generating the second discrete movement. - case 1: - if (absPosition < 2) { - return movement; - } - movement += dir; - nonAccelMovement += dir; - position += dir > 0 ? -2 : 2; - absPosition = Math.abs(position); - step = 2; - break; - // After the first two, we generate discrete movements - // consistently with the trackball, applying an acceleration - // if the trackball is moving quickly. This is a simple - // acceleration on top of what we already compute based - // on how quickly the wheel is being turned, to apply - // a longer increasing acceleration to continuous movement - // in one direction. - default: - if (absPosition < 1) { - return movement; - } - movement += dir; - position += dir >= 0 ? -1 : 1; - absPosition = Math.abs(position); - float acc = acceleration; - acc *= 1.1f; - acceleration = acc < MAX_ACCELERATION ? acc : acceleration; - break; - } - } while (true); - } - } - - public static final class CalledFromWrongThreadException extends AndroidRuntimeException { - public CalledFromWrongThreadException(String msg) { - super(msg); - } - } - - private SurfaceHolder mHolder = new SurfaceHolder() { - // we only need a SurfaceHolder for opengl. it would be nice - // to implement everything else though, especially the callback - // support (opengl doesn't make use of it right now, but eventually - // will). - public Surface getSurface() { - return mSurface; - } - - public boolean isCreating() { - return false; - } - - public void addCallback(Callback callback) { - } - - public void removeCallback(Callback callback) { - } - - public void setFixedSize(int width, int height) { - } - - public void setSizeFromLayout() { - } - - public void setFormat(int format) { - } - - public void setType(int type) { - } - - public void setKeepScreenOn(boolean screenOn) { - } - - public Canvas lockCanvas() { - return null; - } - - public Canvas lockCanvas(Rect dirty) { - return null; - } - - public void unlockCanvasAndPost(Canvas canvas) { - } - public Rect getSurfaceFrame() { - return null; - } - }; - - static RunQueue getRunQueue() { - RunQueue rq = sRunQueues.get(); - if (rq != null) { - return rq; - } - rq = new RunQueue(); - sRunQueues.set(rq); - return rq; - } - - /** - * @hide - */ - static final class RunQueue { - private final ArrayList mActions = new ArrayList(); - - void post(Runnable action) { - postDelayed(action, 0); - } - - void postDelayed(Runnable action, long delayMillis) { - HandlerAction handlerAction = new HandlerAction(); - handlerAction.action = action; - handlerAction.delay = delayMillis; - - synchronized (mActions) { - mActions.add(handlerAction); - } - } - - void removeCallbacks(Runnable action) { - final HandlerAction handlerAction = new HandlerAction(); - handlerAction.action = action; - - synchronized (mActions) { - final ArrayList actions = mActions; - - while (actions.remove(handlerAction)) { - // Keep going - } - } - } - - void executeActions(Handler handler) { - synchronized (mActions) { - final ArrayList actions = mActions; - final int count = actions.size(); - - for (int i = 0; i < count; i++) { - final HandlerAction handlerAction = actions.get(i); - handler.postDelayed(handlerAction.action, handlerAction.delay); - } - - actions.clear(); - } - } - - private static class HandlerAction { - Runnable action; - long delay; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - HandlerAction that = (HandlerAction) o; - return !(action != null ? !action.equals(that.action) : that.action != null); - - } - - @Override - public int hashCode() { - int result = action != null ? action.hashCode() : 0; - result = 31 * result + (int) (delay ^ (delay >>> 32)); - return result; - } - } - } - - private static native void nativeShowFPS(Canvas canvas, int durationMillis); -} -- cgit v1.2.3