diff options
14 files changed, 3760 insertions, 3459 deletions
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java new file mode 100644 index 000000000000..d3d9df4359d5 --- /dev/null +++ b/services/java/com/android/server/wm/AppWindowToken.java @@ -0,0 +1,413 @@ +/* + * Copyright (C) 2011 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 com.android.server.wm; + +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; + +import com.android.server.wm.WindowManagerService.H; + +import android.content.pm.ActivityInfo; +import android.os.Message; +import android.os.RemoteException; +import android.util.Slog; +import android.view.IApplicationToken; +import android.view.View; +import android.view.WindowManager; +import android.view.animation.Animation; +import android.view.animation.Transformation; + +import java.io.PrintWriter; +import java.util.ArrayList; + +/** + * Version of WindowToken that is specifically for a particular application (or + * really activity) that is displaying windows. + */ +class AppWindowToken extends WindowToken { + // Non-null only for application tokens. + final IApplicationToken appToken; + + // All of the windows and child windows that are included in this + // application token. Note this list is NOT sorted! + final ArrayList<WindowState> allAppWindows = new ArrayList<WindowState>(); + + int groupId = -1; + boolean appFullscreen; + int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + + // The input dispatching timeout for this application token in nanoseconds. + long inputDispatchingTimeoutNanos; + + // These are used for determining when all windows associated with + // an activity have been drawn, so they can be made visible together + // at the same time. + int lastTransactionSequence; + int numInterestingWindows; + int numDrawnWindows; + boolean inPendingTransaction; + boolean allDrawn; + + // Is this token going to be hidden in a little while? If so, it + // won't be taken into account for setting the screen orientation. + boolean willBeHidden; + + // Is this window's surface needed? This is almost like hidden, except + // it will sometimes be true a little earlier: when the token has + // been shown, but is still waiting for its app transition to execute + // before making its windows shown. + boolean hiddenRequested; + + // Have we told the window clients to hide themselves? + boolean clientHidden; + + // Last visibility state we reported to the app token. + boolean reportedVisible; + + // Set to true when the token has been removed from the window mgr. + boolean removed; + + // Have we been asked to have this token keep the screen frozen? + boolean freezingScreen; + + boolean animating; + Animation animation; + boolean hasTransformation; + final Transformation transformation = new Transformation(); + + // Offset to the window of all layers in the token, for use by + // AppWindowToken animations. + int animLayerAdjustment; + + // Information about an application starting window if displayed. + StartingData startingData; + WindowState startingWindow; + View startingView; + boolean startingDisplayed; + boolean startingMoved; + boolean firstWindowDrawn; + + // Input application handle used by the input dispatcher. + InputApplicationHandle mInputApplicationHandle; + + AppWindowToken(WindowManagerService _service, IApplicationToken _token) { + super(_service, _token.asBinder(), + WindowManager.LayoutParams.TYPE_APPLICATION, true); + appWindowToken = this; + appToken = _token; + mInputApplicationHandle = new InputApplicationHandle(this); + lastTransactionSequence = service.mTransactionSequence-1; + } + + public void setAnimation(Animation anim) { + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Setting animation in " + this + ": " + anim); + animation = anim; + animating = false; + anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION); + anim.scaleCurrentDuration(service.mTransitionAnimationScale); + int zorder = anim.getZAdjustment(); + int adj = 0; + if (zorder == Animation.ZORDER_TOP) { + adj = WindowManagerService.TYPE_LAYER_OFFSET; + } else if (zorder == Animation.ZORDER_BOTTOM) { + adj = -WindowManagerService.TYPE_LAYER_OFFSET; + } + + if (animLayerAdjustment != adj) { + animLayerAdjustment = adj; + updateLayers(); + } + } + + public void setDummyAnimation() { + if (animation == null) { + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Setting dummy animation in " + this); + animation = WindowManagerService.sDummyAnimation; + } + } + + public void clearAnimation() { + if (animation != null) { + animation = null; + animating = true; + } + } + + void updateLayers() { + final int N = allAppWindows.size(); + final int adj = animLayerAdjustment; + for (int i=0; i<N; i++) { + WindowState w = allAppWindows.get(i); + w.mAnimLayer = w.mLayer + adj; + if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Updating layer " + w + ": " + + w.mAnimLayer); + if (w == service.mInputMethodTarget && !service.mInputMethodTargetWaitingAnim) { + service.setInputMethodAnimLayerAdjustment(adj); + } + if (w == service.mWallpaperTarget && service.mLowerWallpaperTarget == null) { + service.setWallpaperAnimLayerAdjustmentLocked(adj); + } + } + } + + void sendAppVisibilityToClients() { + final int N = allAppWindows.size(); + for (int i=0; i<N; i++) { + WindowState win = allAppWindows.get(i); + if (win == startingWindow && clientHidden) { + // Don't hide the starting window. + continue; + } + try { + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, + "Setting visibility of " + win + ": " + (!clientHidden)); + win.mClient.dispatchAppVisibility(!clientHidden); + } catch (RemoteException e) { + } + } + } + + void showAllWindowsLocked() { + final int NW = allAppWindows.size(); + for (int i=0; i<NW; i++) { + WindowState w = allAppWindows.get(i); + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, + "performing show on: " + w); + w.performShowLocked(); + } + } + + // This must be called while inside a transaction. + boolean stepAnimationLocked(long currentTime, int dw, int dh) { + if (!service.mDisplayFrozen && service.mPolicy.isScreenOn()) { + // We will run animations as long as the display isn't frozen. + + if (animation == WindowManagerService.sDummyAnimation) { + // This guy is going to animate, but not yet. For now count + // it as not animating for purposes of scheduling transactions; + // when it is really time to animate, this will be set to + // a real animation and the next call will execute normally. + return false; + } + + if ((allDrawn || animating || startingDisplayed) && animation != null) { + if (!animating) { + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Starting animation in " + this + + " @ " + currentTime + ": dw=" + dw + " dh=" + dh + + " scale=" + service.mTransitionAnimationScale + + " allDrawn=" + allDrawn + " animating=" + animating); + animation.initialize(dw, dh, dw, dh); + animation.setStartTime(currentTime); + animating = true; + } + transformation.clear(); + final boolean more = animation.getTransformation( + currentTime, transformation); + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Stepped animation in " + this + + ": more=" + more + ", xform=" + transformation); + if (more) { + // we're done! + hasTransformation = true; + return true; + } + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Finished animation in " + this + + " @ " + currentTime); + animation = null; + } + } else if (animation != null) { + // If the display is frozen, and there is a pending animation, + // clear it and make sure we run the cleanup code. + animating = true; + animation = null; + } + + hasTransformation = false; + + if (!animating) { + return false; + } + + clearAnimation(); + animating = false; + if (animLayerAdjustment != 0) { + animLayerAdjustment = 0; + updateLayers(); + } + if (service.mInputMethodTarget != null && service.mInputMethodTarget.mAppToken == this) { + service.moveInputMethodWindowsIfNeededLocked(true); + } + + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Animation done in " + this + + ": reportedVisible=" + reportedVisible); + + transformation.clear(); + + final int N = windows.size(); + for (int i=0; i<N; i++) { + windows.get(i).finishExit(); + } + updateReportedVisibilityLocked(); + + return false; + } + + void updateReportedVisibilityLocked() { + if (appToken == null) { + return; + } + + int numInteresting = 0; + int numVisible = 0; + boolean nowGone = true; + + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Update reported visibility: " + this); + final int N = allAppWindows.size(); + for (int i=0; i<N; i++) { + WindowState win = allAppWindows.get(i); + if (win == startingWindow || win.mAppFreezing + || win.mViewVisibility != View.VISIBLE + || win.mAttrs.type == TYPE_APPLICATION_STARTING + || win.mDestroying) { + continue; + } + if (WindowManagerService.DEBUG_VISIBILITY) { + Slog.v(WindowManagerService.TAG, "Win " + win + ": isDrawn=" + + win.isDrawnLw() + + ", isAnimating=" + win.isAnimating()); + if (!win.isDrawnLw()) { + Slog.v(WindowManagerService.TAG, "Not displayed: s=" + win.mSurface + + " pv=" + win.mPolicyVisibility + + " dp=" + win.mDrawPending + + " cdp=" + win.mCommitDrawPending + + " ah=" + win.mAttachedHidden + + " th=" + + (win.mAppToken != null + ? win.mAppToken.hiddenRequested : false) + + " a=" + win.mAnimating); + } + } + numInteresting++; + if (win.isDrawnLw()) { + if (!win.isAnimating()) { + numVisible++; + } + nowGone = false; + } else if (win.isAnimating()) { + nowGone = false; + } + } + + boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting; + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "VIS " + this + ": interesting=" + + numInteresting + " visible=" + numVisible); + if (nowVisible != reportedVisible) { + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v( + WindowManagerService.TAG, "Visibility changed in " + this + + ": vis=" + nowVisible); + reportedVisible = nowVisible; + Message m = service.mH.obtainMessage( + H.REPORT_APPLICATION_TOKEN_WINDOWS, + nowVisible ? 1 : 0, + nowGone ? 1 : 0, + this); + service.mH.sendMessage(m); + } + } + + WindowState findMainWindow() { + int j = windows.size(); + while (j > 0) { + j--; + WindowState win = windows.get(j); + if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION + || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) { + return win; + } + } + return null; + } + + void dump(PrintWriter pw, String prefix) { + super.dump(pw, prefix); + if (appToken != null) { + pw.print(prefix); pw.println("app=true"); + } + if (allAppWindows.size() > 0) { + pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows); + } + pw.print(prefix); pw.print("groupId="); pw.print(groupId); + pw.print(" appFullscreen="); pw.print(appFullscreen); + pw.print(" requestedOrientation="); pw.println(requestedOrientation); + pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested); + pw.print(" clientHidden="); pw.print(clientHidden); + pw.print(" willBeHidden="); pw.print(willBeHidden); + pw.print(" reportedVisible="); pw.println(reportedVisible); + if (paused || freezingScreen) { + pw.print(prefix); pw.print("paused="); pw.print(paused); + pw.print(" freezingScreen="); pw.println(freezingScreen); + } + if (numInterestingWindows != 0 || numDrawnWindows != 0 + || inPendingTransaction || allDrawn) { + pw.print(prefix); pw.print("numInterestingWindows="); + pw.print(numInterestingWindows); + pw.print(" numDrawnWindows="); pw.print(numDrawnWindows); + pw.print(" inPendingTransaction="); pw.print(inPendingTransaction); + pw.print(" allDrawn="); pw.println(allDrawn); + } + if (animating || animation != null) { + pw.print(prefix); pw.print("animating="); pw.print(animating); + pw.print(" animation="); pw.println(animation); + } + if (hasTransformation) { + pw.print(prefix); pw.print("XForm: "); + transformation.printShortString(pw); + pw.println(); + } + if (animLayerAdjustment != 0) { + pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment); + } + if (startingData != null || removed || firstWindowDrawn) { + pw.print(prefix); pw.print("startingData="); pw.print(startingData); + pw.print(" removed="); pw.print(removed); + pw.print(" firstWindowDrawn="); pw.println(firstWindowDrawn); + } + if (startingWindow != null || startingView != null + || startingDisplayed || startingMoved) { + pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow); + pw.print(" startingView="); pw.print(startingView); + pw.print(" startingDisplayed="); pw.print(startingDisplayed); + pw.print(" startingMoved"); pw.println(startingMoved); + } + } + + @Override + public String toString() { + if (stringName == null) { + StringBuilder sb = new StringBuilder(); + sb.append("AppWindowToken{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" token="); sb.append(token); sb.append('}'); + stringName = sb.toString(); + } + return stringName; + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java new file mode 100644 index 000000000000..1fcb8697174a --- /dev/null +++ b/services/java/com/android/server/wm/DimAnimator.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2011 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 com.android.server.wm; + +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.util.Slog; +import android.util.TypedValue; +import android.view.Surface; +import android.view.SurfaceSession; + +import java.io.PrintWriter; + +/** + * DimAnimator class that controls the dim animation. This holds the surface and + * all state used for dim animation. + */ +class DimAnimator { + Surface mDimSurface; + boolean mDimShown = false; + float mDimCurrentAlpha; + float mDimTargetAlpha; + float mDimDeltaPerMs; + long mLastDimAnimTime; + + int mLastDimWidth, mLastDimHeight; + + DimAnimator (SurfaceSession session) { + if (mDimSurface == null) { + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + + mDimSurface + ": CREATE"); + try { + mDimSurface = new Surface(session, 0, + "DimSurface", + -1, 16, 16, PixelFormat.OPAQUE, + Surface.FX_SURFACE_DIM); + mDimSurface.setAlpha(0.0f); + } catch (Exception e) { + Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e); + } + } + } + + /** + * Show the dim surface. + */ + void show(int dw, int dh) { + if (!mDimShown) { + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + mDimSurface + ": SHOW pos=(0,0) (" + + dw + "x" + dh + ")"); + mDimShown = true; + try { + mLastDimWidth = dw; + mLastDimHeight = dh; + mDimSurface.setPosition(0, 0); + mDimSurface.setSize(dw, dh); + mDimSurface.show(); + } catch (RuntimeException e) { + Slog.w(WindowManagerService.TAG, "Failure showing dim surface", e); + } + } else if (mLastDimWidth != dw || mLastDimHeight != dh) { + mLastDimWidth = dw; + mLastDimHeight = dh; + mDimSurface.setSize(dw, dh); + } + } + + /** + * Set's the dim surface's layer and update dim parameters that will be used in + * {@link updateSurface} after all windows are examined. + */ + void updateParameters(Resources res, WindowState w, long currentTime) { + mDimSurface.setLayer(w.mAnimLayer-1); + + final float target = w.mExiting ? 0 : w.mAttrs.dimAmount; + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + mDimSurface + + ": layer=" + (w.mAnimLayer-1) + " target=" + target); + if (mDimTargetAlpha != target) { + // If the desired dim level has changed, then + // start an animation to it. + mLastDimAnimTime = currentTime; + long duration = (w.mAnimating && w.mAnimation != null) + ? w.mAnimation.computeDurationHint() + : WindowManagerService.DEFAULT_DIM_DURATION; + if (target > mDimTargetAlpha) { + TypedValue tv = new TypedValue(); + res.getValue(com.android.internal.R.fraction.config_dimBehindFadeDuration, + tv, true); + if (tv.type == TypedValue.TYPE_FRACTION) { + duration = (long)tv.getFraction((float)duration, (float)duration); + } else if (tv.type >= TypedValue.TYPE_FIRST_INT + && tv.type <= TypedValue.TYPE_LAST_INT) { + duration = tv.data; + } + } + if (duration < 1) { + // Don't divide by zero + duration = 1; + } + mDimTargetAlpha = target; + mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha) / duration; + } + } + + /** + * Updating the surface's alpha. Returns true if the animation continues, or returns + * false when the animation is finished and the dim surface is hidden. + */ + boolean updateSurface(boolean dimming, long currentTime, boolean displayFrozen) { + if (!dimming) { + if (mDimTargetAlpha != 0) { + mLastDimAnimTime = currentTime; + mDimTargetAlpha = 0; + mDimDeltaPerMs = (-mDimCurrentAlpha) / WindowManagerService.DEFAULT_DIM_DURATION; + } + } + + boolean animating = false; + if (mLastDimAnimTime != 0) { + mDimCurrentAlpha += mDimDeltaPerMs + * (currentTime-mLastDimAnimTime); + boolean more = true; + if (displayFrozen) { + // If the display is frozen, there is no reason to animate. + more = false; + } else if (mDimDeltaPerMs > 0) { + if (mDimCurrentAlpha > mDimTargetAlpha) { + more = false; + } + } else if (mDimDeltaPerMs < 0) { + if (mDimCurrentAlpha < mDimTargetAlpha) { + more = false; + } + } else { + more = false; + } + + // Do we need to continue animating? + if (more) { + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + + mDimSurface + ": alpha=" + mDimCurrentAlpha); + mLastDimAnimTime = currentTime; + mDimSurface.setAlpha(mDimCurrentAlpha); + animating = true; + } else { + mDimCurrentAlpha = mDimTargetAlpha; + mLastDimAnimTime = 0; + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + + mDimSurface + ": final alpha=" + mDimCurrentAlpha); + mDimSurface.setAlpha(mDimCurrentAlpha); + if (!dimming) { + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + mDimSurface + + ": HIDE"); + try { + mDimSurface.hide(); + } catch (RuntimeException e) { + Slog.w(WindowManagerService.TAG, "Illegal argument exception hiding dim surface"); + } + mDimShown = false; + } + } + } + return animating; + } + + public void printTo(PrintWriter pw) { + pw.print(" mDimShown="); pw.print(mDimShown); + pw.print(" current="); pw.print(mDimCurrentAlpha); + pw.print(" target="); pw.print(mDimTargetAlpha); + pw.print(" delta="); pw.print(mDimDeltaPerMs); + pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime); + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java new file mode 100644 index 000000000000..c8f8ff3ca03e --- /dev/null +++ b/services/java/com/android/server/wm/DragState.java @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2011 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 com.android.server.wm; + +import com.android.server.wm.WindowManagerService.H; + +import android.content.ClipData; +import android.content.ClipDescription; +import android.graphics.Region; +import android.os.IBinder; +import android.os.Message; +import android.os.Process; +import android.os.RemoteException; +import android.util.Slog; +import android.view.DragEvent; +import android.view.InputChannel; +import android.view.InputQueue; +import android.view.Surface; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowManagerPolicy; + +import java.util.ArrayList; + +/** + * Drag/drop state + */ +class DragState { + final WindowManagerService mService; + IBinder mToken; + Surface mSurface; + int mFlags; + IBinder mLocalWin; + ClipData mData; + ClipDescription mDataDescription; + boolean mDragResult; + float mCurrentX, mCurrentY; + float mThumbOffsetX, mThumbOffsetY; + InputChannel mServerChannel, mClientChannel; + WindowState mTargetWindow; + ArrayList<WindowState> mNotifiedWindows; + boolean mDragInProgress; + + private final Region mTmpRegion = new Region(); + + DragState(WindowManagerService service, IBinder token, Surface surface, + int flags, IBinder localWin) { + mService = service; + mToken = token; + mSurface = surface; + mFlags = flags; + mLocalWin = localWin; + mNotifiedWindows = new ArrayList<WindowState>(); + } + + void reset() { + if (mSurface != null) { + mSurface.destroy(); + } + mSurface = null; + mFlags = 0; + mLocalWin = null; + mToken = null; + mData = null; + mThumbOffsetX = mThumbOffsetY = 0; + mNotifiedWindows = null; + } + + void register() { + if (WindowManagerService.DEBUG_DRAG) Slog.d(WindowManagerService.TAG, "registering drag input channel"); + if (mClientChannel != null) { + Slog.e(WindowManagerService.TAG, "Duplicate register of drag input channel"); + } else { + InputChannel[] channels = InputChannel.openInputChannelPair("drag"); + mServerChannel = channels[0]; + mClientChannel = channels[1]; + mService.mInputManager.registerInputChannel(mServerChannel, null); + InputQueue.registerInputChannel(mClientChannel, mService.mDragInputHandler, + mService.mH.getLooper().getQueue()); + } + } + + void unregister() { + if (WindowManagerService.DEBUG_DRAG) Slog.d(WindowManagerService.TAG, "unregistering drag input channel"); + if (mClientChannel == null) { + Slog.e(WindowManagerService.TAG, "Unregister of nonexistent drag input channel"); + } else { + mService.mInputManager.unregisterInputChannel(mServerChannel); + InputQueue.unregisterInputChannel(mClientChannel); + mClientChannel.dispose(); + mServerChannel.dispose(); + mClientChannel = null; + mServerChannel = null; + } + } + + int getDragLayerLw() { + return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_DRAG) + * WindowManagerService.TYPE_LAYER_MULTIPLIER + + WindowManagerService.TYPE_LAYER_OFFSET; + } + + /* call out to each visible window/session informing it about the drag + */ + void broadcastDragStartedLw(final float touchX, final float touchY) { + // Cache a base-class instance of the clip metadata so that parceling + // works correctly in calling out to the apps. + mDataDescription = (mData != null) ? mData.getDescription() : null; + mNotifiedWindows.clear(); + mDragInProgress = true; + + if (WindowManagerService.DEBUG_DRAG) { + Slog.d(WindowManagerService.TAG, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")"); + } + + final int N = mService.mWindows.size(); + for (int i = 0; i < N; i++) { + sendDragStartedLw(mService.mWindows.get(i), touchX, touchY, mDataDescription); + } + } + + /* helper - send a caller-provided event, presumed to be DRAG_STARTED, if the + * designated window is potentially a drop recipient. There are race situations + * around DRAG_ENDED broadcast, so we make sure that once we've declared that + * the drag has ended, we never send out another DRAG_STARTED for this drag action. + * + * This method clones the 'event' parameter if it's being delivered to the same + * process, so it's safe for the caller to call recycle() on the event afterwards. + */ + private void sendDragStartedLw(WindowState newWin, float touchX, float touchY, + ClipDescription desc) { + // Don't actually send the event if the drag is supposed to be pinned + // to the originating window but 'newWin' is not that window. + if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) { + final IBinder winBinder = newWin.mClient.asBinder(); + if (winBinder != mLocalWin) { + if (WindowManagerService.DEBUG_DRAG) { + Slog.d(WindowManagerService.TAG, "Not dispatching local DRAG_STARTED to " + newWin); + } + return; + } + } + + if (mDragInProgress && newWin.isPotentialDragTarget()) { + DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED, + touchX - newWin.mFrame.left, touchY - newWin.mFrame.top, + null, desc, null, false); + try { + newWin.mClient.dispatchDragEvent(event); + // track each window that we've notified that the drag is starting + mNotifiedWindows.add(newWin); + } catch (RemoteException e) { + Slog.w(WindowManagerService.TAG, "Unable to drag-start window " + newWin); + } finally { + // if the callee was local, the dispatch has already recycled the event + if (Process.myPid() != newWin.mSession.mPid) { + event.recycle(); + } + } + } + } + + /* helper - construct and send a DRAG_STARTED event only if the window has not + * previously been notified, i.e. it became visible after the drag operation + * was begun. This is a rare case. + */ + void sendDragStartedIfNeededLw(WindowState newWin) { + if (mDragInProgress) { + // If we have sent the drag-started, we needn't do so again + for (WindowState ws : mNotifiedWindows) { + if (ws == newWin) { + return; + } + } + if (WindowManagerService.DEBUG_DRAG) { + Slog.d(WindowManagerService.TAG, "need to send DRAG_STARTED to new window " + newWin); + } + sendDragStartedLw(newWin, mCurrentX, mCurrentY, mDataDescription); + } + } + + void broadcastDragEndedLw() { + if (WindowManagerService.DEBUG_DRAG) { + Slog.d(WindowManagerService.TAG, "broadcasting DRAG_ENDED"); + } + DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED, + 0, 0, null, null, null, mDragResult); + for (WindowState ws: mNotifiedWindows) { + try { + ws.mClient.dispatchDragEvent(evt); + } catch (RemoteException e) { + Slog.w(WindowManagerService.TAG, "Unable to drag-end window " + ws); + } + } + mNotifiedWindows.clear(); + mDragInProgress = false; + evt.recycle(); + } + + void endDragLw() { + mService.mDragState.broadcastDragEndedLw(); + + // stop intercepting input + mService.mDragState.unregister(); + mService.mInputMonitor.updateInputWindowsLw(true /*force*/); + + // free our resources and drop all the object references + mService.mDragState.reset(); + mService.mDragState = null; + + if (WindowManagerService.DEBUG_ORIENTATION) Slog.d(WindowManagerService.TAG, "Performing post-drag rotation"); + boolean changed = mService.setRotationUncheckedLocked( + WindowManagerPolicy.USE_LAST_ROTATION, 0, false); + if (changed) { + mService.mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); + } + } + + void notifyMoveLw(float x, float y) { + final int myPid = Process.myPid(); + + // Move the surface to the given touch + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, ">>> OPEN TRANSACTION notifyMoveLw"); + Surface.openTransaction(); + try { + mSurface.setPosition((int)(x - mThumbOffsetX), (int)(y - mThumbOffsetY)); + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DRAG " + + mSurface + ": pos=(" + + (int)(x - mThumbOffsetX) + "," + (int)(y - mThumbOffsetY) + ")"); + } finally { + Surface.closeTransaction(); + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "<<< CLOSE TRANSACTION notifyMoveLw"); + } + + // Tell the affected window + WindowState touchedWin = getTouchedWinAtPointLw(x, y); + if (touchedWin == null) { + if (WindowManagerService.DEBUG_DRAG) Slog.d(WindowManagerService.TAG, "No touched win at x=" + x + " y=" + y); + return; + } + if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) { + final IBinder touchedBinder = touchedWin.mClient.asBinder(); + if (touchedBinder != mLocalWin) { + // This drag is pinned only to the originating window, but the drag + // point is outside that window. Pretend it's over empty space. + touchedWin = null; + } + } + try { + // have we dragged over a new window? + if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) { + if (WindowManagerService.DEBUG_DRAG) { + Slog.d(WindowManagerService.TAG, "sending DRAG_EXITED to " + mTargetWindow); + } + // force DRAG_EXITED_EVENT if appropriate + DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_EXITED, + x - mTargetWindow.mFrame.left, y - mTargetWindow.mFrame.top, + null, null, null, false); + mTargetWindow.mClient.dispatchDragEvent(evt); + if (myPid != mTargetWindow.mSession.mPid) { + evt.recycle(); + } + } + if (touchedWin != null) { + if (false && WindowManagerService.DEBUG_DRAG) { + Slog.d(WindowManagerService.TAG, "sending DRAG_LOCATION to " + touchedWin); + } + DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_LOCATION, + x - touchedWin.mFrame.left, y - touchedWin.mFrame.top, + null, null, null, false); + touchedWin.mClient.dispatchDragEvent(evt); + if (myPid != touchedWin.mSession.mPid) { + evt.recycle(); + } + } + } catch (RemoteException e) { + Slog.w(WindowManagerService.TAG, "can't send drag notification to windows"); + } + mTargetWindow = touchedWin; + } + + // Tell the drop target about the data. Returns 'true' if we can immediately + // dispatch the global drag-ended message, 'false' if we need to wait for a + // result from the recipient. + boolean notifyDropLw(float x, float y) { + WindowState touchedWin = getTouchedWinAtPointLw(x, y); + if (touchedWin == null) { + // "drop" outside a valid window -- no recipient to apply a + // timeout to, and we can send the drag-ended message immediately. + mDragResult = false; + return true; + } + + if (WindowManagerService.DEBUG_DRAG) { + Slog.d(WindowManagerService.TAG, "sending DROP to " + touchedWin); + } + final int myPid = Process.myPid(); + final IBinder token = touchedWin.mClient.asBinder(); + DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DROP, + x - touchedWin.mFrame.left, y - touchedWin.mFrame.top, + null, null, mData, false); + try { + touchedWin.mClient.dispatchDragEvent(evt); + + // 5 second timeout for this window to respond to the drop + mService.mH.removeMessages(H.DRAG_END_TIMEOUT, token); + Message msg = mService.mH.obtainMessage(H.DRAG_END_TIMEOUT, token); + mService.mH.sendMessageDelayed(msg, 5000); + } catch (RemoteException e) { + Slog.w(WindowManagerService.TAG, "can't send drop notification to win " + touchedWin); + return true; + } finally { + if (myPid != touchedWin.mSession.mPid) { + evt.recycle(); + } + } + mToken = token; + return false; + } + + // Find the visible, touch-deliverable window under the given point + private WindowState getTouchedWinAtPointLw(float xf, float yf) { + WindowState touchedWin = null; + final int x = (int) xf; + final int y = (int) yf; + final ArrayList<WindowState> windows = mService.mWindows; + final int N = windows.size(); + for (int i = N - 1; i >= 0; i--) { + WindowState child = windows.get(i); + final int flags = child.mAttrs.flags; + if (!child.isVisibleLw()) { + // not visible == don't tell about drags + continue; + } + if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) { + // not touchable == don't tell about drags + continue; + } + + child.getTouchableRegion(mTmpRegion); + + final int touchFlags = flags & + (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); + if (mTmpRegion.contains(x, y) || touchFlags == 0) { + // Found it + touchedWin = child; + break; + } + } + + return touchedWin; + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/wm/FadeInOutAnimation.java b/services/java/com/android/server/wm/FadeInOutAnimation.java new file mode 100644 index 000000000000..06f76571b016 --- /dev/null +++ b/services/java/com/android/server/wm/FadeInOutAnimation.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011 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 com.android.server.wm; + +import android.view.animation.AccelerateInterpolator; +import android.view.animation.Animation; +import android.view.animation.Transformation; + +/** + * Animation that fade in after 0.5 interpolate time, or fade out in reverse order. + * This is used for opening/closing transition for apps in compatible mode. + */ +class FadeInOutAnimation extends Animation { + boolean mFadeIn; + + public FadeInOutAnimation(boolean fadeIn) { + setInterpolator(new AccelerateInterpolator()); + setDuration(WindowManagerService.DEFAULT_FADE_IN_OUT_DURATION); + mFadeIn = fadeIn; + } + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + float x = interpolatedTime; + if (!mFadeIn) { + x = 1.0f - x; // reverse the interpolation for fade out + } + t.setAlpha(x); + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/wm/InputApplicationHandle.java b/services/java/com/android/server/wm/InputApplicationHandle.java index c95e52580fee..64c8e7ed73db 100644 --- a/services/java/com/android/server/wm/InputApplicationHandle.java +++ b/services/java/com/android/server/wm/InputApplicationHandle.java @@ -30,11 +30,11 @@ public final class InputApplicationHandle { private int ptr; // The window manager's application window token. - public final WindowManagerService.AppWindowToken appWindowToken; + public final AppWindowToken appWindowToken; private native void nativeDispose(); - public InputApplicationHandle(WindowManagerService.AppWindowToken appWindowToken) { + public InputApplicationHandle(AppWindowToken appWindowToken) { this.appWindowToken = appWindowToken; } diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java new file mode 100644 index 000000000000..34f36184ba63 --- /dev/null +++ b/services/java/com/android/server/wm/InputMonitor.java @@ -0,0 +1,364 @@ +/** + * + */ +package com.android.server.wm; + +import android.graphics.Rect; +import android.os.Process; +import android.os.RemoteException; +import android.util.Log; +import android.util.Slog; +import android.view.KeyEvent; +import android.view.WindowManager; + +import java.util.ArrayList; + +final class InputMonitor { + private final WindowManagerService mService; + + // Current window with input focus for keys and other non-touch events. May be null. + private WindowState mInputFocus; + + // When true, prevents input dispatch from proceeding until set to false again. + private boolean mInputDispatchFrozen; + + // When true, input dispatch proceeds normally. Otherwise all events are dropped. + private boolean mInputDispatchEnabled = true; + + // When true, need to call updateInputWindowsLw(). + private boolean mUpdateInputWindowsNeeded = true; + + // Temporary list of windows information to provide to the input dispatcher. + private InputWindowList mTempInputWindows = new InputWindowList(); + + // Temporary input application object to provide to the input dispatcher. + private InputApplication mTempInputApplication = new InputApplication(); + + // Set to true when the first input device configuration change notification + // is received to indicate that the input devices are ready. + private final Object mInputDevicesReadyMonitor = new Object(); + private boolean mInputDevicesReady; + + public InputMonitor(WindowManagerService service) { + mService = service; + } + + /* Notifies the window manager about a broken input channel. + * + * Called by the InputManager. + */ + public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { + if (inputWindowHandle == null) { + return; + } + + synchronized (mService.mWindowMap) { + WindowState windowState = (WindowState) inputWindowHandle.windowState; + Slog.i(WindowManagerService.TAG, "WINDOW DIED " + windowState); + mService.removeWindowLocked(windowState.mSession, windowState); + } + } + + /* Notifies the window manager about an application that is not responding. + * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch. + * + * Called by the InputManager. + */ + public long notifyANR(InputApplicationHandle inputApplicationHandle, + InputWindowHandle inputWindowHandle) { + AppWindowToken appWindowToken = null; + if (inputWindowHandle != null) { + synchronized (mService.mWindowMap) { + WindowState windowState = (WindowState) inputWindowHandle.windowState; + if (windowState != null) { + Slog.i(WindowManagerService.TAG, "Input event dispatching timed out sending to " + + windowState.mAttrs.getTitle()); + appWindowToken = windowState.mAppToken; + } + } + } + + if (appWindowToken == null && inputApplicationHandle != null) { + appWindowToken = inputApplicationHandle.appWindowToken; + Slog.i(WindowManagerService.TAG, "Input event dispatching timed out sending to application " + + appWindowToken.stringName); + } + + if (appWindowToken != null && appWindowToken.appToken != null) { + try { + // Notify the activity manager about the timeout and let it decide whether + // to abort dispatching or keep waiting. + boolean abort = appWindowToken.appToken.keyDispatchingTimedOut(); + if (! abort) { + // The activity manager declined to abort dispatching. + // Wait a bit longer and timeout again later. + return appWindowToken.inputDispatchingTimeoutNanos; + } + } catch (RemoteException ex) { + } + } + return 0; // abort dispatching + } + + private void addDragInputWindowLw(InputWindowList windowList) { + final InputWindow inputWindow = windowList.add(); + inputWindow.inputChannel = mService.mDragState.mServerChannel; + inputWindow.name = "drag"; + inputWindow.layoutParamsFlags = 0; + inputWindow.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG; + inputWindow.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; + inputWindow.visible = true; + inputWindow.canReceiveKeys = false; + inputWindow.hasFocus = true; + inputWindow.hasWallpaper = false; + inputWindow.paused = false; + inputWindow.layer = mService.mDragState.getDragLayerLw(); + inputWindow.ownerPid = Process.myPid(); + inputWindow.ownerUid = Process.myUid(); + + // The drag window covers the entire display + inputWindow.frameLeft = 0; + inputWindow.frameTop = 0; + inputWindow.frameRight = mService.mDisplay.getWidth(); + inputWindow.frameBottom = mService.mDisplay.getHeight(); + + // The drag window cannot receive new touches. + inputWindow.touchableRegion.setEmpty(); + } + + public void setUpdateInputWindowsNeededLw() { + mUpdateInputWindowsNeeded = true; + } + + /* Updates the cached window information provided to the input dispatcher. */ + public void updateInputWindowsLw(boolean force) { + if (!force && !mUpdateInputWindowsNeeded) { + return; + } + mUpdateInputWindowsNeeded = false; + + // Populate the input window list with information about all of the windows that + // could potentially receive input. + // As an optimization, we could try to prune the list of windows but this turns + // out to be difficult because only the native code knows for sure which window + // currently has touch focus. + final ArrayList<WindowState> windows = mService.mWindows; + + // If there's a drag in flight, provide a pseudowindow to catch drag input + final boolean inDrag = (mService.mDragState != null); + if (inDrag) { + if (WindowManagerService.DEBUG_DRAG) { + Log.d(WindowManagerService.TAG, "Inserting drag window"); + } + addDragInputWindowLw(mTempInputWindows); + } + + final int N = windows.size(); + for (int i = N - 1; i >= 0; i--) { + final WindowState child = windows.get(i); + if (child.mInputChannel == null || child.mRemoved) { + // Skip this window because it cannot possibly receive input. + continue; + } + + final int flags = child.mAttrs.flags; + final int type = child.mAttrs.type; + + final boolean hasFocus = (child == mInputFocus); + final boolean isVisible = child.isVisibleLw(); + final boolean hasWallpaper = (child == mService.mWallpaperTarget) + && (type != WindowManager.LayoutParams.TYPE_KEYGUARD); + + // If there's a drag in progress and 'child' is a potential drop target, + // make sure it's been told about the drag + if (inDrag && isVisible) { + mService.mDragState.sendDragStartedIfNeededLw(child); + } + + // Add a window to our list of input windows. + final InputWindow inputWindow = mTempInputWindows.add(); + inputWindow.inputWindowHandle = child.mInputWindowHandle; + inputWindow.inputChannel = child.mInputChannel; + inputWindow.name = child.toString(); + inputWindow.layoutParamsFlags = flags; + inputWindow.layoutParamsType = type; + inputWindow.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos(); + inputWindow.visible = isVisible; + inputWindow.canReceiveKeys = child.canReceiveKeys(); + inputWindow.hasFocus = hasFocus; + inputWindow.hasWallpaper = hasWallpaper; + inputWindow.paused = child.mAppToken != null ? child.mAppToken.paused : false; + inputWindow.layer = child.mLayer; + inputWindow.ownerPid = child.mSession.mPid; + inputWindow.ownerUid = child.mSession.mUid; + + final Rect frame = child.mFrame; + inputWindow.frameLeft = frame.left; + inputWindow.frameTop = frame.top; + inputWindow.frameRight = frame.right; + inputWindow.frameBottom = frame.bottom; + + child.getTouchableRegion(inputWindow.touchableRegion); + } + + // Send windows to native code. + mService.mInputManager.setInputWindows(mTempInputWindows.toNullTerminatedArray()); + + // Clear the list in preparation for the next round. + // Also avoids keeping InputChannel objects referenced unnecessarily. + mTempInputWindows.clear(); + } + + /* Notifies that the input device configuration has changed. */ + public void notifyConfigurationChanged() { + mService.sendNewConfiguration(); + + synchronized (mInputDevicesReadyMonitor) { + if (!mInputDevicesReady) { + mInputDevicesReady = true; + mInputDevicesReadyMonitor.notifyAll(); + } + } + } + + /* Waits until the built-in input devices have been configured. */ + public boolean waitForInputDevicesReady(long timeoutMillis) { + synchronized (mInputDevicesReadyMonitor) { + if (!mInputDevicesReady) { + try { + mInputDevicesReadyMonitor.wait(timeoutMillis); + } catch (InterruptedException ex) { + } + } + return mInputDevicesReady; + } + } + + /* Notifies that the lid switch changed state. */ + public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { + mService.mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen); + } + + /* Provides an opportunity for the window manager policy to intercept early key + * processing as soon as the key has been read from the device. */ + public int interceptKeyBeforeQueueing( + KeyEvent event, int policyFlags, boolean isScreenOn) { + return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn); + } + + /* Provides an opportunity for the window manager policy to process a key before + * ordinary dispatch. */ + public boolean interceptKeyBeforeDispatching( + InputWindowHandle focus, KeyEvent event, int policyFlags) { + WindowState windowState = focus != null ? (WindowState) focus.windowState : null; + return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags); + } + + /* Provides an opportunity for the window manager policy to process a key that + * the application did not handle. */ + public KeyEvent dispatchUnhandledKey( + InputWindowHandle focus, KeyEvent event, int policyFlags) { + WindowState windowState = focus != null ? (WindowState) focus.windowState : null; + return mService.mPolicy.dispatchUnhandledKey(windowState, event, policyFlags); + } + + /* Called when the current input focus changes. + * Layer assignment is assumed to be complete by the time this is called. + */ + public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) { + if (WindowManagerService.DEBUG_INPUT) { + Slog.d(WindowManagerService.TAG, "Input focus has changed to " + newWindow); + } + + if (newWindow != mInputFocus) { + if (newWindow != null && newWindow.canReceiveKeys()) { + // Displaying a window implicitly causes dispatching to be unpaused. + // This is to protect against bugs if someone pauses dispatching but + // forgets to resume. + newWindow.mToken.paused = false; + } + + mInputFocus = newWindow; + setUpdateInputWindowsNeededLw(); + + if (updateInputWindows) { + updateInputWindowsLw(false /*force*/); + } + } + } + + public void setFocusedAppLw(AppWindowToken newApp) { + // Focused app has changed. + if (newApp == null) { + mService.mInputManager.setFocusedApplication(null); + } else { + mTempInputApplication.inputApplicationHandle = newApp.mInputApplicationHandle; + mTempInputApplication.name = newApp.toString(); + mTempInputApplication.dispatchingTimeoutNanos = + newApp.inputDispatchingTimeoutNanos; + + mService.mInputManager.setFocusedApplication(mTempInputApplication); + + mTempInputApplication.recycle(); + } + } + + public void pauseDispatchingLw(WindowToken window) { + if (! window.paused) { + if (WindowManagerService.DEBUG_INPUT) { + Slog.v(WindowManagerService.TAG, "Pausing WindowToken " + window); + } + + window.paused = true; + updateInputWindowsLw(true /*force*/); + } + } + + public void resumeDispatchingLw(WindowToken window) { + if (window.paused) { + if (WindowManagerService.DEBUG_INPUT) { + Slog.v(WindowManagerService.TAG, "Resuming WindowToken " + window); + } + + window.paused = false; + updateInputWindowsLw(true /*force*/); + } + } + + public void freezeInputDispatchingLw() { + if (! mInputDispatchFrozen) { + if (WindowManagerService.DEBUG_INPUT) { + Slog.v(WindowManagerService.TAG, "Freezing input dispatching"); + } + + mInputDispatchFrozen = true; + updateInputDispatchModeLw(); + } + } + + public void thawInputDispatchingLw() { + if (mInputDispatchFrozen) { + if (WindowManagerService.DEBUG_INPUT) { + Slog.v(WindowManagerService.TAG, "Thawing input dispatching"); + } + + mInputDispatchFrozen = false; + updateInputDispatchModeLw(); + } + } + + public void setEventDispatchingLw(boolean enabled) { + if (mInputDispatchEnabled != enabled) { + if (WindowManagerService.DEBUG_INPUT) { + Slog.v(WindowManagerService.TAG, "Setting event dispatching to " + enabled); + } + + mInputDispatchEnabled = enabled; + updateInputDispatchModeLw(); + } + } + + private void updateInputDispatchModeLw() { + mService.mInputManager.setInputDispatchMode(mInputDispatchEnabled, mInputDispatchFrozen); + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java index fc9f10ec850d..4356ce5ae427 100644 --- a/services/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java @@ -14,8 +14,7 @@ * limitations under the License. */ -package com.android.server.wm; // TODO: use com.android.server.wm, once things move there - +package com.android.server.wm; import android.content.Context; import android.graphics.Bitmap; diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java new file mode 100644 index 000000000000..b9db17702a81 --- /dev/null +++ b/services/java/com/android/server/wm/Session.java @@ -0,0 +1,419 @@ +/* + * Copyright (C) 2011 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 com.android.server.wm; + +import com.android.internal.view.IInputContext; +import com.android.internal.view.IInputMethodClient; +import com.android.internal.view.IInputMethodManager; +import com.android.server.wm.WindowManagerService.H; + +import android.content.ClipData; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.graphics.Region; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Parcel; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Slog; +import android.view.IWindow; +import android.view.IWindowSession; +import android.view.InputChannel; +import android.view.Surface; +import android.view.SurfaceSession; +import android.view.WindowManager; + +import java.io.PrintWriter; + +/** + * This class represents an active client session. There is generally one + * Session object per process that is interacting with the window manager. + */ +final class Session extends IWindowSession.Stub + implements IBinder.DeathRecipient { + final WindowManagerService mService; + final IInputMethodClient mClient; + final IInputContext mInputContext; + final int mUid; + final int mPid; + final String mStringName; + SurfaceSession mSurfaceSession; + int mNumWindow = 0; + boolean mClientDead = false; + + public Session(WindowManagerService service, IInputMethodClient client, + IInputContext inputContext) { + mService = service; + mClient = client; + mInputContext = inputContext; + mUid = Binder.getCallingUid(); + mPid = Binder.getCallingPid(); + StringBuilder sb = new StringBuilder(); + sb.append("Session{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" uid "); + sb.append(mUid); + sb.append("}"); + mStringName = sb.toString(); + + synchronized (mService.mWindowMap) { + if (mService.mInputMethodManager == null && mService.mHaveInputMethods) { + IBinder b = ServiceManager.getService( + Context.INPUT_METHOD_SERVICE); + mService.mInputMethodManager = IInputMethodManager.Stub.asInterface(b); + } + } + long ident = Binder.clearCallingIdentity(); + try { + // Note: it is safe to call in to the input method manager + // here because we are not holding our lock. + if (mService.mInputMethodManager != null) { + mService.mInputMethodManager.addClient(client, inputContext, + mUid, mPid); + } else { + client.setUsingInputMethod(false); + } + client.asBinder().linkToDeath(this, 0); + } catch (RemoteException e) { + // The caller has died, so we can just forget about this. + try { + if (mService.mInputMethodManager != null) { + mService.mInputMethodManager.removeClient(client); + } + } catch (RemoteException ee) { + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + try { + return super.onTransact(code, data, reply, flags); + } catch (RuntimeException e) { + // Log all 'real' exceptions thrown to the caller + if (!(e instanceof SecurityException)) { + Slog.e(WindowManagerService.TAG, "Window Session Crash", e); + } + throw e; + } + } + + public void binderDied() { + // Note: it is safe to call in to the input method manager + // here because we are not holding our lock. + try { + if (mService.mInputMethodManager != null) { + mService.mInputMethodManager.removeClient(mClient); + } + } catch (RemoteException e) { + } + synchronized(mService.mWindowMap) { + mClient.asBinder().unlinkToDeath(this, 0); + mClientDead = true; + killSessionLocked(); + } + } + + public int add(IWindow window, WindowManager.LayoutParams attrs, + int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) { + return mService.addWindow(this, window, attrs, viewVisibility, outContentInsets, + outInputChannel); + } + + public int addWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs, + int viewVisibility, Rect outContentInsets) { + return mService.addWindow(this, window, attrs, viewVisibility, outContentInsets, null); + } + + public void remove(IWindow window) { + mService.removeWindow(this, window); + } + + public int relayout(IWindow window, WindowManager.LayoutParams attrs, + int requestedWidth, int requestedHeight, int viewFlags, + boolean insetsPending, Rect outFrame, Rect outContentInsets, + Rect outVisibleInsets, Configuration outConfig, Surface outSurface) { + //Log.d(TAG, ">>>>>> ENTERED relayout from " + Binder.getCallingPid()); + int res = mService.relayoutWindow(this, window, attrs, + requestedWidth, requestedHeight, viewFlags, insetsPending, + outFrame, outContentInsets, outVisibleInsets, outConfig, outSurface); + //Log.d(TAG, "<<<<<< EXITING relayout to " + Binder.getCallingPid()); + return res; + } + + public void setTransparentRegion(IWindow window, Region region) { + mService.setTransparentRegionWindow(this, window, region); + } + + public void setInsets(IWindow window, int touchableInsets, + Rect contentInsets, Rect visibleInsets, Region touchableArea) { + mService.setInsetsWindow(this, window, touchableInsets, contentInsets, + visibleInsets, touchableArea); + } + + public void getDisplayFrame(IWindow window, Rect outDisplayFrame) { + mService.getWindowDisplayFrame(this, window, outDisplayFrame); + } + + public void finishDrawing(IWindow window) { + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "IWindow finishDrawing called for " + window); + mService.finishDrawingWindow(this, window); + } + + public void setInTouchMode(boolean mode) { + synchronized(mService.mWindowMap) { + mService.mInTouchMode = mode; + } + } + + public boolean getInTouchMode() { + synchronized(mService.mWindowMap) { + return mService.mInTouchMode; + } + } + + public boolean performHapticFeedback(IWindow window, int effectId, + boolean always) { + synchronized(mService.mWindowMap) { + long ident = Binder.clearCallingIdentity(); + try { + return mService.mPolicy.performHapticFeedbackLw( + mService.windowForClientLocked(this, window, true), + effectId, always); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + /* Drag/drop */ + public IBinder prepareDrag(IWindow window, int flags, + int width, int height, Surface outSurface) { + return mService.prepareDragSurface(window, mSurfaceSession, flags, + width, height, outSurface); + } + + public boolean performDrag(IWindow window, IBinder dragToken, + float touchX, float touchY, float thumbCenterX, float thumbCenterY, + ClipData data) { + if (WindowManagerService.DEBUG_DRAG) { + Slog.d(WindowManagerService.TAG, "perform drag: win=" + window + " data=" + data); + } + + synchronized (mService.mWindowMap) { + if (mService.mDragState == null) { + Slog.w(WindowManagerService.TAG, "No drag prepared"); + throw new IllegalStateException("performDrag() without prepareDrag()"); + } + + if (dragToken != mService.mDragState.mToken) { + Slog.w(WindowManagerService.TAG, "Performing mismatched drag"); + throw new IllegalStateException("performDrag() does not match prepareDrag()"); + } + + WindowState callingWin = mService.windowForClientLocked(null, window, false); + if (callingWin == null) { + Slog.w(WindowManagerService.TAG, "Bad requesting window " + window); + return false; // !!! TODO: throw here? + } + + // !!! TODO: if input is not still focused on the initiating window, fail + // the drag initiation (e.g. an alarm window popped up just as the application + // called performDrag() + + mService.mH.removeMessages(H.DRAG_START_TIMEOUT, window.asBinder()); + + // !!! TODO: extract the current touch (x, y) in screen coordinates. That + // will let us eliminate the (touchX,touchY) parameters from the API. + + // !!! FIXME: put all this heavy stuff onto the mH looper, as well as + // the actual drag event dispatch stuff in the dragstate + + mService.mDragState.register(); + mService.mInputMonitor.updateInputWindowsLw(true /*force*/); + if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel, + mService.mDragState.mServerChannel)) { + Slog.e(WindowManagerService.TAG, "Unable to transfer touch focus"); + mService.mDragState.unregister(); + mService.mDragState = null; + mService.mInputMonitor.updateInputWindowsLw(true /*force*/); + return false; + } + + mService.mDragState.mData = data; + mService.mDragState.mCurrentX = touchX; + mService.mDragState.mCurrentY = touchY; + mService.mDragState.broadcastDragStartedLw(touchX, touchY); + + // remember the thumb offsets for later + mService.mDragState.mThumbOffsetX = thumbCenterX; + mService.mDragState.mThumbOffsetY = thumbCenterY; + + // Make the surface visible at the proper location + final Surface surface = mService.mDragState.mSurface; + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, ">>> OPEN TRANSACTION performDrag"); + Surface.openTransaction(); + try { + surface.setPosition((int)(touchX - thumbCenterX), + (int)(touchY - thumbCenterY)); + surface.setAlpha(.7071f); + surface.setLayer(mService.mDragState.getDragLayerLw()); + surface.show(); + } finally { + Surface.closeTransaction(); + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "<<< CLOSE TRANSACTION performDrag"); + } + } + + return true; // success! + } + + public void reportDropResult(IWindow window, boolean consumed) { + IBinder token = window.asBinder(); + if (WindowManagerService.DEBUG_DRAG) { + Slog.d(WindowManagerService.TAG, "Drop result=" + consumed + " reported by " + token); + } + + synchronized (mService.mWindowMap) { + long ident = Binder.clearCallingIdentity(); + try { + if (mService.mDragState == null || mService.mDragState.mToken != token) { + Slog.w(WindowManagerService.TAG, "Invalid drop-result claim by " + window); + throw new IllegalStateException("reportDropResult() by non-recipient"); + } + + // The right window has responded, even if it's no longer around, + // so be sure to halt the timeout even if the later WindowState + // lookup fails. + mService.mH.removeMessages(H.DRAG_END_TIMEOUT, window.asBinder()); + WindowState callingWin = mService.windowForClientLocked(null, window, false); + if (callingWin == null) { + Slog.w(WindowManagerService.TAG, "Bad result-reporting window " + window); + return; // !!! TODO: throw here? + } + + mService.mDragState.mDragResult = consumed; + mService.mDragState.endDragLw(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + public void dragRecipientEntered(IWindow window) { + if (WindowManagerService.DEBUG_DRAG) { + Slog.d(WindowManagerService.TAG, "Drag into new candidate view @ " + window.asBinder()); + } + } + + public void dragRecipientExited(IWindow window) { + if (WindowManagerService.DEBUG_DRAG) { + Slog.d(WindowManagerService.TAG, "Drag from old candidate view @ " + window.asBinder()); + } + } + + public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) { + synchronized(mService.mWindowMap) { + long ident = Binder.clearCallingIdentity(); + try { + mService.setWindowWallpaperPositionLocked( + mService.windowForClientLocked(this, window, true), + x, y, xStep, yStep); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + public void wallpaperOffsetsComplete(IBinder window) { + mService.wallpaperOffsetsComplete(window); + } + + public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y, + int z, Bundle extras, boolean sync) { + synchronized(mService.mWindowMap) { + long ident = Binder.clearCallingIdentity(); + try { + return mService.sendWindowWallpaperCommandLocked( + mService.windowForClientLocked(this, window, true), + action, x, y, z, extras, sync); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + public void wallpaperCommandComplete(IBinder window, Bundle result) { + mService.wallpaperCommandComplete(window, result); + } + + void windowAddedLocked() { + if (mSurfaceSession == null) { + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "First window added to " + this + ", creating SurfaceSession"); + mSurfaceSession = new SurfaceSession(); + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i( + WindowManagerService.TAG, " NEW SURFACE SESSION " + mSurfaceSession); + mService.mSessions.add(this); + } + mNumWindow++; + } + + void windowRemovedLocked() { + mNumWindow--; + killSessionLocked(); + } + + void killSessionLocked() { + if (mNumWindow <= 0 && mClientDead) { + mService.mSessions.remove(this); + if (mSurfaceSession != null) { + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Last window removed from " + this + + ", destroying " + mSurfaceSession); + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i( + WindowManagerService.TAG, " KILL SURFACE SESSION " + mSurfaceSession); + try { + mSurfaceSession.kill(); + } catch (Exception e) { + Slog.w(WindowManagerService.TAG, "Exception thrown when killing surface session " + + mSurfaceSession + " in session " + this + + ": " + e.toString()); + } + mSurfaceSession = null; + } + } + } + + void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow); + pw.print(" mClientDead="); pw.print(mClientDead); + pw.print(" mSurfaceSession="); pw.println(mSurfaceSession); + } + + @Override + public String toString() { + return mStringName; + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/wm/StartingData.java b/services/java/com/android/server/wm/StartingData.java new file mode 100644 index 000000000000..625fcfeb27d6 --- /dev/null +++ b/services/java/com/android/server/wm/StartingData.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2011 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 com.android.server.wm; + +final class StartingData { + final String pkg; + final int theme; + final CharSequence nonLocalizedLabel; + final int labelRes; + final int icon; + final int windowFlags; + + StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel, + int _labelRes, int _icon, int _windowFlags) { + pkg = _pkg; + theme = _theme; + nonLocalizedLabel = _nonLocalizedLabel; + labelRes = _labelRes; + icon = _icon; + windowFlags = _windowFlags; + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/wm/StrictModeFlash.java b/services/java/com/android/server/wm/StrictModeFlash.java index 2aa45ac27223..2c62080ea7d2 100644 --- a/services/java/com/android/server/wm/StrictModeFlash.java +++ b/services/java/com/android/server/wm/StrictModeFlash.java @@ -14,13 +14,12 @@ * limitations under the License. */ -package com.android.server.wm; // TODO: use com.android.server.wm, once things move there +package com.android.server.wm; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PixelFormat; -import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Region; import android.util.DisplayMetrics; diff --git a/services/java/com/android/server/wm/Watermark.java b/services/java/com/android/server/wm/Watermark.java new file mode 100644 index 000000000000..22126f3052ed --- /dev/null +++ b/services/java/com/android/server/wm/Watermark.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2011 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 com.android.server.wm; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.graphics.Paint.FontMetricsInt; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; +import android.view.Display; +import android.view.Surface; +import android.view.SurfaceSession; +import android.view.Surface.OutOfResourcesException; + +/** + * Displays a watermark on top of the window manager's windows. + */ +class Watermark { + final String[] mTokens; + final String mText; + final Paint mTextPaint; + final int mTextWidth; + final int mTextHeight; + final int mTextAscent; + final int mTextDescent; + final int mDeltaX; + final int mDeltaY; + + Surface mSurface; + int mLastDW; + int mLastDH; + boolean mDrawNeeded; + + Watermark(Display display, SurfaceSession session, String[] tokens) { + final DisplayMetrics dm = new DisplayMetrics(); + display.getMetrics(dm); + + if (false) { + Log.i(WindowManagerService.TAG, "*********************** WATERMARK"); + for (int i=0; i<tokens.length; i++) { + Log.i(WindowManagerService.TAG, " TOKEN #" + i + ": " + tokens[i]); + } + } + + mTokens = tokens; + + StringBuilder builder = new StringBuilder(32); + int len = mTokens[0].length(); + len = len & ~1; + for (int i=0; i<len; i+=2) { + int c1 = mTokens[0].charAt(i); + int c2 = mTokens[0].charAt(i+1); + if (c1 >= 'a' && c1 <= 'f') c1 = c1 - 'a' + 10; + else if (c1 >= 'A' && c1 <= 'F') c1 = c1 - 'A' + 10; + else c1 -= '0'; + if (c2 >= 'a' && c2 <= 'f') c2 = c2 - 'a' + 10; + else if (c2 >= 'A' && c2 <= 'F') c2 = c2 - 'A' + 10; + else c2 -= '0'; + builder.append((char)(255-((c1*16)+c2))); + } + mText = builder.toString(); + if (false) { + Log.i(WindowManagerService.TAG, "Final text: " + mText); + } + + int fontSize = WindowManagerService.getPropertyInt(tokens, 1, + TypedValue.COMPLEX_UNIT_DIP, 20, dm); + + mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mTextPaint.setTextSize(fontSize); + mTextPaint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD)); + + FontMetricsInt fm = mTextPaint.getFontMetricsInt(); + mTextWidth = (int)mTextPaint.measureText(mText); + mTextAscent = fm.ascent; + mTextDescent = fm.descent; + mTextHeight = fm.descent - fm.ascent; + + mDeltaX = WindowManagerService.getPropertyInt(tokens, 2, + TypedValue.COMPLEX_UNIT_PX, mTextWidth*2, dm); + mDeltaY = WindowManagerService.getPropertyInt(tokens, 3, + TypedValue.COMPLEX_UNIT_PX, mTextHeight*3, dm); + int shadowColor = WindowManagerService.getPropertyInt(tokens, 4, + TypedValue.COMPLEX_UNIT_PX, 0xb0000000, dm); + int color = WindowManagerService.getPropertyInt(tokens, 5, + TypedValue.COMPLEX_UNIT_PX, 0x60ffffff, dm); + int shadowRadius = WindowManagerService.getPropertyInt(tokens, 6, + TypedValue.COMPLEX_UNIT_PX, 7, dm); + int shadowDx = WindowManagerService.getPropertyInt(tokens, 8, + TypedValue.COMPLEX_UNIT_PX, 0, dm); + int shadowDy = WindowManagerService.getPropertyInt(tokens, 9, + TypedValue.COMPLEX_UNIT_PX, 0, dm); + + mTextPaint.setColor(color); + mTextPaint.setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor); + + try { + mSurface = new Surface(session, 0, + "WatermarkSurface", -1, 1, 1, PixelFormat.TRANSLUCENT, 0); + mSurface.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER*100); + mSurface.setPosition(0, 0); + mSurface.show(); + } catch (OutOfResourcesException e) { + } + } + + void positionSurface(int dw, int dh) { + if (mLastDW != dw || mLastDH != dh) { + mLastDW = dw; + mLastDH = dh; + mSurface.setSize(dw, dh); + mDrawNeeded = true; + } + } + + void drawIfNeeded() { + if (mDrawNeeded) { + final int dw = mLastDW; + final int dh = mLastDH; + + mDrawNeeded = false; + Rect dirty = new Rect(0, 0, dw, dh); + Canvas c = null; + try { + c = mSurface.lockCanvas(dirty); + } catch (IllegalArgumentException e) { + } catch (OutOfResourcesException e) { + } + if (c != null) { + c.drawColor(0, PorterDuff.Mode.CLEAR); + + int deltaX = mDeltaX; + int deltaY = mDeltaY; + + // deltaX shouldn't be close to a round fraction of our + // x step, or else things will line up too much. + int div = (dw+mTextWidth)/deltaX; + int rem = (dw+mTextWidth) - (div*deltaX); + int qdelta = deltaX/4; + if (rem < qdelta || rem > (deltaX-qdelta)) { + deltaX += deltaX/3; + } + + int y = -mTextHeight; + int x = -mTextWidth; + while (y < (dh+mTextHeight)) { + c.drawText(mText, x, y, mTextPaint); + x += deltaX; + if (x >= dw) { + x -= (dw+mTextWidth); + y += deltaY; + } + } + mSurface.unlockCanvasAndPost(c); + } + } + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 3183643da5d6..a598ce9ebcd6 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -22,7 +22,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; @@ -46,8 +45,6 @@ import com.android.server.AttributeCache; import com.android.server.EventLogTags; import com.android.server.PowerManagerService; import com.android.server.Watchdog; -import com.android.server.AttributeCache.Entry; -import com.android.server.Watchdog.Monitor; import com.android.server.am.BatteryStatsService; import android.Manifest; @@ -56,8 +53,6 @@ import android.app.IActivityManager; import android.app.StatusBarManager; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; -import android.content.ClipData; -import android.content.ClipDescription; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -65,17 +60,12 @@ import android.content.pm.ActivityInfo; 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.Matrix; -import android.graphics.Paint; import android.graphics.PixelFormat; -import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Region; -import android.graphics.Typeface; -import android.graphics.Paint.FontMetricsInt; import android.os.BatteryStats; import android.os.Binder; import android.os.Bundle; @@ -104,8 +94,6 @@ import android.util.Slog; import android.util.SparseIntArray; import android.util.TypedValue; import android.view.Display; -import android.view.DragEvent; -import android.view.Gravity; import android.view.IApplicationToken; import android.view.IOnKeyguardExitResult; import android.view.IRotationWatcher; @@ -122,13 +110,10 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.SurfaceSession; import android.view.View; -import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; -import android.view.Surface.OutOfResourcesException; import android.view.WindowManager.LayoutParams; -import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Transformation; @@ -225,7 +210,7 @@ public class WindowManagerService extends IWindowManager.Stub private static final int INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS = 1000; // Default input dispatching timeout in nanoseconds. - private static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L; + static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L; static final int UPDATE_FOCUS_NORMAL = 0; static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1; @@ -513,336 +498,8 @@ public class WindowManagerService extends IWindowManager.Stub boolean mTurnOnScreen; - /** - * Drag/drop state - */ - class DragState { - IBinder mToken; - Surface mSurface; - int mFlags; - IBinder mLocalWin; - ClipData mData; - ClipDescription mDataDescription; - boolean mDragResult; - float mCurrentX, mCurrentY; - float mThumbOffsetX, mThumbOffsetY; - InputChannel mServerChannel, mClientChannel; - WindowState mTargetWindow; - ArrayList<WindowState> mNotifiedWindows; - boolean mDragInProgress; - - private final Region mTmpRegion = new Region(); - - DragState(IBinder token, Surface surface, int flags, IBinder localWin) { - mToken = token; - mSurface = surface; - mFlags = flags; - mLocalWin = localWin; - mNotifiedWindows = new ArrayList<WindowState>(); - } - - void reset() { - if (mSurface != null) { - mSurface.destroy(); - } - mSurface = null; - mFlags = 0; - mLocalWin = null; - mToken = null; - mData = null; - mThumbOffsetX = mThumbOffsetY = 0; - mNotifiedWindows = null; - } - - void register() { - if (DEBUG_DRAG) Slog.d(TAG, "registering drag input channel"); - if (mClientChannel != null) { - Slog.e(TAG, "Duplicate register of drag input channel"); - } else { - InputChannel[] channels = InputChannel.openInputChannelPair("drag"); - mServerChannel = channels[0]; - mClientChannel = channels[1]; - mInputManager.registerInputChannel(mServerChannel, null); - InputQueue.registerInputChannel(mClientChannel, mDragInputHandler, - mH.getLooper().getQueue()); - } - } - - void unregister() { - if (DEBUG_DRAG) Slog.d(TAG, "unregistering drag input channel"); - if (mClientChannel == null) { - Slog.e(TAG, "Unregister of nonexistent drag input channel"); - } else { - mInputManager.unregisterInputChannel(mServerChannel); - InputQueue.unregisterInputChannel(mClientChannel); - mClientChannel.dispose(); - mServerChannel.dispose(); - mClientChannel = null; - mServerChannel = null; - } - } - - int getDragLayerLw() { - return mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_DRAG) - * TYPE_LAYER_MULTIPLIER - + TYPE_LAYER_OFFSET; - } - - /* call out to each visible window/session informing it about the drag - */ - void broadcastDragStartedLw(final float touchX, final float touchY) { - // Cache a base-class instance of the clip metadata so that parceling - // works correctly in calling out to the apps. - mDataDescription = (mData != null) ? mData.getDescription() : null; - mNotifiedWindows.clear(); - mDragInProgress = true; - - if (DEBUG_DRAG) { - Slog.d(TAG, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")"); - } - - final int N = mWindows.size(); - for (int i = 0; i < N; i++) { - sendDragStartedLw(mWindows.get(i), touchX, touchY, mDataDescription); - } - } - - /* helper - send a caller-provided event, presumed to be DRAG_STARTED, if the - * designated window is potentially a drop recipient. There are race situations - * around DRAG_ENDED broadcast, so we make sure that once we've declared that - * the drag has ended, we never send out another DRAG_STARTED for this drag action. - * - * This method clones the 'event' parameter if it's being delivered to the same - * process, so it's safe for the caller to call recycle() on the event afterwards. - */ - private void sendDragStartedLw(WindowState newWin, float touchX, float touchY, - ClipDescription desc) { - // Don't actually send the event if the drag is supposed to be pinned - // to the originating window but 'newWin' is not that window. - if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) { - final IBinder winBinder = newWin.mClient.asBinder(); - if (winBinder != mLocalWin) { - if (DEBUG_DRAG) { - Slog.d(TAG, "Not dispatching local DRAG_STARTED to " + newWin); - } - return; - } - } - - if (mDragInProgress && newWin.isPotentialDragTarget()) { - DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED, - touchX - newWin.mFrame.left, touchY - newWin.mFrame.top, - null, desc, null, false); - try { - newWin.mClient.dispatchDragEvent(event); - // track each window that we've notified that the drag is starting - mNotifiedWindows.add(newWin); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to drag-start window " + newWin); - } finally { - // if the callee was local, the dispatch has already recycled the event - if (Process.myPid() != newWin.mSession.mPid) { - event.recycle(); - } - } - } - } - - /* helper - construct and send a DRAG_STARTED event only if the window has not - * previously been notified, i.e. it became visible after the drag operation - * was begun. This is a rare case. - */ - private void sendDragStartedIfNeededLw(WindowState newWin) { - if (mDragInProgress) { - // If we have sent the drag-started, we needn't do so again - for (WindowState ws : mNotifiedWindows) { - if (ws == newWin) { - return; - } - } - if (DEBUG_DRAG) { - Slog.d(TAG, "need to send DRAG_STARTED to new window " + newWin); - } - sendDragStartedLw(newWin, mCurrentX, mCurrentY, mDataDescription); - } - } - - void broadcastDragEndedLw() { - if (DEBUG_DRAG) { - Slog.d(TAG, "broadcasting DRAG_ENDED"); - } - DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED, - 0, 0, null, null, null, mDragResult); - for (WindowState ws: mNotifiedWindows) { - try { - ws.mClient.dispatchDragEvent(evt); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to drag-end window " + ws); - } - } - mNotifiedWindows.clear(); - mDragInProgress = false; - evt.recycle(); - } - - void endDragLw() { - mDragState.broadcastDragEndedLw(); - - // stop intercepting input - mDragState.unregister(); - mInputMonitor.updateInputWindowsLw(true /*force*/); - - // free our resources and drop all the object references - mDragState.reset(); - mDragState = null; - - if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-drag rotation"); - boolean changed = setRotationUncheckedLocked( - WindowManagerPolicy.USE_LAST_ROTATION, 0, false); - if (changed) { - mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); - } - } - - void notifyMoveLw(float x, float y) { - final int myPid = Process.myPid(); - - // Move the surface to the given touch - if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION notifyMoveLw"); - Surface.openTransaction(); - try { - mSurface.setPosition((int)(x - mThumbOffsetX), (int)(y - mThumbOffsetY)); - if (SHOW_TRANSACTIONS) Slog.i(TAG, " DRAG " - + mSurface + ": pos=(" + - (int)(x - mThumbOffsetX) + "," + (int)(y - mThumbOffsetY) + ")"); - } finally { - Surface.closeTransaction(); - if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION notifyMoveLw"); - } - - // Tell the affected window - WindowState touchedWin = getTouchedWinAtPointLw(x, y); - if (touchedWin == null) { - if (DEBUG_DRAG) Slog.d(TAG, "No touched win at x=" + x + " y=" + y); - return; - } - if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) { - final IBinder touchedBinder = touchedWin.mClient.asBinder(); - if (touchedBinder != mLocalWin) { - // This drag is pinned only to the originating window, but the drag - // point is outside that window. Pretend it's over empty space. - touchedWin = null; - } - } - try { - // have we dragged over a new window? - if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) { - if (DEBUG_DRAG) { - Slog.d(TAG, "sending DRAG_EXITED to " + mTargetWindow); - } - // force DRAG_EXITED_EVENT if appropriate - DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_EXITED, - x - mTargetWindow.mFrame.left, y - mTargetWindow.mFrame.top, - null, null, null, false); - mTargetWindow.mClient.dispatchDragEvent(evt); - if (myPid != mTargetWindow.mSession.mPid) { - evt.recycle(); - } - } - if (touchedWin != null) { - if (false && DEBUG_DRAG) { - Slog.d(TAG, "sending DRAG_LOCATION to " + touchedWin); - } - DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_LOCATION, - x - touchedWin.mFrame.left, y - touchedWin.mFrame.top, - null, null, null, false); - touchedWin.mClient.dispatchDragEvent(evt); - if (myPid != touchedWin.mSession.mPid) { - evt.recycle(); - } - } - } catch (RemoteException e) { - Slog.w(TAG, "can't send drag notification to windows"); - } - mTargetWindow = touchedWin; - } - - // Tell the drop target about the data. Returns 'true' if we can immediately - // dispatch the global drag-ended message, 'false' if we need to wait for a - // result from the recipient. - boolean notifyDropLw(float x, float y) { - WindowState touchedWin = getTouchedWinAtPointLw(x, y); - if (touchedWin == null) { - // "drop" outside a valid window -- no recipient to apply a - // timeout to, and we can send the drag-ended message immediately. - mDragResult = false; - return true; - } - - if (DEBUG_DRAG) { - Slog.d(TAG, "sending DROP to " + touchedWin); - } - final int myPid = Process.myPid(); - final IBinder token = touchedWin.mClient.asBinder(); - DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DROP, - x - touchedWin.mFrame.left, y - touchedWin.mFrame.top, - null, null, mData, false); - try { - touchedWin.mClient.dispatchDragEvent(evt); - - // 5 second timeout for this window to respond to the drop - mH.removeMessages(H.DRAG_END_TIMEOUT, token); - Message msg = mH.obtainMessage(H.DRAG_END_TIMEOUT, token); - mH.sendMessageDelayed(msg, 5000); - } catch (RemoteException e) { - Slog.w(TAG, "can't send drop notification to win " + touchedWin); - return true; - } finally { - if (myPid != touchedWin.mSession.mPid) { - evt.recycle(); - } - } - mToken = token; - return false; - } - - // Find the visible, touch-deliverable window under the given point - private WindowState getTouchedWinAtPointLw(float xf, float yf) { - WindowState touchedWin = null; - final int x = (int) xf; - final int y = (int) yf; - final ArrayList<WindowState> windows = mWindows; - final int N = windows.size(); - for (int i = N - 1; i >= 0; i--) { - WindowState child = windows.get(i); - final int flags = child.mAttrs.flags; - if (!child.isVisibleLw()) { - // not visible == don't tell about drags - continue; - } - if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) { - // not touchable == don't tell about drags - continue; - } - - child.getTouchableRegion(mTmpRegion); - - final int touchFlags = flags & - (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); - if (mTmpRegion.contains(x, y) || touchFlags == 0) { - // Found it - touchedWin = child; - break; - } - } - - return touchedWin; - } - } - DragState mDragState = null; - private final InputHandler mDragInputHandler = new BaseInputHandler() { + final InputHandler mDragInputHandler = new BaseInputHandler() { @Override public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) { boolean handled = false; @@ -2306,7 +1963,7 @@ public class WindowManagerService extends IWindowManager.Stub + attrs.token + ". Aborting."); return WindowManagerImpl.ADD_BAD_APP_TOKEN; } - token = new WindowToken(attrs.token, -1, false); + token = new WindowToken(this, attrs.token, -1, false); addToken = true; } else if (attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW) { @@ -2340,7 +1997,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - win = new WindowState(session, client, token, + win = new WindowState(this, session, client, token, attachedWindow, attrs, viewVisibility); if (win.mDeathRecipient == null) { // Client has apparently died, so there is no reason to @@ -2638,7 +2295,7 @@ public class WindowManagerService extends IWindowManager.Stub mInputMonitor.updateInputWindowsLw(true /*force*/); } - private static void logSurface(WindowState w, String msg, RuntimeException where) { + static void logSurface(WindowState w, String msg, RuntimeException where) { String str = " SURFACE " + Integer.toHexString(w.hashCode()) + ": " + msg + " / " + w.mAttrs.getTitle(); if (where != null) { @@ -2648,7 +2305,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - private void setTransparentRegionWindow(Session session, IWindow client, Region region) { + void setTransparentRegionWindow(Session session, IWindow client, Region region) { long origId = Binder.clearCallingIdentity(); try { synchronized (mWindowMap) { @@ -3102,7 +2759,7 @@ public class WindowManagerService extends IWindowManager.Stub return null; } - private void applyEnterAnimationLocked(WindowState win) { + void applyEnterAnimationLocked(WindowState win) { int transit = WindowManagerPolicy.TRANSIT_SHOW; if (win.mEnterAnimationPending) { win.mEnterAnimationPending = false; @@ -3112,7 +2769,7 @@ public class WindowManagerService extends IWindowManager.Stub applyAnimationLocked(win, transit, true); } - private boolean applyAnimationLocked(WindowState win, + boolean applyAnimationLocked(WindowState win, int transit, boolean isEntrance) { if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) { // If we are trying to apply an animation, but already running @@ -3368,7 +3025,7 @@ public class WindowManagerService extends IWindowManager.Stub Slog.w(TAG, "Attempted to add existing input method token: " + token); return; } - wtoken = new WindowToken(token, type, true); + wtoken = new WindowToken(this, token, type, true); mTokenMap.put(token, wtoken); if (type == TYPE_WALLPAPER) { mWallpaperTokens.add(wtoken); @@ -3456,7 +3113,7 @@ public class WindowManagerService extends IWindowManager.Stub Slog.w(TAG, "Attempted to add existing app token: " + token); return; } - wtoken = new AppWindowToken(token); + wtoken = new AppWindowToken(this, token); wtoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos; wtoken.groupId = groupId; wtoken.appFullscreen = fullscreen; @@ -5584,7 +5241,7 @@ public class WindowManagerService extends IWindowManager.Stub parameters = ""; } - final WindowManagerService.WindowState window = findWindow(hashCode); + final WindowState window = findWindow(hashCode); if (window == null) { return false; } @@ -5895,7 +5552,7 @@ public class WindowManagerService extends IWindowManager.Stub outSurface.copyFrom(surface); final IBinder winBinder = window.asBinder(); token = new Binder(); - mDragState = new DragState(token, surface, /*flags*/ 0, winBinder); + mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder); mDragState.mSurface = surface; token = mDragState.mToken = new Binder(); @@ -5925,355 +5582,8 @@ public class WindowManagerService extends IWindowManager.Stub // Input Events and Focus Management // ------------------------------------------------------------- - InputMonitor mInputMonitor = new InputMonitor(); + final InputMonitor mInputMonitor = new InputMonitor(this); - /* Tracks the progress of input dispatch and ensures that input dispatch state - * is kept in sync with changes in window focus, visibility, registration, and - * other relevant Window Manager state transitions. */ - final class InputMonitor { - // Current window with input focus for keys and other non-touch events. May be null. - private WindowState mInputFocus; - - // When true, prevents input dispatch from proceeding until set to false again. - private boolean mInputDispatchFrozen; - - // When true, input dispatch proceeds normally. Otherwise all events are dropped. - private boolean mInputDispatchEnabled = true; - - // When true, need to call updateInputWindowsLw(). - private boolean mUpdateInputWindowsNeeded = true; - - // Temporary list of windows information to provide to the input dispatcher. - private InputWindowList mTempInputWindows = new InputWindowList(); - - // Temporary input application object to provide to the input dispatcher. - private InputApplication mTempInputApplication = new InputApplication(); - - // Set to true when the first input device configuration change notification - // is received to indicate that the input devices are ready. - private final Object mInputDevicesReadyMonitor = new Object(); - private boolean mInputDevicesReady; - - /* Notifies the window manager about a broken input channel. - * - * Called by the InputManager. - */ - public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { - if (inputWindowHandle == null) { - return; - } - - synchronized (mWindowMap) { - WindowState windowState = (WindowState) inputWindowHandle.windowState; - Slog.i(TAG, "WINDOW DIED " + windowState); - removeWindowLocked(windowState.mSession, windowState); - } - } - - /* Notifies the window manager about an application that is not responding. - * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch. - * - * Called by the InputManager. - */ - public long notifyANR(InputApplicationHandle inputApplicationHandle, - InputWindowHandle inputWindowHandle) { - AppWindowToken appWindowToken = null; - if (inputWindowHandle != null) { - synchronized (mWindowMap) { - WindowState windowState = (WindowState) inputWindowHandle.windowState; - if (windowState != null) { - Slog.i(TAG, "Input event dispatching timed out sending to " - + windowState.mAttrs.getTitle()); - appWindowToken = windowState.mAppToken; - } - } - } - - if (appWindowToken == null && inputApplicationHandle != null) { - appWindowToken = inputApplicationHandle.appWindowToken; - Slog.i(TAG, "Input event dispatching timed out sending to application " - + appWindowToken.stringName); - } - - if (appWindowToken != null && appWindowToken.appToken != null) { - try { - // Notify the activity manager about the timeout and let it decide whether - // to abort dispatching or keep waiting. - boolean abort = appWindowToken.appToken.keyDispatchingTimedOut(); - if (! abort) { - // The activity manager declined to abort dispatching. - // Wait a bit longer and timeout again later. - return appWindowToken.inputDispatchingTimeoutNanos; - } - } catch (RemoteException ex) { - } - } - return 0; // abort dispatching - } - - private void addDragInputWindowLw(InputWindowList windowList) { - final InputWindow inputWindow = windowList.add(); - inputWindow.inputChannel = mDragState.mServerChannel; - inputWindow.name = "drag"; - inputWindow.layoutParamsFlags = 0; - inputWindow.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG; - inputWindow.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; - inputWindow.visible = true; - inputWindow.canReceiveKeys = false; - inputWindow.hasFocus = true; - inputWindow.hasWallpaper = false; - inputWindow.paused = false; - inputWindow.layer = mDragState.getDragLayerLw(); - inputWindow.ownerPid = Process.myPid(); - inputWindow.ownerUid = Process.myUid(); - - // The drag window covers the entire display - inputWindow.frameLeft = 0; - inputWindow.frameTop = 0; - inputWindow.frameRight = mDisplay.getWidth(); - inputWindow.frameBottom = mDisplay.getHeight(); - - // The drag window cannot receive new touches. - inputWindow.touchableRegion.setEmpty(); - } - - public void setUpdateInputWindowsNeededLw() { - mUpdateInputWindowsNeeded = true; - } - - /* Updates the cached window information provided to the input dispatcher. */ - public void updateInputWindowsLw(boolean force) { - if (!force && !mUpdateInputWindowsNeeded) { - return; - } - mUpdateInputWindowsNeeded = false; - - // Populate the input window list with information about all of the windows that - // could potentially receive input. - // As an optimization, we could try to prune the list of windows but this turns - // out to be difficult because only the native code knows for sure which window - // currently has touch focus. - final ArrayList<WindowState> windows = mWindows; - - // If there's a drag in flight, provide a pseudowindow to catch drag input - final boolean inDrag = (mDragState != null); - if (inDrag) { - if (DEBUG_DRAG) { - Log.d(TAG, "Inserting drag window"); - } - addDragInputWindowLw(mTempInputWindows); - } - - final int N = windows.size(); - for (int i = N - 1; i >= 0; i--) { - final WindowState child = windows.get(i); - if (child.mInputChannel == null || child.mRemoved) { - // Skip this window because it cannot possibly receive input. - continue; - } - - final int flags = child.mAttrs.flags; - final int type = child.mAttrs.type; - - final boolean hasFocus = (child == mInputFocus); - final boolean isVisible = child.isVisibleLw(); - final boolean hasWallpaper = (child == mWallpaperTarget) - && (type != WindowManager.LayoutParams.TYPE_KEYGUARD); - - // If there's a drag in progress and 'child' is a potential drop target, - // make sure it's been told about the drag - if (inDrag && isVisible) { - mDragState.sendDragStartedIfNeededLw(child); - } - - // Add a window to our list of input windows. - final InputWindow inputWindow = mTempInputWindows.add(); - inputWindow.inputWindowHandle = child.mInputWindowHandle; - inputWindow.inputChannel = child.mInputChannel; - inputWindow.name = child.toString(); - inputWindow.layoutParamsFlags = flags; - inputWindow.layoutParamsType = type; - inputWindow.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos(); - inputWindow.visible = isVisible; - inputWindow.canReceiveKeys = child.canReceiveKeys(); - inputWindow.hasFocus = hasFocus; - inputWindow.hasWallpaper = hasWallpaper; - inputWindow.paused = child.mAppToken != null ? child.mAppToken.paused : false; - inputWindow.layer = child.mLayer; - inputWindow.ownerPid = child.mSession.mPid; - inputWindow.ownerUid = child.mSession.mUid; - - final Rect frame = child.mFrame; - inputWindow.frameLeft = frame.left; - inputWindow.frameTop = frame.top; - inputWindow.frameRight = frame.right; - inputWindow.frameBottom = frame.bottom; - - child.getTouchableRegion(inputWindow.touchableRegion); - } - - // Send windows to native code. - mInputManager.setInputWindows(mTempInputWindows.toNullTerminatedArray()); - - // Clear the list in preparation for the next round. - // Also avoids keeping InputChannel objects referenced unnecessarily. - mTempInputWindows.clear(); - } - - /* Notifies that the input device configuration has changed. */ - public void notifyConfigurationChanged() { - sendNewConfiguration(); - - synchronized (mInputDevicesReadyMonitor) { - if (!mInputDevicesReady) { - mInputDevicesReady = true; - mInputDevicesReadyMonitor.notifyAll(); - } - } - } - - /* Waits until the built-in input devices have been configured. */ - public boolean waitForInputDevicesReady(long timeoutMillis) { - synchronized (mInputDevicesReadyMonitor) { - if (!mInputDevicesReady) { - try { - mInputDevicesReadyMonitor.wait(timeoutMillis); - } catch (InterruptedException ex) { - } - } - return mInputDevicesReady; - } - } - - /* Notifies that the lid switch changed state. */ - public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { - mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen); - } - - /* Provides an opportunity for the window manager policy to intercept early key - * processing as soon as the key has been read from the device. */ - public int interceptKeyBeforeQueueing( - KeyEvent event, int policyFlags, boolean isScreenOn) { - return mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn); - } - - /* Provides an opportunity for the window manager policy to process a key before - * ordinary dispatch. */ - public boolean interceptKeyBeforeDispatching( - InputWindowHandle focus, KeyEvent event, int policyFlags) { - WindowState windowState = focus != null ? (WindowState) focus.windowState : null; - return mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags); - } - - /* Provides an opportunity for the window manager policy to process a key that - * the application did not handle. */ - public KeyEvent dispatchUnhandledKey( - InputWindowHandle focus, KeyEvent event, int policyFlags) { - WindowState windowState = focus != null ? (WindowState) focus.windowState : null; - return mPolicy.dispatchUnhandledKey(windowState, event, policyFlags); - } - - /* Called when the current input focus changes. - * Layer assignment is assumed to be complete by the time this is called. - */ - public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) { - if (DEBUG_INPUT) { - Slog.d(TAG, "Input focus has changed to " + newWindow); - } - - if (newWindow != mInputFocus) { - if (newWindow != null && newWindow.canReceiveKeys()) { - // Displaying a window implicitly causes dispatching to be unpaused. - // This is to protect against bugs if someone pauses dispatching but - // forgets to resume. - newWindow.mToken.paused = false; - } - - mInputFocus = newWindow; - setUpdateInputWindowsNeededLw(); - - if (updateInputWindows) { - updateInputWindowsLw(false /*force*/); - } - } - } - - public void setFocusedAppLw(AppWindowToken newApp) { - // Focused app has changed. - if (newApp == null) { - mInputManager.setFocusedApplication(null); - } else { - mTempInputApplication.inputApplicationHandle = newApp.mInputApplicationHandle; - mTempInputApplication.name = newApp.toString(); - mTempInputApplication.dispatchingTimeoutNanos = - newApp.inputDispatchingTimeoutNanos; - - mInputManager.setFocusedApplication(mTempInputApplication); - - mTempInputApplication.recycle(); - } - } - - public void pauseDispatchingLw(WindowToken window) { - if (! window.paused) { - if (DEBUG_INPUT) { - Slog.v(TAG, "Pausing WindowToken " + window); - } - - window.paused = true; - updateInputWindowsLw(true /*force*/); - } - } - - public void resumeDispatchingLw(WindowToken window) { - if (window.paused) { - if (DEBUG_INPUT) { - Slog.v(TAG, "Resuming WindowToken " + window); - } - - window.paused = false; - updateInputWindowsLw(true /*force*/); - } - } - - public void freezeInputDispatchingLw() { - if (! mInputDispatchFrozen) { - if (DEBUG_INPUT) { - Slog.v(TAG, "Freezing input dispatching"); - } - - mInputDispatchFrozen = true; - updateInputDispatchModeLw(); - } - } - - public void thawInputDispatchingLw() { - if (mInputDispatchFrozen) { - if (DEBUG_INPUT) { - Slog.v(TAG, "Thawing input dispatching"); - } - - mInputDispatchFrozen = false; - updateInputDispatchModeLw(); - } - } - - public void setEventDispatchingLw(boolean enabled) { - if (mInputDispatchEnabled != enabled) { - if (DEBUG_INPUT) { - Slog.v(TAG, "Setting event dispatching to " + enabled); - } - - mInputDispatchEnabled = enabled; - updateInputDispatchModeLw(); - } - } - - private void updateInputDispatchModeLw() { - mInputManager.setInputDispatchMode(mInputDispatchEnabled, mInputDispatchFrozen); - } - } - public void pauseKeyDispatching(IBinder _token) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "pauseKeyDispatching()")) { @@ -6502,2409 +5812,6 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.systemReady(); } - // ------------------------------------------------------------- - // Client Session State - // ------------------------------------------------------------- - - private final class Session extends IWindowSession.Stub - implements IBinder.DeathRecipient { - final IInputMethodClient mClient; - final IInputContext mInputContext; - final int mUid; - final int mPid; - final String mStringName; - SurfaceSession mSurfaceSession; - int mNumWindow = 0; - boolean mClientDead = false; - - public Session(IInputMethodClient client, IInputContext inputContext) { - mClient = client; - mInputContext = inputContext; - mUid = Binder.getCallingUid(); - mPid = Binder.getCallingPid(); - StringBuilder sb = new StringBuilder(); - sb.append("Session{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(" uid "); - sb.append(mUid); - sb.append("}"); - mStringName = sb.toString(); - - synchronized (mWindowMap) { - if (mInputMethodManager == null && mHaveInputMethods) { - IBinder b = ServiceManager.getService( - Context.INPUT_METHOD_SERVICE); - mInputMethodManager = IInputMethodManager.Stub.asInterface(b); - } - } - long ident = Binder.clearCallingIdentity(); - try { - // Note: it is safe to call in to the input method manager - // here because we are not holding our lock. - if (mInputMethodManager != null) { - mInputMethodManager.addClient(client, inputContext, - mUid, mPid); - } else { - client.setUsingInputMethod(false); - } - client.asBinder().linkToDeath(this, 0); - } catch (RemoteException e) { - // The caller has died, so we can just forget about this. - try { - if (mInputMethodManager != null) { - mInputMethodManager.removeClient(client); - } - } catch (RemoteException ee) { - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - try { - return super.onTransact(code, data, reply, flags); - } catch (RuntimeException e) { - // Log all 'real' exceptions thrown to the caller - if (!(e instanceof SecurityException)) { - Slog.e(TAG, "Window Session Crash", e); - } - throw e; - } - } - - public void binderDied() { - // Note: it is safe to call in to the input method manager - // here because we are not holding our lock. - try { - if (mInputMethodManager != null) { - mInputMethodManager.removeClient(mClient); - } - } catch (RemoteException e) { - } - synchronized(mWindowMap) { - mClient.asBinder().unlinkToDeath(this, 0); - mClientDead = true; - killSessionLocked(); - } - } - - public int add(IWindow window, WindowManager.LayoutParams attrs, - int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) { - return addWindow(this, window, attrs, viewVisibility, outContentInsets, - outInputChannel); - } - - public int addWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs, - int viewVisibility, Rect outContentInsets) { - return addWindow(this, window, attrs, viewVisibility, outContentInsets, null); - } - - public void remove(IWindow window) { - removeWindow(this, window); - } - - public int relayout(IWindow window, WindowManager.LayoutParams attrs, - int requestedWidth, int requestedHeight, int viewFlags, - boolean insetsPending, Rect outFrame, Rect outContentInsets, - Rect outVisibleInsets, Configuration outConfig, Surface outSurface) { - //Log.d(TAG, ">>>>>> ENTERED relayout from " + Binder.getCallingPid()); - int res = relayoutWindow(this, window, attrs, - requestedWidth, requestedHeight, viewFlags, insetsPending, - outFrame, outContentInsets, outVisibleInsets, outConfig, outSurface); - //Log.d(TAG, "<<<<<< EXITING relayout to " + Binder.getCallingPid()); - return res; - } - - public void setTransparentRegion(IWindow window, Region region) { - setTransparentRegionWindow(this, window, region); - } - - public void setInsets(IWindow window, int touchableInsets, - Rect contentInsets, Rect visibleInsets, Region touchableArea) { - setInsetsWindow(this, window, touchableInsets, contentInsets, - visibleInsets, touchableArea); - } - - public void getDisplayFrame(IWindow window, Rect outDisplayFrame) { - getWindowDisplayFrame(this, window, outDisplayFrame); - } - - public void finishDrawing(IWindow window) { - if (localLOGV) Slog.v( - TAG, "IWindow finishDrawing called for " + window); - finishDrawingWindow(this, window); - } - - public void setInTouchMode(boolean mode) { - synchronized(mWindowMap) { - mInTouchMode = mode; - } - } - - public boolean getInTouchMode() { - synchronized(mWindowMap) { - return mInTouchMode; - } - } - - public boolean performHapticFeedback(IWindow window, int effectId, - boolean always) { - synchronized(mWindowMap) { - long ident = Binder.clearCallingIdentity(); - try { - return mPolicy.performHapticFeedbackLw( - windowForClientLocked(this, window, true), - effectId, always); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - - /* Drag/drop */ - public IBinder prepareDrag(IWindow window, int flags, - int width, int height, Surface outSurface) { - return prepareDragSurface(window, mSurfaceSession, flags, - width, height, outSurface); - } - - public boolean performDrag(IWindow window, IBinder dragToken, - float touchX, float touchY, float thumbCenterX, float thumbCenterY, - ClipData data) { - if (DEBUG_DRAG) { - Slog.d(TAG, "perform drag: win=" + window + " data=" + data); - } - - synchronized (mWindowMap) { - if (mDragState == null) { - Slog.w(TAG, "No drag prepared"); - throw new IllegalStateException("performDrag() without prepareDrag()"); - } - - if (dragToken != mDragState.mToken) { - Slog.w(TAG, "Performing mismatched drag"); - throw new IllegalStateException("performDrag() does not match prepareDrag()"); - } - - WindowState callingWin = windowForClientLocked(null, window, false); - if (callingWin == null) { - Slog.w(TAG, "Bad requesting window " + window); - return false; // !!! TODO: throw here? - } - - // !!! TODO: if input is not still focused on the initiating window, fail - // the drag initiation (e.g. an alarm window popped up just as the application - // called performDrag() - - mH.removeMessages(H.DRAG_START_TIMEOUT, window.asBinder()); - - // !!! TODO: extract the current touch (x, y) in screen coordinates. That - // will let us eliminate the (touchX,touchY) parameters from the API. - - // !!! FIXME: put all this heavy stuff onto the mH looper, as well as - // the actual drag event dispatch stuff in the dragstate - - mDragState.register(); - mInputMonitor.updateInputWindowsLw(true /*force*/); - if (!mInputManager.transferTouchFocus(callingWin.mInputChannel, - mDragState.mServerChannel)) { - Slog.e(TAG, "Unable to transfer touch focus"); - mDragState.unregister(); - mDragState = null; - mInputMonitor.updateInputWindowsLw(true /*force*/); - return false; - } - - mDragState.mData = data; - mDragState.mCurrentX = touchX; - mDragState.mCurrentY = touchY; - mDragState.broadcastDragStartedLw(touchX, touchY); - - // remember the thumb offsets for later - mDragState.mThumbOffsetX = thumbCenterX; - mDragState.mThumbOffsetY = thumbCenterY; - - // Make the surface visible at the proper location - final Surface surface = mDragState.mSurface; - if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION performDrag"); - Surface.openTransaction(); - try { - surface.setPosition((int)(touchX - thumbCenterX), - (int)(touchY - thumbCenterY)); - surface.setAlpha(.7071f); - surface.setLayer(mDragState.getDragLayerLw()); - surface.show(); - } finally { - Surface.closeTransaction(); - if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION performDrag"); - } - } - - return true; // success! - } - - public void reportDropResult(IWindow window, boolean consumed) { - IBinder token = window.asBinder(); - if (DEBUG_DRAG) { - Slog.d(TAG, "Drop result=" + consumed + " reported by " + token); - } - - synchronized (mWindowMap) { - long ident = Binder.clearCallingIdentity(); - try { - if (mDragState == null || mDragState.mToken != token) { - Slog.w(TAG, "Invalid drop-result claim by " + window); - throw new IllegalStateException("reportDropResult() by non-recipient"); - } - - // The right window has responded, even if it's no longer around, - // so be sure to halt the timeout even if the later WindowState - // lookup fails. - mH.removeMessages(H.DRAG_END_TIMEOUT, window.asBinder()); - WindowState callingWin = windowForClientLocked(null, window, false); - if (callingWin == null) { - Slog.w(TAG, "Bad result-reporting window " + window); - return; // !!! TODO: throw here? - } - - mDragState.mDragResult = consumed; - mDragState.endDragLw(); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - - public void dragRecipientEntered(IWindow window) { - if (DEBUG_DRAG) { - Slog.d(TAG, "Drag into new candidate view @ " + window.asBinder()); - } - } - - public void dragRecipientExited(IWindow window) { - if (DEBUG_DRAG) { - Slog.d(TAG, "Drag from old candidate view @ " + window.asBinder()); - } - } - - public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) { - synchronized(mWindowMap) { - long ident = Binder.clearCallingIdentity(); - try { - setWindowWallpaperPositionLocked( - windowForClientLocked(this, window, true), - x, y, xStep, yStep); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - - public void wallpaperOffsetsComplete(IBinder window) { - WindowManagerService.this.wallpaperOffsetsComplete(window); - } - - public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y, - int z, Bundle extras, boolean sync) { - synchronized(mWindowMap) { - long ident = Binder.clearCallingIdentity(); - try { - return sendWindowWallpaperCommandLocked( - windowForClientLocked(this, window, true), - action, x, y, z, extras, sync); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - - public void wallpaperCommandComplete(IBinder window, Bundle result) { - WindowManagerService.this.wallpaperCommandComplete(window, result); - } - - void windowAddedLocked() { - if (mSurfaceSession == null) { - if (localLOGV) Slog.v( - TAG, "First window added to " + this + ", creating SurfaceSession"); - mSurfaceSession = new SurfaceSession(); - if (SHOW_TRANSACTIONS) Slog.i( - TAG, " NEW SURFACE SESSION " + mSurfaceSession); - mSessions.add(this); - } - mNumWindow++; - } - - void windowRemovedLocked() { - mNumWindow--; - killSessionLocked(); - } - - void killSessionLocked() { - if (mNumWindow <= 0 && mClientDead) { - mSessions.remove(this); - if (mSurfaceSession != null) { - if (localLOGV) Slog.v( - TAG, "Last window removed from " + this - + ", destroying " + mSurfaceSession); - if (SHOW_TRANSACTIONS) Slog.i( - TAG, " KILL SURFACE SESSION " + mSurfaceSession); - try { - mSurfaceSession.kill(); - } catch (Exception e) { - Slog.w(TAG, "Exception thrown when killing surface session " - + mSurfaceSession + " in session " + this - + ": " + e.toString()); - } - mSurfaceSession = null; - } - } - } - - void dump(PrintWriter pw, String prefix) { - pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow); - pw.print(" mClientDead="); pw.print(mClientDead); - pw.print(" mSurfaceSession="); pw.println(mSurfaceSession); - } - - @Override - public String toString() { - return mStringName; - } - } - - // ------------------------------------------------------------- - // Client Window State - // ------------------------------------------------------------- - - private final class WindowState implements WindowManagerPolicy.WindowState { - final Session mSession; - final IWindow mClient; - WindowToken mToken; - WindowToken mRootToken; - AppWindowToken mAppToken; - AppWindowToken mTargetAppToken; - final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams(); - final DeathRecipient mDeathRecipient; - final WindowState mAttachedWindow; - final ArrayList<WindowState> mChildWindows = new ArrayList<WindowState>(); - final int mBaseLayer; - final int mSubLayer; - final boolean mLayoutAttached; - final boolean mIsImWindow; - final boolean mIsWallpaper; - final boolean mIsFloatingLayer; - int mViewVisibility; - boolean mPolicyVisibility = true; - boolean mPolicyVisibilityAfterAnim = true; - boolean mAppFreezing; - Surface mSurface; - boolean mReportDestroySurface; - boolean mSurfacePendingDestroy; - boolean mAttachedHidden; // is our parent window hidden? - boolean mLastHidden; // was this window last hidden? - boolean mWallpaperVisible; // for wallpaper, what was last vis report? - int mRequestedWidth; - int mRequestedHeight; - int mLastRequestedWidth; - int mLastRequestedHeight; - int mLayer; - int mAnimLayer; - int mLastLayer; - boolean mHaveFrame; - boolean mObscured; - boolean mTurnOnScreen; - - int mLayoutSeq = -1; - - Configuration mConfiguration = null; - - // Actual frame shown on-screen (may be modified by animation) - final Rect mShownFrame = new Rect(); - final Rect mLastShownFrame = new Rect(); - - /** - * Set when we have changed the size of the surface, to know that - * we must tell them application to resize (and thus redraw itself). - */ - boolean mSurfaceResized; - - /** - * Insets that determine the actually visible area - */ - final Rect mVisibleInsets = new Rect(); - final Rect mLastVisibleInsets = new Rect(); - boolean mVisibleInsetsChanged; - - /** - * Insets that are covered by system windows - */ - final Rect mContentInsets = new Rect(); - final Rect mLastContentInsets = new Rect(); - boolean mContentInsetsChanged; - - /** - * Set to true if we are waiting for this window to receive its - * given internal insets before laying out other windows based on it. - */ - boolean mGivenInsetsPending; - - /** - * These are the content insets that were given during layout for - * this window, to be applied to windows behind it. - */ - final Rect mGivenContentInsets = new Rect(); - - /** - * These are the visible insets that were given during layout for - * this window, to be applied to windows behind it. - */ - final Rect mGivenVisibleInsets = new Rect(); - - /** - * This is the given touchable area relative to the window frame, or null if none. - */ - final Region mGivenTouchableRegion = new Region(); - - /** - * Flag indicating whether the touchable region should be adjusted by - * the visible insets; if false the area outside the visible insets is - * NOT touchable, so we must use those to adjust the frame during hit - * tests. - */ - int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; - - // Current transformation being applied. - boolean mHaveMatrix; - float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1; - float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1; - float mHScale=1, mVScale=1; - float mLastHScale=1, mLastVScale=1; - final Matrix mTmpMatrix = new Matrix(); - - // "Real" frame that the application sees. - final Rect mFrame = new Rect(); - final Rect mLastFrame = new Rect(); - - final Rect mContainingFrame = new Rect(); - final Rect mDisplayFrame = new Rect(); - final Rect mContentFrame = new Rect(); - final Rect mParentFrame = new Rect(); - final Rect mVisibleFrame = new Rect(); - - boolean mContentChanged; - - float mShownAlpha = 1; - float mAlpha = 1; - float mLastAlpha = 1; - - // Set to true if, when the window gets displayed, it should perform - // an enter animation. - boolean mEnterAnimationPending; - - // Currently running animation. - boolean mAnimating; - boolean mLocalAnimating; - Animation mAnimation; - boolean mAnimationIsEntrance; - boolean mHasTransformation; - boolean mHasLocalTransformation; - final Transformation mTransformation = new Transformation(); - - // If a window showing a wallpaper: the requested offset for the - // wallpaper; if a wallpaper window: the currently applied offset. - float mWallpaperX = -1; - float mWallpaperY = -1; - - // If a window showing a wallpaper: what fraction of the offset - // range corresponds to a full virtual screen. - float mWallpaperXStep = -1; - float mWallpaperYStep = -1; - - // Wallpaper windows: pixels offset based on above variables. - int mXOffset; - int mYOffset; - - // This is set after IWindowSession.relayout() has been called at - // least once for the window. It allows us to detect the situation - // where we don't yet have a surface, but should have one soon, so - // we can give the window focus before waiting for the relayout. - boolean mRelayoutCalled; - - // This is set after the Surface has been created but before the - // window has been drawn. During this time the surface is hidden. - boolean mDrawPending; - - // This is set after the window has finished drawing for the first - // time but before its surface is shown. The surface will be - // displayed when the next layout is run. - boolean mCommitDrawPending; - - // This is set during the time after the window's drawing has been - // committed, and before its surface is actually shown. It is used - // to delay showing the surface until all windows in a token are ready - // to be shown. - boolean mReadyToShow; - - // Set when the window has been shown in the screen the first time. - boolean mHasDrawn; - - // Currently running an exit animation? - boolean mExiting; - - // Currently on the mDestroySurface list? - boolean mDestroying; - - // Completely remove from window manager after exit animation? - boolean mRemoveOnExit; - - // Set when the orientation is changing and this window has not yet - // been updated for the new orientation. - boolean mOrientationChanging; - - // Is this window now (or just being) removed? - boolean mRemoved; - - // Temp for keeping track of windows that have been removed when - // rebuilding window list. - boolean mRebuilding; - - // For debugging, this is the last information given to the surface flinger. - boolean mSurfaceShown; - int mSurfaceX, mSurfaceY, mSurfaceW, mSurfaceH; - int mSurfaceLayer; - float mSurfaceAlpha; - - // Input channel and input window handle used by the input dispatcher. - InputWindowHandle mInputWindowHandle; - InputChannel mInputChannel; - - // Used to improve performance of toString() - String mStringNameCache; - CharSequence mLastTitle; - boolean mWasPaused; - - WindowState(Session s, IWindow c, WindowToken token, - WindowState attachedWindow, WindowManager.LayoutParams a, - int viewVisibility) { - mSession = s; - mClient = c; - mToken = token; - mAttrs.copyFrom(a); - mViewVisibility = viewVisibility; - DeathRecipient deathRecipient = new DeathRecipient(); - mAlpha = a.alpha; - if (localLOGV) Slog.v( - TAG, "Window " + this + " client=" + c.asBinder() - + " token=" + token + " (" + mAttrs.token + ")"); - try { - c.asBinder().linkToDeath(deathRecipient, 0); - } catch (RemoteException e) { - mDeathRecipient = null; - mAttachedWindow = null; - mLayoutAttached = false; - mIsImWindow = false; - mIsWallpaper = false; - mIsFloatingLayer = false; - mBaseLayer = 0; - mSubLayer = 0; - return; - } - mDeathRecipient = deathRecipient; - - if ((mAttrs.type >= FIRST_SUB_WINDOW && - mAttrs.type <= LAST_SUB_WINDOW)) { - // The multiplier here is to reserve space for multiple - // windows in the same type layer. - mBaseLayer = mPolicy.windowTypeToLayerLw( - attachedWindow.mAttrs.type) * TYPE_LAYER_MULTIPLIER - + TYPE_LAYER_OFFSET; - mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type); - mAttachedWindow = attachedWindow; - if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + mAttachedWindow); - mAttachedWindow.mChildWindows.add(this); - mLayoutAttached = mAttrs.type != - WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; - mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD - || attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG; - mIsWallpaper = attachedWindow.mAttrs.type == TYPE_WALLPAPER; - mIsFloatingLayer = mIsImWindow || mIsWallpaper; - } else { - // The multiplier here is to reserve space for multiple - // windows in the same type layer. - mBaseLayer = mPolicy.windowTypeToLayerLw(a.type) - * TYPE_LAYER_MULTIPLIER - + TYPE_LAYER_OFFSET; - mSubLayer = 0; - mAttachedWindow = null; - mLayoutAttached = false; - mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD - || mAttrs.type == TYPE_INPUT_METHOD_DIALOG; - mIsWallpaper = mAttrs.type == TYPE_WALLPAPER; - mIsFloatingLayer = mIsImWindow || mIsWallpaper; - } - - WindowState appWin = this; - while (appWin.mAttachedWindow != null) { - appWin = mAttachedWindow; - } - WindowToken appToken = appWin.mToken; - while (appToken.appWindowToken == null) { - WindowToken parent = mTokenMap.get(appToken.token); - if (parent == null || appToken == parent) { - break; - } - appToken = parent; - } - mRootToken = appToken; - mAppToken = appToken.appWindowToken; - - mSurface = null; - mRequestedWidth = 0; - mRequestedHeight = 0; - mLastRequestedWidth = 0; - mLastRequestedHeight = 0; - mXOffset = 0; - mYOffset = 0; - mLayer = 0; - mAnimLayer = 0; - mLastLayer = 0; - mInputWindowHandle = new InputWindowHandle( - mAppToken != null ? mAppToken.mInputApplicationHandle : null, this); - } - - void attach() { - if (localLOGV) Slog.v( - TAG, "Attaching " + this + " token=" + mToken - + ", list=" + mToken.windows); - mSession.windowAddedLocked(); - } - - public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) { - mHaveFrame = true; - - final Rect container = mContainingFrame; - container.set(pf); - - final Rect display = mDisplayFrame; - display.set(df); - - if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) { - container.intersect(mCompatibleScreenFrame); - if ((mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) == 0) { - display.intersect(mCompatibleScreenFrame); - } - } - - final int pw = container.right - container.left; - final int ph = container.bottom - container.top; - - int w,h; - if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) { - w = mAttrs.width < 0 ? pw : mAttrs.width; - h = mAttrs.height< 0 ? ph : mAttrs.height; - } else { - w = mAttrs.width == mAttrs.MATCH_PARENT ? pw : mRequestedWidth; - h = mAttrs.height== mAttrs.MATCH_PARENT ? ph : mRequestedHeight; - } - - if (!mParentFrame.equals(pf)) { - //Slog.i(TAG, "Window " + this + " content frame from " + mParentFrame - // + " to " + pf); - mParentFrame.set(pf); - mContentChanged = true; - } - - final Rect content = mContentFrame; - content.set(cf); - - final Rect visible = mVisibleFrame; - visible.set(vf); - - final Rect frame = mFrame; - final int fw = frame.width(); - final int fh = frame.height(); - - //System.out.println("In: w=" + w + " h=" + h + " container=" + - // container + " x=" + mAttrs.x + " y=" + mAttrs.y); - - Gravity.apply(mAttrs.gravity, w, h, container, - (int) (mAttrs.x + mAttrs.horizontalMargin * pw), - (int) (mAttrs.y + mAttrs.verticalMargin * ph), frame); - - //System.out.println("Out: " + mFrame); - - // Now make sure the window fits in the overall display. - Gravity.applyDisplay(mAttrs.gravity, df, frame); - - // Make sure the content and visible frames are inside of the - // final window frame. - if (content.left < frame.left) content.left = frame.left; - if (content.top < frame.top) content.top = frame.top; - if (content.right > frame.right) content.right = frame.right; - if (content.bottom > frame.bottom) content.bottom = frame.bottom; - if (visible.left < frame.left) visible.left = frame.left; - if (visible.top < frame.top) visible.top = frame.top; - if (visible.right > frame.right) visible.right = frame.right; - if (visible.bottom > frame.bottom) visible.bottom = frame.bottom; - - final Rect contentInsets = mContentInsets; - contentInsets.left = content.left-frame.left; - contentInsets.top = content.top-frame.top; - contentInsets.right = frame.right-content.right; - contentInsets.bottom = frame.bottom-content.bottom; - - final Rect visibleInsets = mVisibleInsets; - visibleInsets.left = visible.left-frame.left; - visibleInsets.top = visible.top-frame.top; - visibleInsets.right = frame.right-visible.right; - visibleInsets.bottom = frame.bottom-visible.bottom; - - if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) { - updateWallpaperOffsetLocked(this, mDisplay.getWidth(), - mDisplay.getHeight(), false); - } - - if (localLOGV) { - //if ("com.google.android.youtube".equals(mAttrs.packageName) - // && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { - Slog.v(TAG, "Resolving (mRequestedWidth=" - + mRequestedWidth + ", mRequestedheight=" - + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph - + "): frame=" + mFrame.toShortString() - + " ci=" + contentInsets.toShortString() - + " vi=" + visibleInsets.toShortString()); - //} - } - } - - public Rect getFrameLw() { - return mFrame; - } - - public Rect getShownFrameLw() { - return mShownFrame; - } - - public Rect getDisplayFrameLw() { - return mDisplayFrame; - } - - public Rect getContentFrameLw() { - return mContentFrame; - } - - public Rect getVisibleFrameLw() { - return mVisibleFrame; - } - - public boolean getGivenInsetsPendingLw() { - return mGivenInsetsPending; - } - - public Rect getGivenContentInsetsLw() { - return mGivenContentInsets; - } - - public Rect getGivenVisibleInsetsLw() { - return mGivenVisibleInsets; - } - - public WindowManager.LayoutParams getAttrs() { - return mAttrs; - } - - public int getSurfaceLayer() { - return mLayer; - } - - public IApplicationToken getAppToken() { - return mAppToken != null ? mAppToken.appToken : null; - } - - public long getInputDispatchingTimeoutNanos() { - return mAppToken != null - ? mAppToken.inputDispatchingTimeoutNanos - : DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; - } - - public boolean hasAppShownWindows() { - return mAppToken != null ? mAppToken.firstWindowDrawn : false; - } - - public void setAnimation(Animation anim) { - if (localLOGV) Slog.v( - TAG, "Setting animation in " + this + ": " + anim); - mAnimating = false; - mLocalAnimating = false; - mAnimation = anim; - mAnimation.restrictDuration(MAX_ANIMATION_DURATION); - mAnimation.scaleCurrentDuration(mWindowAnimationScale); - } - - public void clearAnimation() { - if (mAnimation != null) { - mAnimating = true; - mLocalAnimating = false; - mAnimation.cancel(); - mAnimation = null; - } - } - - Surface createSurfaceLocked() { - if (mSurface == null) { - mReportDestroySurface = false; - mSurfacePendingDestroy = false; - mDrawPending = true; - mCommitDrawPending = false; - mReadyToShow = false; - if (mAppToken != null) { - mAppToken.allDrawn = false; - } - - int flags = 0; - - if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) { - flags |= Surface.SECURE; - } - if (DEBUG_VISIBILITY) Slog.v( - TAG, "Creating surface in session " - + mSession.mSurfaceSession + " window " + this - + " w=" + mFrame.width() - + " h=" + mFrame.height() + " format=" - + mAttrs.format + " flags=" + flags); - - int w = mFrame.width(); - int h = mFrame.height(); - if ((mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) { - // for a scaled surface, we always want the requested - // size. - w = mRequestedWidth; - h = mRequestedHeight; - } - - // Something is wrong and SurfaceFlinger will not like this, - // try to revert to sane values - if (w <= 0) w = 1; - if (h <= 0) h = 1; - - mSurfaceShown = false; - mSurfaceLayer = 0; - mSurfaceAlpha = 1; - mSurfaceX = 0; - mSurfaceY = 0; - mSurfaceW = w; - mSurfaceH = h; - try { - final boolean isHwAccelerated = (mAttrs.flags & - WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; - final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : mAttrs.format; - if (isHwAccelerated && mAttrs.format == PixelFormat.OPAQUE) { - flags |= Surface.OPAQUE; - } - mSurface = new Surface( - mSession.mSurfaceSession, mSession.mPid, - mAttrs.getTitle().toString(), - 0, w, h, format, flags); - if (SHOW_TRANSACTIONS) Slog.i(TAG, " CREATE SURFACE " - + mSurface + " IN SESSION " - + mSession.mSurfaceSession - + ": pid=" + mSession.mPid + " format=" - + mAttrs.format + " flags=0x" - + Integer.toHexString(flags) - + " / " + this); - } catch (Surface.OutOfResourcesException e) { - Slog.w(TAG, "OutOfResourcesException creating surface"); - reclaimSomeSurfaceMemoryLocked(this, "create"); - return null; - } catch (Exception e) { - Slog.e(TAG, "Exception creating surface", e); - return null; - } - - if (localLOGV) Slog.v( - TAG, "Got surface: " + mSurface - + ", set left=" + mFrame.left + " top=" + mFrame.top - + ", animLayer=" + mAnimLayer); - if (SHOW_TRANSACTIONS) { - Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked"); - logSurface(this, "CREATE pos=(" + mFrame.left + "," + mFrame.top + ") (" + - mFrame.width() + "x" + mFrame.height() + "), layer=" + - mAnimLayer + " HIDE", null); - } - Surface.openTransaction(); - try { - try { - mSurfaceX = mFrame.left + mXOffset; - mSurfaceY = mFrame.top + mYOffset; - mSurface.setPosition(mSurfaceX, mSurfaceY); - mSurfaceLayer = mAnimLayer; - mSurface.setLayer(mAnimLayer); - mSurfaceShown = false; - mSurface.hide(); - if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) { - if (SHOW_TRANSACTIONS) logSurface(this, "DITHER", null); - mSurface.setFlags(Surface.SURFACE_DITHER, - Surface.SURFACE_DITHER); - } - } catch (RuntimeException e) { - Slog.w(TAG, "Error creating surface in " + w, e); - reclaimSomeSurfaceMemoryLocked(this, "create-init"); - } - mLastHidden = true; - } finally { - Surface.closeTransaction(); - if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION createSurfaceLocked"); - } - if (localLOGV) Slog.v( - TAG, "Created surface " + this); - } - return mSurface; - } - - void destroySurfaceLocked() { - if (mAppToken != null && this == mAppToken.startingWindow) { - mAppToken.startingDisplayed = false; - } - - if (mSurface != null) { - mDrawPending = false; - mCommitDrawPending = false; - mReadyToShow = false; - - int i = mChildWindows.size(); - while (i > 0) { - i--; - WindowState c = mChildWindows.get(i); - c.mAttachedHidden = true; - } - - if (mReportDestroySurface) { - mReportDestroySurface = false; - mSurfacePendingDestroy = true; - try { - mClient.dispatchGetNewSurface(); - // We'll really destroy on the next time around. - return; - } catch (RemoteException e) { - } - } - - try { - if (DEBUG_VISIBILITY) { - RuntimeException e = null; - if (!HIDE_STACK_CRAWLS) { - e = new RuntimeException(); - e.fillInStackTrace(); - } - Slog.w(TAG, "Window " + this + " destroying surface " - + mSurface + ", session " + mSession, e); - } - if (SHOW_TRANSACTIONS) { - RuntimeException e = null; - if (!HIDE_STACK_CRAWLS) { - e = new RuntimeException(); - e.fillInStackTrace(); - } - if (SHOW_TRANSACTIONS) logSurface(this, "DESTROY", e); - } - mSurface.destroy(); - } catch (RuntimeException e) { - Slog.w(TAG, "Exception thrown when destroying Window " + this - + " surface " + mSurface + " session " + mSession - + ": " + e.toString()); - } - - mSurfaceShown = false; - mSurface = null; - } - } - - boolean finishDrawingLocked() { - if (mDrawPending) { - if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Slog.v( - TAG, "finishDrawingLocked: " + mSurface); - mCommitDrawPending = true; - mDrawPending = false; - return true; - } - return false; - } - - // This must be called while inside a transaction. - boolean commitFinishDrawingLocked(long currentTime) { - //Slog.i(TAG, "commitFinishDrawingLocked: " + mSurface); - if (!mCommitDrawPending) { - return false; - } - mCommitDrawPending = false; - mReadyToShow = true; - final boolean starting = mAttrs.type == TYPE_APPLICATION_STARTING; - final AppWindowToken atoken = mAppToken; - if (atoken == null || atoken.allDrawn || starting) { - performShowLocked(); - } - return true; - } - - // This must be called while inside a transaction. - boolean performShowLocked() { - if (DEBUG_VISIBILITY) { - RuntimeException e = null; - if (!HIDE_STACK_CRAWLS) { - e = new RuntimeException(); - e.fillInStackTrace(); - } - Slog.v(TAG, "performShow on " + this - + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay() - + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e); - } - if (mReadyToShow && isReadyForDisplay()) { - if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) logSurface(this, - "SHOW (performShowLocked)", null); - if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this - + " during animation: policyVis=" + mPolicyVisibility - + " attHidden=" + mAttachedHidden - + " tok.hiddenRequested=" - + (mAppToken != null ? mAppToken.hiddenRequested : false) - + " tok.hidden=" - + (mAppToken != null ? mAppToken.hidden : false) - + " animating=" + mAnimating - + " tok animating=" - + (mAppToken != null ? mAppToken.animating : false)); - if (!showSurfaceRobustlyLocked(this)) { - return false; - } - mLastAlpha = -1; - mHasDrawn = true; - mLastHidden = false; - mReadyToShow = false; - enableScreenIfNeededLocked(); - - applyEnterAnimationLocked(this); - - int i = mChildWindows.size(); - while (i > 0) { - i--; - WindowState c = mChildWindows.get(i); - if (c.mAttachedHidden) { - c.mAttachedHidden = false; - if (c.mSurface != null) { - c.performShowLocked(); - // It hadn't been shown, which means layout not - // performed on it, so now we want to make sure to - // do a layout. If called from within the transaction - // loop, this will cause it to restart with a new - // layout. - mLayoutNeeded = true; - } - } - } - - if (mAttrs.type != TYPE_APPLICATION_STARTING - && mAppToken != null) { - mAppToken.firstWindowDrawn = true; - - if (mAppToken.startingData != null) { - if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, - "Finish starting " + mToken - + ": first real window is shown, no animation"); - // If this initial window is animating, stop it -- we - // will do an animation to reveal it from behind the - // starting window, so there is no need for it to also - // be doing its own stuff. - if (mAnimation != null) { - mAnimation.cancel(); - mAnimation = null; - // Make sure we clean up the animation. - mAnimating = true; - } - mFinishedStarting.add(mAppToken); - mH.sendEmptyMessage(H.FINISHED_STARTING); - } - mAppToken.updateReportedVisibilityLocked(); - } - } - return true; - } - - // This must be called while inside a transaction. Returns true if - // there is more animation to run. - boolean stepAnimationLocked(long currentTime, int dw, int dh) { - if (!mDisplayFrozen && mPolicy.isScreenOn()) { - // We will run animations as long as the display isn't frozen. - - if (!mDrawPending && !mCommitDrawPending && mAnimation != null) { - mHasTransformation = true; - mHasLocalTransformation = true; - if (!mLocalAnimating) { - if (DEBUG_ANIM) Slog.v( - TAG, "Starting animation in " + this + - " @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() + - " dw=" + dw + " dh=" + dh + " scale=" + mWindowAnimationScale); - mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh); - mAnimation.setStartTime(currentTime); - mLocalAnimating = true; - mAnimating = true; - } - mTransformation.clear(); - final boolean more = mAnimation.getTransformation( - currentTime, mTransformation); - if (DEBUG_ANIM) Slog.v( - TAG, "Stepped animation in " + this + - ": more=" + more + ", xform=" + mTransformation); - if (more) { - // we're not done! - return true; - } - if (DEBUG_ANIM) Slog.v( - TAG, "Finished animation in " + this + - " @ " + currentTime); - - if (mAnimation != null) { - mAnimation.cancel(); - mAnimation = null; - } - //WindowManagerService.this.dump(); - } - mHasLocalTransformation = false; - if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null - && mAppToken.animation != null) { - // When our app token is animating, we kind-of pretend like - // we are as well. Note the mLocalAnimating mAnimationIsEntrance - // part of this check means that we will only do this if - // our window is not currently exiting, or it is not - // locally animating itself. The idea being that one that - // is exiting and doing a local animation should be removed - // once that animation is done. - mAnimating = true; - mHasTransformation = true; - mTransformation.clear(); - return false; - } else if (mHasTransformation) { - // Little trick to get through the path below to act like - // we have finished an animation. - mAnimating = true; - } else if (isAnimating()) { - mAnimating = true; - } - } else if (mAnimation != null) { - // If the display is frozen, and there is a pending animation, - // clear it and make sure we run the cleanup code. - mAnimating = true; - mLocalAnimating = true; - mAnimation.cancel(); - mAnimation = null; - } - - if (!mAnimating && !mLocalAnimating) { - return false; - } - - if (DEBUG_ANIM) Slog.v( - TAG, "Animation done in " + this + ": exiting=" + mExiting - + ", reportedVisible=" - + (mAppToken != null ? mAppToken.reportedVisible : false)); - - mAnimating = false; - mLocalAnimating = false; - if (mAnimation != null) { - mAnimation.cancel(); - mAnimation = null; - } - mAnimLayer = mLayer; - if (mIsImWindow) { - mAnimLayer += mInputMethodAnimLayerAdjustment; - } else if (mIsWallpaper) { - mAnimLayer += mWallpaperAnimLayerAdjustment; - } - if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this - + " anim layer: " + mAnimLayer); - mHasTransformation = false; - mHasLocalTransformation = false; - if (mPolicyVisibility != mPolicyVisibilityAfterAnim) { - if (DEBUG_VISIBILITY) { - Slog.v(TAG, "Policy visibility changing after anim in " + this + ": " - + mPolicyVisibilityAfterAnim); - } - mPolicyVisibility = mPolicyVisibilityAfterAnim; - if (!mPolicyVisibility) { - if (mCurrentFocus == this) { - mFocusMayChange = true; - } - // Window is no longer visible -- make sure if we were waiting - // for it to be displayed before enabling the display, that - // we allow the display to be enabled now. - enableScreenIfNeededLocked(); - } - } - mTransformation.clear(); - if (mHasDrawn - && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING - && mAppToken != null - && mAppToken.firstWindowDrawn - && mAppToken.startingData != null) { - if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Finish starting " - + mToken + ": first real window done animating"); - mFinishedStarting.add(mAppToken); - mH.sendEmptyMessage(H.FINISHED_STARTING); - } - - finishExit(); - - if (mAppToken != null) { - mAppToken.updateReportedVisibilityLocked(); - } - - return false; - } - - void finishExit() { - if (DEBUG_ANIM) Slog.v( - TAG, "finishExit in " + this - + ": exiting=" + mExiting - + " remove=" + mRemoveOnExit - + " windowAnimating=" + isWindowAnimating()); - - final int N = mChildWindows.size(); - for (int i=0; i<N; i++) { - mChildWindows.get(i).finishExit(); - } - - if (!mExiting) { - return; - } - - if (isWindowAnimating()) { - return; - } - - if (localLOGV) Slog.v( - TAG, "Exit animation finished in " + this - + ": remove=" + mRemoveOnExit); - if (mSurface != null) { - mDestroySurface.add(this); - mDestroying = true; - if (SHOW_TRANSACTIONS) logSurface(this, "HIDE (finishExit)", null); - mSurfaceShown = false; - try { - mSurface.hide(); - } catch (RuntimeException e) { - Slog.w(TAG, "Error hiding surface in " + this, e); - } - mLastHidden = true; - } - mExiting = false; - if (mRemoveOnExit) { - mPendingRemove.add(this); - mRemoveOnExit = false; - } - } - - boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { - if (dsdx < .99999f || dsdx > 1.00001f) return false; - if (dtdy < .99999f || dtdy > 1.00001f) return false; - if (dtdx < -.000001f || dtdx > .000001f) return false; - if (dsdy < -.000001f || dsdy > .000001f) return false; - return true; - } - - void computeShownFrameLocked() { - final boolean selfTransformation = mHasLocalTransformation; - Transformation attachedTransformation = - (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation) - ? mAttachedWindow.mTransformation : null; - Transformation appTransformation = - (mAppToken != null && mAppToken.hasTransformation) - ? mAppToken.transformation : null; - - // Wallpapers are animated based on the "real" window they - // are currently targeting. - if (mAttrs.type == TYPE_WALLPAPER && mLowerWallpaperTarget == null - && mWallpaperTarget != null) { - if (mWallpaperTarget.mHasLocalTransformation && - mWallpaperTarget.mAnimation != null && - !mWallpaperTarget.mAnimation.getDetachWallpaper()) { - attachedTransformation = mWallpaperTarget.mTransformation; - if (DEBUG_WALLPAPER && attachedTransformation != null) { - Slog.v(TAG, "WP target attached xform: " + attachedTransformation); - } - } - if (mWallpaperTarget.mAppToken != null && - mWallpaperTarget.mAppToken.hasTransformation && - mWallpaperTarget.mAppToken.animation != null && - !mWallpaperTarget.mAppToken.animation.getDetachWallpaper()) { - appTransformation = mWallpaperTarget.mAppToken.transformation; - if (DEBUG_WALLPAPER && appTransformation != null) { - Slog.v(TAG, "WP target app xform: " + appTransformation); - } - } - } - - final boolean screenAnimation = mScreenRotationAnimation != null - && mScreenRotationAnimation.isAnimating(); - if (selfTransformation || attachedTransformation != null - || appTransformation != null || screenAnimation) { - // cache often used attributes locally - final Rect frame = mFrame; - final float tmpFloats[] = mTmpFloats; - final Matrix tmpMatrix = mTmpMatrix; - - // Compute the desired transformation. - tmpMatrix.setTranslate(0, 0); - if (selfTransformation) { - tmpMatrix.postConcat(mTransformation.getMatrix()); - } - tmpMatrix.postTranslate(frame.left + mXOffset, frame.top + mYOffset); - if (attachedTransformation != null) { - tmpMatrix.postConcat(attachedTransformation.getMatrix()); - } - if (appTransformation != null) { - tmpMatrix.postConcat(appTransformation.getMatrix()); - } - if (screenAnimation) { - tmpMatrix.postConcat( - mScreenRotationAnimation.getEnterTransformation().getMatrix()); - } - - // "convert" it into SurfaceFlinger's format - // (a 2x2 matrix + an offset) - // Here we must not transform the position of the surface - // since it is already included in the transformation. - //Slog.i(TAG, "Transform: " + matrix); - - mHaveMatrix = true; - tmpMatrix.getValues(tmpFloats); - mDsDx = tmpFloats[Matrix.MSCALE_X]; - mDtDx = tmpFloats[Matrix.MSKEW_Y]; - mDsDy = tmpFloats[Matrix.MSKEW_X]; - mDtDy = tmpFloats[Matrix.MSCALE_Y]; - int x = (int)tmpFloats[Matrix.MTRANS_X]; - int y = (int)tmpFloats[Matrix.MTRANS_Y]; - int w = frame.width(); - int h = frame.height(); - mShownFrame.set(x, y, x+w, y+h); - - // Now set the alpha... but because our current hardware - // can't do alpha transformation on a non-opaque surface, - // turn it off if we are running an animation that is also - // transforming since it is more important to have that - // animation be smooth. - mShownAlpha = mAlpha; - if (!mLimitedAlphaCompositing - || (!PixelFormat.formatHasAlpha(mAttrs.format) - || (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy) - && x == frame.left && y == frame.top))) { - //Slog.i(TAG, "Applying alpha transform"); - if (selfTransformation) { - mShownAlpha *= mTransformation.getAlpha(); - } - if (attachedTransformation != null) { - mShownAlpha *= attachedTransformation.getAlpha(); - } - if (appTransformation != null) { - mShownAlpha *= appTransformation.getAlpha(); - } - if (screenAnimation) { - mShownAlpha *= - mScreenRotationAnimation.getEnterTransformation().getAlpha(); - } - } else { - //Slog.i(TAG, "Not applying alpha transform"); - } - - if (localLOGV) Slog.v( - TAG, "Continuing animation in " + this + - ": " + mShownFrame + - ", alpha=" + mTransformation.getAlpha()); - return; - } - - mShownFrame.set(mFrame); - if (mXOffset != 0 || mYOffset != 0) { - mShownFrame.offset(mXOffset, mYOffset); - } - mShownAlpha = mAlpha; - mHaveMatrix = false; - mDsDx = 1; - mDtDx = 0; - mDsDy = 0; - mDtDy = 1; - } - - /** - * Is this window visible? It is not visible if there is no - * surface, or we are in the process of running an exit animation - * that will remove the surface, or its app token has been hidden. - */ - public boolean isVisibleLw() { - final AppWindowToken atoken = mAppToken; - return mSurface != null && mPolicyVisibility && !mAttachedHidden - && (atoken == null || !atoken.hiddenRequested) - && !mExiting && !mDestroying; - } - - /** - * Like {@link #isVisibleLw}, but also counts a window that is currently - * "hidden" behind the keyguard as visible. This allows us to apply - * things like window flags that impact the keyguard. - * XXX I am starting to think we need to have ANOTHER visibility flag - * for this "hidden behind keyguard" state rather than overloading - * mPolicyVisibility. Ungh. - */ - public boolean isVisibleOrBehindKeyguardLw() { - final AppWindowToken atoken = mAppToken; - return mSurface != null && !mAttachedHidden - && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested) - && !mDrawPending && !mCommitDrawPending - && !mExiting && !mDestroying; - } - - /** - * Is this window visible, ignoring its app token? It is not visible - * if there is no surface, or we are in the process of running an exit animation - * that will remove the surface. - */ - public boolean isWinVisibleLw() { - final AppWindowToken atoken = mAppToken; - return mSurface != null && mPolicyVisibility && !mAttachedHidden - && (atoken == null || !atoken.hiddenRequested || atoken.animating) - && !mExiting && !mDestroying; - } - - /** - * The same as isVisible(), but follows the current hidden state of - * the associated app token, not the pending requested hidden state. - */ - boolean isVisibleNow() { - return mSurface != null && mPolicyVisibility && !mAttachedHidden - && !mRootToken.hidden && !mExiting && !mDestroying; - } - - /** - * Can this window possibly be a drag/drop target? The test here is - * a combination of the above "visible now" with the check that the - * Input Manager uses when discarding windows from input consideration. - */ - boolean isPotentialDragTarget() { - return isVisibleNow() && (mInputChannel != null) && !mRemoved; - } - - /** - * Same as isVisible(), but we also count it as visible between the - * call to IWindowSession.add() and the first relayout(). - */ - boolean isVisibleOrAdding() { - final AppWindowToken atoken = mAppToken; - return ((mSurface != null && !mReportDestroySurface) - || (!mRelayoutCalled && mViewVisibility == View.VISIBLE)) - && mPolicyVisibility && !mAttachedHidden - && (atoken == null || !atoken.hiddenRequested) - && !mExiting && !mDestroying; - } - - /** - * Is this window currently on-screen? It is on-screen either if it - * is visible or it is currently running an animation before no longer - * being visible. - */ - boolean isOnScreen() { - final AppWindowToken atoken = mAppToken; - if (atoken != null) { - return mSurface != null && mPolicyVisibility && !mDestroying - && ((!mAttachedHidden && !atoken.hiddenRequested) - || mAnimation != null || atoken.animation != null); - } else { - return mSurface != null && mPolicyVisibility && !mDestroying - && (!mAttachedHidden || mAnimation != null); - } - } - - /** - * Like isOnScreen(), but we don't return true if the window is part - * of a transition that has not yet been started. - */ - boolean isReadyForDisplay() { - if (mRootToken.waitingToShow && - mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { - return false; - } - final AppWindowToken atoken = mAppToken; - final boolean animating = atoken != null - ? (atoken.animation != null) : false; - return mSurface != null && mPolicyVisibility && !mDestroying - && ((!mAttachedHidden && mViewVisibility == View.VISIBLE - && !mRootToken.hidden) - || mAnimation != null || animating); - } - - /** Is the window or its container currently animating? */ - boolean isAnimating() { - final WindowState attached = mAttachedWindow; - final AppWindowToken atoken = mAppToken; - return mAnimation != null - || (attached != null && attached.mAnimation != null) - || (atoken != null && - (atoken.animation != null - || atoken.inPendingTransaction)); - } - - /** Is this window currently animating? */ - boolean isWindowAnimating() { - return mAnimation != null; - } - - /** - * Like isOnScreen, but returns false if the surface hasn't yet - * been drawn. - */ - public boolean isDisplayedLw() { - final AppWindowToken atoken = mAppToken; - return mSurface != null && mPolicyVisibility && !mDestroying - && !mDrawPending && !mCommitDrawPending - && ((!mAttachedHidden && - (atoken == null || !atoken.hiddenRequested)) - || mAnimating); - } - - /** - * Returns true if the window has a surface that it has drawn a - * complete UI in to. - */ - public boolean isDrawnLw() { - final AppWindowToken atoken = mAppToken; - return mSurface != null && !mDestroying - && !mDrawPending && !mCommitDrawPending; - } - - /** - * Return true if the window is opaque and fully drawn. This indicates - * it may obscure windows behind it. - */ - boolean isOpaqueDrawn() { - return (mAttrs.format == PixelFormat.OPAQUE - || mAttrs.type == TYPE_WALLPAPER) - && mSurface != null && mAnimation == null - && (mAppToken == null || mAppToken.animation == null) - && !mDrawPending && !mCommitDrawPending; - } - - /** - * Return whether this window is wanting to have a translation - * animation applied to it for an in-progress move. (Only makes - * sense to call from performLayoutAndPlaceSurfacesLockedInner().) - */ - boolean shouldAnimateMove() { - return mContentChanged && !mExiting && !mLastHidden && !mDisplayFrozen - && (mFrame.top != mLastFrame.top - || mFrame.left != mLastFrame.left) - && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove()) - && mPolicy.isScreenOn(); - } - - boolean needsBackgroundFiller(int screenWidth, int screenHeight) { - return - // only if the application is requesting compatible window - (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0 && - // only if it's visible - mHasDrawn && mViewVisibility == View.VISIBLE && - // and only if the application fills the compatible screen - mFrame.left <= mCompatibleScreenFrame.left && - mFrame.top <= mCompatibleScreenFrame.top && - mFrame.right >= mCompatibleScreenFrame.right && - mFrame.bottom >= mCompatibleScreenFrame.bottom; - } - - boolean isFullscreen(int screenWidth, int screenHeight) { - return mFrame.left <= 0 && mFrame.top <= 0 && - mFrame.right >= screenWidth && mFrame.bottom >= screenHeight; - } - - void removeLocked() { - disposeInputChannel(); - - if (mAttachedWindow != null) { - if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Removing " + this + " from " + mAttachedWindow); - mAttachedWindow.mChildWindows.remove(this); - } - destroySurfaceLocked(); - mSession.windowRemovedLocked(); - try { - mClient.asBinder().unlinkToDeath(mDeathRecipient, 0); - } catch (RuntimeException e) { - // Ignore if it has already been removed (usually because - // we are doing this as part of processing a death note.) - } - } - - void disposeInputChannel() { - if (mInputChannel != null) { - mInputManager.unregisterInputChannel(mInputChannel); - - mInputChannel.dispose(); - mInputChannel = null; - } - } - - private class DeathRecipient implements IBinder.DeathRecipient { - public void binderDied() { - try { - synchronized(mWindowMap) { - WindowState win = windowForClientLocked(mSession, mClient, false); - Slog.i(TAG, "WIN DEATH: " + win); - if (win != null) { - removeWindowLocked(mSession, win); - } - } - } catch (IllegalArgumentException ex) { - // This will happen if the window has already been - // removed. - } - } - } - - /** Returns true if this window desires key events. */ - public final boolean canReceiveKeys() { - return isVisibleOrAdding() - && (mViewVisibility == View.VISIBLE) - && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0); - } - - public boolean hasDrawnLw() { - return mHasDrawn; - } - - public boolean showLw(boolean doAnimation) { - return showLw(doAnimation, true); - } - - boolean showLw(boolean doAnimation, boolean requestAnim) { - if (mPolicyVisibility && mPolicyVisibilityAfterAnim) { - return false; - } - if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility true: " + this); - if (doAnimation) { - if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility=" - + mPolicyVisibility + " mAnimation=" + mAnimation); - if (mDisplayFrozen || !mPolicy.isScreenOn()) { - doAnimation = false; - } else if (mPolicyVisibility && mAnimation == null) { - // Check for the case where we are currently visible and - // not animating; we do not want to do animation at such a - // point to become visible when we already are. - doAnimation = false; - } - } - mPolicyVisibility = true; - mPolicyVisibilityAfterAnim = true; - if (doAnimation) { - applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true); - } - if (requestAnim) { - requestAnimationLocked(0); - } - return true; - } - - public boolean hideLw(boolean doAnimation) { - return hideLw(doAnimation, true); - } - - boolean hideLw(boolean doAnimation, boolean requestAnim) { - if (doAnimation) { - if (mDisplayFrozen || !mPolicy.isScreenOn()) { - doAnimation = false; - } - } - boolean current = doAnimation ? mPolicyVisibilityAfterAnim - : mPolicyVisibility; - if (!current) { - return false; - } - if (doAnimation) { - applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false); - if (mAnimation == null) { - doAnimation = false; - } - } - if (doAnimation) { - mPolicyVisibilityAfterAnim = false; - } else { - if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility false: " + this); - mPolicyVisibilityAfterAnim = false; - mPolicyVisibility = false; - // Window is no longer visible -- make sure if we were waiting - // for it to be displayed before enabling the display, that - // we allow the display to be enabled now. - enableScreenIfNeededLocked(); - if (mCurrentFocus == this) { - mFocusMayChange = true; - } - } - if (requestAnim) { - requestAnimationLocked(0); - } - return true; - } - - public void getTouchableRegion(Region outRegion) { - final Rect frame = mFrame; - switch (mTouchableInsets) { - default: - case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME: - outRegion.set(frame); - break; - case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: { - final Rect inset = mGivenContentInsets; - outRegion.set( - frame.left + inset.left, frame.top + inset.top, - frame.right - inset.right, frame.bottom - inset.bottom); - break; - } - case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: { - final Rect inset = mGivenVisibleInsets; - outRegion.set( - frame.left + inset.left, frame.top + inset.top, - frame.right - inset.right, frame.bottom - inset.bottom); - break; - } - case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION: { - final Region givenTouchableRegion = mGivenTouchableRegion; - outRegion.set(givenTouchableRegion); - outRegion.translate(frame.left, frame.top); - break; - } - } - } - - void dump(PrintWriter pw, String prefix) { - pw.print(prefix); pw.print("mSession="); pw.print(mSession); - pw.print(" mClient="); pw.println(mClient.asBinder()); - pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs); - if (mAttachedWindow != null || mLayoutAttached) { - pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow); - pw.print(" mLayoutAttached="); pw.println(mLayoutAttached); - } - if (mIsImWindow || mIsWallpaper || mIsFloatingLayer) { - pw.print(prefix); pw.print("mIsImWindow="); pw.print(mIsImWindow); - pw.print(" mIsWallpaper="); pw.print(mIsWallpaper); - pw.print(" mIsFloatingLayer="); pw.print(mIsFloatingLayer); - pw.print(" mWallpaperVisible="); pw.println(mWallpaperVisible); - } - pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer); - pw.print(" mSubLayer="); pw.print(mSubLayer); - pw.print(" mAnimLayer="); pw.print(mLayer); pw.print("+"); - pw.print((mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment - : (mAppToken != null ? mAppToken.animLayerAdjustment : 0))); - pw.print("="); pw.print(mAnimLayer); - pw.print(" mLastLayer="); pw.println(mLastLayer); - if (mSurface != null) { - pw.print(prefix); pw.print("mSurface="); pw.println(mSurface); - pw.print(prefix); pw.print("Surface: shown="); pw.print(mSurfaceShown); - pw.print(" layer="); pw.print(mSurfaceLayer); - pw.print(" alpha="); pw.print(mSurfaceAlpha); - pw.print(" rect=("); pw.print(mSurfaceX); - pw.print(","); pw.print(mSurfaceY); - pw.print(") "); pw.print(mSurfaceW); - pw.print(" x "); pw.println(mSurfaceH); - } - pw.print(prefix); pw.print("mToken="); pw.println(mToken); - pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken); - if (mAppToken != null) { - pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken); - } - if (mTargetAppToken != null) { - pw.print(prefix); pw.print("mTargetAppToken="); pw.println(mTargetAppToken); - } - pw.print(prefix); pw.print("mViewVisibility=0x"); - pw.print(Integer.toHexString(mViewVisibility)); - pw.print(" mLastHidden="); pw.print(mLastHidden); - pw.print(" mHaveFrame="); pw.print(mHaveFrame); - pw.print(" mObscured="); pw.println(mObscured); - if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) { - pw.print(prefix); pw.print("mPolicyVisibility="); - pw.print(mPolicyVisibility); - pw.print(" mPolicyVisibilityAfterAnim="); - pw.print(mPolicyVisibilityAfterAnim); - pw.print(" mAttachedHidden="); pw.println(mAttachedHidden); - } - if (!mRelayoutCalled) { - pw.print(prefix); pw.print("mRelayoutCalled="); pw.println(mRelayoutCalled); - } - pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth); - pw.print(" h="); pw.print(mRequestedHeight); - pw.print(" mLayoutSeq="); pw.println(mLayoutSeq); - if (mXOffset != 0 || mYOffset != 0) { - pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset); - pw.print(" y="); pw.println(mYOffset); - } - pw.print(prefix); pw.print("mGivenContentInsets="); - mGivenContentInsets.printShortString(pw); - pw.print(" mGivenVisibleInsets="); - mGivenVisibleInsets.printShortString(pw); - pw.println(); - if (mTouchableInsets != 0 || mGivenInsetsPending) { - pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets); - pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending); - } - pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration); - pw.print(prefix); pw.print("mShownFrame="); - mShownFrame.printShortString(pw); - pw.print(" last="); mLastShownFrame.printShortString(pw); - pw.println(); - pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw); - pw.print(" last="); mLastFrame.printShortString(pw); - pw.println(); - pw.print(prefix); pw.print("mContainingFrame="); - mContainingFrame.printShortString(pw); - pw.print(" mParentFrame="); - mParentFrame.printShortString(pw); - pw.print(" mDisplayFrame="); - mDisplayFrame.printShortString(pw); - pw.println(); - pw.print(prefix); pw.print("mContentFrame="); mContentFrame.printShortString(pw); - pw.print(" mVisibleFrame="); mVisibleFrame.printShortString(pw); - pw.println(); - pw.print(prefix); pw.print("mContentInsets="); mContentInsets.printShortString(pw); - pw.print(" last="); mLastContentInsets.printShortString(pw); - pw.print(" mVisibleInsets="); mVisibleInsets.printShortString(pw); - pw.print(" last="); mLastVisibleInsets.printShortString(pw); - pw.println(); - if (mAnimating || mLocalAnimating || mAnimationIsEntrance - || mAnimation != null) { - pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating); - pw.print(" mLocalAnimating="); pw.print(mLocalAnimating); - pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance); - pw.print(" mAnimation="); pw.println(mAnimation); - } - if (mHasTransformation || mHasLocalTransformation) { - pw.print(prefix); pw.print("XForm: has="); - pw.print(mHasTransformation); - pw.print(" hasLocal="); pw.print(mHasLocalTransformation); - pw.print(" "); mTransformation.printShortString(pw); - pw.println(); - } - if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) { - pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha); - pw.print(" mAlpha="); pw.print(mAlpha); - pw.print(" mLastAlpha="); pw.println(mLastAlpha); - } - if (mHaveMatrix) { - pw.print(prefix); pw.print("mDsDx="); pw.print(mDsDx); - pw.print(" mDtDx="); pw.print(mDtDx); - pw.print(" mDsDy="); pw.print(mDsDy); - pw.print(" mDtDy="); pw.println(mDtDy); - } - pw.print(prefix); pw.print("mDrawPending="); pw.print(mDrawPending); - pw.print(" mCommitDrawPending="); pw.print(mCommitDrawPending); - pw.print(" mReadyToShow="); pw.print(mReadyToShow); - pw.print(" mHasDrawn="); pw.println(mHasDrawn); - if (mExiting || mRemoveOnExit || mDestroying || mRemoved) { - pw.print(prefix); pw.print("mExiting="); pw.print(mExiting); - pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit); - pw.print(" mDestroying="); pw.print(mDestroying); - pw.print(" mRemoved="); pw.println(mRemoved); - } - if (mOrientationChanging || mAppFreezing || mTurnOnScreen) { - pw.print(prefix); pw.print("mOrientationChanging="); - pw.print(mOrientationChanging); - pw.print(" mAppFreezing="); pw.print(mAppFreezing); - pw.print(" mTurnOnScreen="); pw.println(mTurnOnScreen); - } - if (mHScale != 1 || mVScale != 1) { - pw.print(prefix); pw.print("mHScale="); pw.print(mHScale); - pw.print(" mVScale="); pw.println(mVScale); - } - if (mWallpaperX != -1 || mWallpaperY != -1) { - pw.print(prefix); pw.print("mWallpaperX="); pw.print(mWallpaperX); - pw.print(" mWallpaperY="); pw.println(mWallpaperY); - } - if (mWallpaperXStep != -1 || mWallpaperYStep != -1) { - pw.print(prefix); pw.print("mWallpaperXStep="); pw.print(mWallpaperXStep); - pw.print(" mWallpaperYStep="); pw.println(mWallpaperYStep); - } - } - - String makeInputChannelName() { - return Integer.toHexString(System.identityHashCode(this)) - + " " + mAttrs.getTitle(); - } - - @Override - public String toString() { - if (mStringNameCache == null || mLastTitle != mAttrs.getTitle() - || mWasPaused != mToken.paused) { - mLastTitle = mAttrs.getTitle(); - mWasPaused = mToken.paused; - mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this)) - + " " + mLastTitle + " paused=" + mWasPaused + "}"; - } - return mStringNameCache; - } - } - - // ------------------------------------------------------------- - // Window Token State - // ------------------------------------------------------------- - - class WindowToken { - // The actual token. - final IBinder token; - - // The type of window this token is for, as per WindowManager.LayoutParams. - final int windowType; - - // Set if this token was explicitly added by a client, so should - // not be removed when all windows are removed. - final boolean explicit; - - // For printing. - String stringName; - - // If this is an AppWindowToken, this is non-null. - AppWindowToken appWindowToken; - - // All of the windows associated with this token. - final ArrayList<WindowState> windows = new ArrayList<WindowState>(); - - // Is key dispatching paused for this token? - boolean paused = false; - - // Should this token's windows be hidden? - boolean hidden; - - // Temporary for finding which tokens no longer have visible windows. - boolean hasVisible; - - // Set to true when this token is in a pending transaction where it - // will be shown. - boolean waitingToShow; - - // Set to true when this token is in a pending transaction where it - // will be hidden. - boolean waitingToHide; - - // Set to true when this token is in a pending transaction where its - // windows will be put to the bottom of the list. - boolean sendingToBottom; - - // Set to true when this token is in a pending transaction where its - // windows will be put to the top of the list. - boolean sendingToTop; - - WindowToken(IBinder _token, int type, boolean _explicit) { - token = _token; - windowType = type; - explicit = _explicit; - } - - void dump(PrintWriter pw, String prefix) { - pw.print(prefix); pw.print("token="); pw.println(token); - pw.print(prefix); pw.print("windows="); pw.println(windows); - pw.print(prefix); pw.print("windowType="); pw.print(windowType); - pw.print(" hidden="); pw.print(hidden); - pw.print(" hasVisible="); pw.println(hasVisible); - if (waitingToShow || waitingToHide || sendingToBottom || sendingToTop) { - pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow); - pw.print(" waitingToHide="); pw.print(waitingToHide); - pw.print(" sendingToBottom="); pw.print(sendingToBottom); - pw.print(" sendingToTop="); pw.println(sendingToTop); - } - } - - @Override - public String toString() { - if (stringName == null) { - StringBuilder sb = new StringBuilder(); - sb.append("WindowToken{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(" token="); sb.append(token); sb.append('}'); - stringName = sb.toString(); - } - return stringName; - } - }; - - class AppWindowToken extends WindowToken { - // Non-null only for application tokens. - final IApplicationToken appToken; - - // All of the windows and child windows that are included in this - // application token. Note this list is NOT sorted! - final ArrayList<WindowState> allAppWindows = new ArrayList<WindowState>(); - - int groupId = -1; - boolean appFullscreen; - int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - - // The input dispatching timeout for this application token in nanoseconds. - long inputDispatchingTimeoutNanos; - - // These are used for determining when all windows associated with - // an activity have been drawn, so they can be made visible together - // at the same time. - int lastTransactionSequence = mTransactionSequence-1; - int numInterestingWindows; - int numDrawnWindows; - boolean inPendingTransaction; - boolean allDrawn; - - // Is this token going to be hidden in a little while? If so, it - // won't be taken into account for setting the screen orientation. - boolean willBeHidden; - - // Is this window's surface needed? This is almost like hidden, except - // it will sometimes be true a little earlier: when the token has - // been shown, but is still waiting for its app transition to execute - // before making its windows shown. - boolean hiddenRequested; - - // Have we told the window clients to hide themselves? - boolean clientHidden; - - // Last visibility state we reported to the app token. - boolean reportedVisible; - - // Set to true when the token has been removed from the window mgr. - boolean removed; - - // Have we been asked to have this token keep the screen frozen? - boolean freezingScreen; - - boolean animating; - Animation animation; - boolean hasTransformation; - final Transformation transformation = new Transformation(); - - // Offset to the window of all layers in the token, for use by - // AppWindowToken animations. - int animLayerAdjustment; - - // Information about an application starting window if displayed. - StartingData startingData; - WindowState startingWindow; - View startingView; - boolean startingDisplayed; - boolean startingMoved; - boolean firstWindowDrawn; - - // Input application handle used by the input dispatcher. - InputApplicationHandle mInputApplicationHandle; - - AppWindowToken(IApplicationToken _token) { - super(_token.asBinder(), - WindowManager.LayoutParams.TYPE_APPLICATION, true); - appWindowToken = this; - appToken = _token; - mInputApplicationHandle = new InputApplicationHandle(this); - } - - public void setAnimation(Animation anim) { - if (localLOGV) Slog.v( - TAG, "Setting animation in " + this + ": " + anim); - animation = anim; - animating = false; - anim.restrictDuration(MAX_ANIMATION_DURATION); - anim.scaleCurrentDuration(mTransitionAnimationScale); - int zorder = anim.getZAdjustment(); - int adj = 0; - if (zorder == Animation.ZORDER_TOP) { - adj = TYPE_LAYER_OFFSET; - } else if (zorder == Animation.ZORDER_BOTTOM) { - adj = -TYPE_LAYER_OFFSET; - } - - if (animLayerAdjustment != adj) { - animLayerAdjustment = adj; - updateLayers(); - } - } - - public void setDummyAnimation() { - if (animation == null) { - if (localLOGV) Slog.v( - TAG, "Setting dummy animation in " + this); - animation = sDummyAnimation; - } - } - - public void clearAnimation() { - if (animation != null) { - animation = null; - animating = true; - } - } - - void updateLayers() { - final int N = allAppWindows.size(); - final int adj = animLayerAdjustment; - for (int i=0; i<N; i++) { - WindowState w = allAppWindows.get(i); - w.mAnimLayer = w.mLayer + adj; - if (DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": " - + w.mAnimLayer); - if (w == mInputMethodTarget && !mInputMethodTargetWaitingAnim) { - setInputMethodAnimLayerAdjustment(adj); - } - if (w == mWallpaperTarget && mLowerWallpaperTarget == null) { - setWallpaperAnimLayerAdjustmentLocked(adj); - } - } - } - - void sendAppVisibilityToClients() { - final int N = allAppWindows.size(); - for (int i=0; i<N; i++) { - WindowState win = allAppWindows.get(i); - if (win == startingWindow && clientHidden) { - // Don't hide the starting window. - continue; - } - try { - if (DEBUG_VISIBILITY) Slog.v(TAG, - "Setting visibility of " + win + ": " + (!clientHidden)); - win.mClient.dispatchAppVisibility(!clientHidden); - } catch (RemoteException e) { - } - } - } - - void showAllWindowsLocked() { - final int NW = allAppWindows.size(); - for (int i=0; i<NW; i++) { - WindowState w = allAppWindows.get(i); - if (DEBUG_VISIBILITY) Slog.v(TAG, - "performing show on: " + w); - w.performShowLocked(); - } - } - - // This must be called while inside a transaction. - boolean stepAnimationLocked(long currentTime, int dw, int dh) { - if (!mDisplayFrozen && mPolicy.isScreenOn()) { - // We will run animations as long as the display isn't frozen. - - if (animation == sDummyAnimation) { - // This guy is going to animate, but not yet. For now count - // it as not animating for purposes of scheduling transactions; - // when it is really time to animate, this will be set to - // a real animation and the next call will execute normally. - return false; - } - - if ((allDrawn || animating || startingDisplayed) && animation != null) { - if (!animating) { - if (DEBUG_ANIM) Slog.v( - TAG, "Starting animation in " + this + - " @ " + currentTime + ": dw=" + dw + " dh=" + dh - + " scale=" + mTransitionAnimationScale - + " allDrawn=" + allDrawn + " animating=" + animating); - animation.initialize(dw, dh, dw, dh); - animation.setStartTime(currentTime); - animating = true; - } - transformation.clear(); - final boolean more = animation.getTransformation( - currentTime, transformation); - if (DEBUG_ANIM) Slog.v( - TAG, "Stepped animation in " + this + - ": more=" + more + ", xform=" + transformation); - if (more) { - // we're done! - hasTransformation = true; - return true; - } - if (DEBUG_ANIM) Slog.v( - TAG, "Finished animation in " + this + - " @ " + currentTime); - animation = null; - } - } else if (animation != null) { - // If the display is frozen, and there is a pending animation, - // clear it and make sure we run the cleanup code. - animating = true; - animation = null; - } - - hasTransformation = false; - - if (!animating) { - return false; - } - - clearAnimation(); - animating = false; - if (animLayerAdjustment != 0) { - animLayerAdjustment = 0; - updateLayers(); - } - if (mInputMethodTarget != null && mInputMethodTarget.mAppToken == this) { - moveInputMethodWindowsIfNeededLocked(true); - } - - if (DEBUG_ANIM) Slog.v( - TAG, "Animation done in " + this - + ": reportedVisible=" + reportedVisible); - - transformation.clear(); - - final int N = windows.size(); - for (int i=0; i<N; i++) { - windows.get(i).finishExit(); - } - updateReportedVisibilityLocked(); - - return false; - } - - void updateReportedVisibilityLocked() { - if (appToken == null) { - return; - } - - int numInteresting = 0; - int numVisible = 0; - boolean nowGone = true; - - if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this); - final int N = allAppWindows.size(); - for (int i=0; i<N; i++) { - WindowState win = allAppWindows.get(i); - if (win == startingWindow || win.mAppFreezing - || win.mViewVisibility != View.VISIBLE - || win.mAttrs.type == TYPE_APPLICATION_STARTING - || win.mDestroying) { - continue; - } - if (DEBUG_VISIBILITY) { - Slog.v(TAG, "Win " + win + ": isDrawn=" - + win.isDrawnLw() - + ", isAnimating=" + win.isAnimating()); - if (!win.isDrawnLw()) { - Slog.v(TAG, "Not displayed: s=" + win.mSurface - + " pv=" + win.mPolicyVisibility - + " dp=" + win.mDrawPending - + " cdp=" + win.mCommitDrawPending - + " ah=" + win.mAttachedHidden - + " th=" - + (win.mAppToken != null - ? win.mAppToken.hiddenRequested : false) - + " a=" + win.mAnimating); - } - } - numInteresting++; - if (win.isDrawnLw()) { - if (!win.isAnimating()) { - numVisible++; - } - nowGone = false; - } else if (win.isAnimating()) { - nowGone = false; - } - } - - boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting; - if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting=" - + numInteresting + " visible=" + numVisible); - if (nowVisible != reportedVisible) { - if (DEBUG_VISIBILITY) Slog.v( - TAG, "Visibility changed in " + this - + ": vis=" + nowVisible); - reportedVisible = nowVisible; - Message m = mH.obtainMessage( - H.REPORT_APPLICATION_TOKEN_WINDOWS, - nowVisible ? 1 : 0, - nowGone ? 1 : 0, - this); - mH.sendMessage(m); - } - } - - WindowState findMainWindow() { - int j = windows.size(); - while (j > 0) { - j--; - WindowState win = windows.get(j); - if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION - || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) { - return win; - } - } - return null; - } - - void dump(PrintWriter pw, String prefix) { - super.dump(pw, prefix); - if (appToken != null) { - pw.print(prefix); pw.println("app=true"); - } - if (allAppWindows.size() > 0) { - pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows); - } - pw.print(prefix); pw.print("groupId="); pw.print(groupId); - pw.print(" appFullscreen="); pw.print(appFullscreen); - pw.print(" requestedOrientation="); pw.println(requestedOrientation); - pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested); - pw.print(" clientHidden="); pw.print(clientHidden); - pw.print(" willBeHidden="); pw.print(willBeHidden); - pw.print(" reportedVisible="); pw.println(reportedVisible); - if (paused || freezingScreen) { - pw.print(prefix); pw.print("paused="); pw.print(paused); - pw.print(" freezingScreen="); pw.println(freezingScreen); - } - if (numInterestingWindows != 0 || numDrawnWindows != 0 - || inPendingTransaction || allDrawn) { - pw.print(prefix); pw.print("numInterestingWindows="); - pw.print(numInterestingWindows); - pw.print(" numDrawnWindows="); pw.print(numDrawnWindows); - pw.print(" inPendingTransaction="); pw.print(inPendingTransaction); - pw.print(" allDrawn="); pw.println(allDrawn); - } - if (animating || animation != null) { - pw.print(prefix); pw.print("animating="); pw.print(animating); - pw.print(" animation="); pw.println(animation); - } - if (hasTransformation) { - pw.print(prefix); pw.print("XForm: "); - transformation.printShortString(pw); - pw.println(); - } - if (animLayerAdjustment != 0) { - pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment); - } - if (startingData != null || removed || firstWindowDrawn) { - pw.print(prefix); pw.print("startingData="); pw.print(startingData); - pw.print(" removed="); pw.print(removed); - pw.print(" firstWindowDrawn="); pw.println(firstWindowDrawn); - } - if (startingWindow != null || startingView != null - || startingDisplayed || startingMoved) { - pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow); - pw.print(" startingView="); pw.print(startingView); - pw.print(" startingDisplayed="); pw.print(startingDisplayed); - pw.print(" startingMoved"); pw.println(startingMoved); - } - } - - @Override - public String toString() { - if (stringName == null) { - StringBuilder sb = new StringBuilder(); - sb.append("AppWindowToken{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(" token="); sb.append(token); sb.append('}'); - stringName = sb.toString(); - } - return stringName; - } - } - - // ------------------------------------------------------------- - // DummyAnimation - // ------------------------------------------------------------- - // This is an animation that does nothing: it just immediately finishes // itself every time it is called. It is used as a stub animation in cases // where we want to synchronize multiple things that may be animating. @@ -8919,26 +5826,7 @@ public class WindowManagerService extends IWindowManager.Stub // Async Handler // ------------------------------------------------------------- - static final class StartingData { - final String pkg; - final int theme; - final CharSequence nonLocalizedLabel; - final int labelRes; - final int icon; - final int windowFlags; - - StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel, - int _labelRes, int _icon, int _windowFlags) { - pkg = _pkg; - theme = _theme; - nonLocalizedLabel = _nonLocalizedLabel; - labelRes = _labelRes; - icon = _icon; - windowFlags = _windowFlags; - } - } - - private final class H extends Handler { + final class H extends Handler { public static final int REPORT_FOCUS_CHANGE = 2; public static final int REPORT_LOSING_FOCUS = 3; public static final int ANIMATE = 4; @@ -9348,7 +6236,7 @@ public class WindowManagerService extends IWindowManager.Stub IInputContext inputContext) { if (client == null) throw new IllegalArgumentException("null client"); if (inputContext == null) throw new IllegalArgumentException("null inputContext"); - Session session = new Session(client, inputContext); + Session session = new Session(this, client, inputContext); return session; } @@ -11482,148 +8370,6 @@ public class WindowManagerService extends IWindowManager.Stub return val; } - static class Watermark { - final String[] mTokens; - final String mText; - final Paint mTextPaint; - final int mTextWidth; - final int mTextHeight; - final int mTextAscent; - final int mTextDescent; - final int mDeltaX; - final int mDeltaY; - - Surface mSurface; - int mLastDW; - int mLastDH; - boolean mDrawNeeded; - - Watermark(Display display, SurfaceSession session, String[] tokens) { - final DisplayMetrics dm = new DisplayMetrics(); - display.getMetrics(dm); - - if (false) { - Log.i(TAG, "*********************** WATERMARK"); - for (int i=0; i<tokens.length; i++) { - Log.i(TAG, " TOKEN #" + i + ": " + tokens[i]); - } - } - - mTokens = tokens; - - StringBuilder builder = new StringBuilder(32); - int len = mTokens[0].length(); - len = len & ~1; - for (int i=0; i<len; i+=2) { - int c1 = mTokens[0].charAt(i); - int c2 = mTokens[0].charAt(i+1); - if (c1 >= 'a' && c1 <= 'f') c1 = c1 - 'a' + 10; - else if (c1 >= 'A' && c1 <= 'F') c1 = c1 - 'A' + 10; - else c1 -= '0'; - if (c2 >= 'a' && c2 <= 'f') c2 = c2 - 'a' + 10; - else if (c2 >= 'A' && c2 <= 'F') c2 = c2 - 'A' + 10; - else c2 -= '0'; - builder.append((char)(255-((c1*16)+c2))); - } - mText = builder.toString(); - if (false) { - Log.i(TAG, "Final text: " + mText); - } - - int fontSize = getPropertyInt(tokens, 1, - TypedValue.COMPLEX_UNIT_DIP, 20, dm); - - mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mTextPaint.setTextSize(fontSize); - mTextPaint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD)); - - FontMetricsInt fm = mTextPaint.getFontMetricsInt(); - mTextWidth = (int)mTextPaint.measureText(mText); - mTextAscent = fm.ascent; - mTextDescent = fm.descent; - mTextHeight = fm.descent - fm.ascent; - - mDeltaX = getPropertyInt(tokens, 2, - TypedValue.COMPLEX_UNIT_PX, mTextWidth*2, dm); - mDeltaY = getPropertyInt(tokens, 3, - TypedValue.COMPLEX_UNIT_PX, mTextHeight*3, dm); - int shadowColor = getPropertyInt(tokens, 4, - TypedValue.COMPLEX_UNIT_PX, 0xb0000000, dm); - int color = getPropertyInt(tokens, 5, - TypedValue.COMPLEX_UNIT_PX, 0x60ffffff, dm); - int shadowRadius = getPropertyInt(tokens, 6, - TypedValue.COMPLEX_UNIT_PX, 7, dm); - int shadowDx = getPropertyInt(tokens, 8, - TypedValue.COMPLEX_UNIT_PX, 0, dm); - int shadowDy = getPropertyInt(tokens, 9, - TypedValue.COMPLEX_UNIT_PX, 0, dm); - - mTextPaint.setColor(color); - mTextPaint.setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor); - - try { - mSurface = new Surface(session, 0, - "WatermarkSurface", -1, 1, 1, PixelFormat.TRANSLUCENT, 0); - mSurface.setLayer(TYPE_LAYER_MULTIPLIER*100); - mSurface.setPosition(0, 0); - mSurface.show(); - } catch (OutOfResourcesException e) { - } - } - - void positionSurface(int dw, int dh) { - if (mLastDW != dw || mLastDH != dh) { - mLastDW = dw; - mLastDH = dh; - mSurface.setSize(dw, dh); - mDrawNeeded = true; - } - } - - void drawIfNeeded() { - if (mDrawNeeded) { - final int dw = mLastDW; - final int dh = mLastDH; - - mDrawNeeded = false; - Rect dirty = new Rect(0, 0, dw, dh); - Canvas c = null; - try { - c = mSurface.lockCanvas(dirty); - } catch (IllegalArgumentException e) { - } catch (OutOfResourcesException e) { - } - if (c != null) { - c.drawColor(0, PorterDuff.Mode.CLEAR); - - int deltaX = mDeltaX; - int deltaY = mDeltaY; - - // deltaX shouldn't be close to a round fraction of our - // x step, or else things will line up too much. - int div = (dw+mTextWidth)/deltaX; - int rem = (dw+mTextWidth) - (div*deltaX); - int qdelta = deltaX/4; - if (rem < qdelta || rem > (deltaX-qdelta)) { - deltaX += deltaX/3; - } - - int y = -mTextHeight; - int x = -mTextWidth; - while (y < (dh+mTextHeight)) { - c.drawText(mText, x, y, mTextPaint); - x += deltaX; - if (x >= dw) { - x -= (dw+mTextWidth); - y += deltaY; - } - } - mSurface.unlockCanvasAndPost(c); - } - } - } - } - void createWatermark() { if (mWatermark != null) { return; @@ -11905,190 +8651,6 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mKeyguardTokenWatcher) { } } - /** - * DimAnimator class that controls the dim animation. This holds the surface and - * all state used for dim animation. - */ - private static class DimAnimator { - Surface mDimSurface; - boolean mDimShown = false; - float mDimCurrentAlpha; - float mDimTargetAlpha; - float mDimDeltaPerMs; - long mLastDimAnimTime; - - int mLastDimWidth, mLastDimHeight; - - DimAnimator (SurfaceSession session) { - if (mDimSurface == null) { - if (SHOW_TRANSACTIONS) Slog.i(TAG, " DIM " - + mDimSurface + ": CREATE"); - try { - mDimSurface = new Surface(session, 0, - "DimSurface", - -1, 16, 16, PixelFormat.OPAQUE, - Surface.FX_SURFACE_DIM); - mDimSurface.setAlpha(0.0f); - } catch (Exception e) { - Slog.e(TAG, "Exception creating Dim surface", e); - } - } - } - - /** - * Show the dim surface. - */ - void show(int dw, int dh) { - if (!mDimShown) { - if (SHOW_TRANSACTIONS) Slog.i(TAG, " DIM " + mDimSurface + ": SHOW pos=(0,0) (" + - dw + "x" + dh + ")"); - mDimShown = true; - try { - mLastDimWidth = dw; - mLastDimHeight = dh; - mDimSurface.setPosition(0, 0); - mDimSurface.setSize(dw, dh); - mDimSurface.show(); - } catch (RuntimeException e) { - Slog.w(TAG, "Failure showing dim surface", e); - } - } else if (mLastDimWidth != dw || mLastDimHeight != dh) { - mLastDimWidth = dw; - mLastDimHeight = dh; - mDimSurface.setSize(dw, dh); - } - } - - /** - * Set's the dim surface's layer and update dim parameters that will be used in - * {@link updateSurface} after all windows are examined. - */ - void updateParameters(Resources res, WindowState w, long currentTime) { - mDimSurface.setLayer(w.mAnimLayer-1); - - final float target = w.mExiting ? 0 : w.mAttrs.dimAmount; - if (SHOW_TRANSACTIONS) Slog.i(TAG, " DIM " + mDimSurface - + ": layer=" + (w.mAnimLayer-1) + " target=" + target); - if (mDimTargetAlpha != target) { - // If the desired dim level has changed, then - // start an animation to it. - mLastDimAnimTime = currentTime; - long duration = (w.mAnimating && w.mAnimation != null) - ? w.mAnimation.computeDurationHint() - : DEFAULT_DIM_DURATION; - if (target > mDimTargetAlpha) { - TypedValue tv = new TypedValue(); - res.getValue(com.android.internal.R.fraction.config_dimBehindFadeDuration, - tv, true); - if (tv.type == TypedValue.TYPE_FRACTION) { - duration = (long)tv.getFraction((float)duration, (float)duration); - } else if (tv.type >= TypedValue.TYPE_FIRST_INT - && tv.type <= TypedValue.TYPE_LAST_INT) { - duration = tv.data; - } - } - if (duration < 1) { - // Don't divide by zero - duration = 1; - } - mDimTargetAlpha = target; - mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha) / duration; - } - } - - /** - * Updating the surface's alpha. Returns true if the animation continues, or returns - * false when the animation is finished and the dim surface is hidden. - */ - boolean updateSurface(boolean dimming, long currentTime, boolean displayFrozen) { - if (!dimming) { - if (mDimTargetAlpha != 0) { - mLastDimAnimTime = currentTime; - mDimTargetAlpha = 0; - mDimDeltaPerMs = (-mDimCurrentAlpha) / DEFAULT_DIM_DURATION; - } - } - - boolean animating = false; - if (mLastDimAnimTime != 0) { - mDimCurrentAlpha += mDimDeltaPerMs - * (currentTime-mLastDimAnimTime); - boolean more = true; - if (displayFrozen) { - // If the display is frozen, there is no reason to animate. - more = false; - } else if (mDimDeltaPerMs > 0) { - if (mDimCurrentAlpha > mDimTargetAlpha) { - more = false; - } - } else if (mDimDeltaPerMs < 0) { - if (mDimCurrentAlpha < mDimTargetAlpha) { - more = false; - } - } else { - more = false; - } - - // Do we need to continue animating? - if (more) { - if (SHOW_TRANSACTIONS) Slog.i(TAG, " DIM " - + mDimSurface + ": alpha=" + mDimCurrentAlpha); - mLastDimAnimTime = currentTime; - mDimSurface.setAlpha(mDimCurrentAlpha); - animating = true; - } else { - mDimCurrentAlpha = mDimTargetAlpha; - mLastDimAnimTime = 0; - if (SHOW_TRANSACTIONS) Slog.i(TAG, " DIM " - + mDimSurface + ": final alpha=" + mDimCurrentAlpha); - mDimSurface.setAlpha(mDimCurrentAlpha); - if (!dimming) { - if (SHOW_TRANSACTIONS) Slog.i(TAG, " DIM " + mDimSurface - + ": HIDE"); - try { - mDimSurface.hide(); - } catch (RuntimeException e) { - Slog.w(TAG, "Illegal argument exception hiding dim surface"); - } - mDimShown = false; - } - } - } - return animating; - } - - public void printTo(PrintWriter pw) { - pw.print(" mDimShown="); pw.print(mDimShown); - pw.print(" current="); pw.print(mDimCurrentAlpha); - pw.print(" target="); pw.print(mDimTargetAlpha); - pw.print(" delta="); pw.print(mDimDeltaPerMs); - pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime); - } - } - - /** - * Animation that fade in after 0.5 interpolate time, or fade out in reverse order. - * This is used for opening/closing transition for apps in compatible mode. - */ - private static class FadeInOutAnimation extends Animation { - boolean mFadeIn; - - public FadeInOutAnimation(boolean fadeIn) { - setInterpolator(new AccelerateInterpolator()); - setDuration(DEFAULT_FADE_IN_OUT_DURATION); - mFadeIn = fadeIn; - } - - @Override - protected void applyTransformation(float interpolatedTime, Transformation t) { - float x = interpolatedTime; - if (!mFadeIn) { - x = 1.0f - x; // reverse the interpolation for fade out - } - t.setAlpha(x); - } - } - public interface OnHardKeyboardStatusChangeListener { public void onHardKeyboardStatusChange(boolean available, boolean enabled); } diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java new file mode 100644 index 000000000000..d0eec898c3af --- /dev/null +++ b/services/java/com/android/server/wm/WindowState.java @@ -0,0 +1,1623 @@ +/* + * Copyright (C) 2011 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 com.android.server.wm; + +import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; +import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; +import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; + +import com.android.server.wm.WindowManagerService.H; + +import android.content.res.Configuration; +import android.graphics.Matrix; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.Region; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; +import android.view.Gravity; +import android.view.IApplicationToken; +import android.view.IWindow; +import android.view.InputChannel; +import android.view.Surface; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.WindowManager; +import android.view.WindowManagerPolicy; +import android.view.WindowManager.LayoutParams; +import android.view.animation.Animation; +import android.view.animation.Transformation; + +import java.io.PrintWriter; +import java.util.ArrayList; + +/** + * A window in the window manager. + */ +final class WindowState implements WindowManagerPolicy.WindowState { + final WindowManagerService mService; + final Session mSession; + final IWindow mClient; + WindowToken mToken; + WindowToken mRootToken; + AppWindowToken mAppToken; + AppWindowToken mTargetAppToken; + final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams(); + final DeathRecipient mDeathRecipient; + final WindowState mAttachedWindow; + final ArrayList<WindowState> mChildWindows = new ArrayList<WindowState>(); + final int mBaseLayer; + final int mSubLayer; + final boolean mLayoutAttached; + final boolean mIsImWindow; + final boolean mIsWallpaper; + final boolean mIsFloatingLayer; + int mViewVisibility; + boolean mPolicyVisibility = true; + boolean mPolicyVisibilityAfterAnim = true; + boolean mAppFreezing; + Surface mSurface; + boolean mReportDestroySurface; + boolean mSurfacePendingDestroy; + boolean mAttachedHidden; // is our parent window hidden? + boolean mLastHidden; // was this window last hidden? + boolean mWallpaperVisible; // for wallpaper, what was last vis report? + int mRequestedWidth; + int mRequestedHeight; + int mLastRequestedWidth; + int mLastRequestedHeight; + int mLayer; + int mAnimLayer; + int mLastLayer; + boolean mHaveFrame; + boolean mObscured; + boolean mTurnOnScreen; + + int mLayoutSeq = -1; + + Configuration mConfiguration = null; + + // Actual frame shown on-screen (may be modified by animation) + final Rect mShownFrame = new Rect(); + final Rect mLastShownFrame = new Rect(); + + /** + * Set when we have changed the size of the surface, to know that + * we must tell them application to resize (and thus redraw itself). + */ + boolean mSurfaceResized; + + /** + * Insets that determine the actually visible area + */ + final Rect mVisibleInsets = new Rect(); + final Rect mLastVisibleInsets = new Rect(); + boolean mVisibleInsetsChanged; + + /** + * Insets that are covered by system windows + */ + final Rect mContentInsets = new Rect(); + final Rect mLastContentInsets = new Rect(); + boolean mContentInsetsChanged; + + /** + * Set to true if we are waiting for this window to receive its + * given internal insets before laying out other windows based on it. + */ + boolean mGivenInsetsPending; + + /** + * These are the content insets that were given during layout for + * this window, to be applied to windows behind it. + */ + final Rect mGivenContentInsets = new Rect(); + + /** + * These are the visible insets that were given during layout for + * this window, to be applied to windows behind it. + */ + final Rect mGivenVisibleInsets = new Rect(); + + /** + * This is the given touchable area relative to the window frame, or null if none. + */ + final Region mGivenTouchableRegion = new Region(); + + /** + * Flag indicating whether the touchable region should be adjusted by + * the visible insets; if false the area outside the visible insets is + * NOT touchable, so we must use those to adjust the frame during hit + * tests. + */ + int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; + + // Current transformation being applied. + boolean mHaveMatrix; + float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1; + float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1; + float mHScale=1, mVScale=1; + float mLastHScale=1, mLastVScale=1; + final Matrix mTmpMatrix = new Matrix(); + + // "Real" frame that the application sees. + final Rect mFrame = new Rect(); + final Rect mLastFrame = new Rect(); + + final Rect mContainingFrame = new Rect(); + final Rect mDisplayFrame = new Rect(); + final Rect mContentFrame = new Rect(); + final Rect mParentFrame = new Rect(); + final Rect mVisibleFrame = new Rect(); + + boolean mContentChanged; + + float mShownAlpha = 1; + float mAlpha = 1; + float mLastAlpha = 1; + + // Set to true if, when the window gets displayed, it should perform + // an enter animation. + boolean mEnterAnimationPending; + + // Currently running animation. + boolean mAnimating; + boolean mLocalAnimating; + Animation mAnimation; + boolean mAnimationIsEntrance; + boolean mHasTransformation; + boolean mHasLocalTransformation; + final Transformation mTransformation = new Transformation(); + + // If a window showing a wallpaper: the requested offset for the + // wallpaper; if a wallpaper window: the currently applied offset. + float mWallpaperX = -1; + float mWallpaperY = -1; + + // If a window showing a wallpaper: what fraction of the offset + // range corresponds to a full virtual screen. + float mWallpaperXStep = -1; + float mWallpaperYStep = -1; + + // Wallpaper windows: pixels offset based on above variables. + int mXOffset; + int mYOffset; + + // This is set after IWindowSession.relayout() has been called at + // least once for the window. It allows us to detect the situation + // where we don't yet have a surface, but should have one soon, so + // we can give the window focus before waiting for the relayout. + boolean mRelayoutCalled; + + // This is set after the Surface has been created but before the + // window has been drawn. During this time the surface is hidden. + boolean mDrawPending; + + // This is set after the window has finished drawing for the first + // time but before its surface is shown. The surface will be + // displayed when the next layout is run. + boolean mCommitDrawPending; + + // This is set during the time after the window's drawing has been + // committed, and before its surface is actually shown. It is used + // to delay showing the surface until all windows in a token are ready + // to be shown. + boolean mReadyToShow; + + // Set when the window has been shown in the screen the first time. + boolean mHasDrawn; + + // Currently running an exit animation? + boolean mExiting; + + // Currently on the mDestroySurface list? + boolean mDestroying; + + // Completely remove from window manager after exit animation? + boolean mRemoveOnExit; + + // Set when the orientation is changing and this window has not yet + // been updated for the new orientation. + boolean mOrientationChanging; + + // Is this window now (or just being) removed? + boolean mRemoved; + + // Temp for keeping track of windows that have been removed when + // rebuilding window list. + boolean mRebuilding; + + // For debugging, this is the last information given to the surface flinger. + boolean mSurfaceShown; + int mSurfaceX, mSurfaceY, mSurfaceW, mSurfaceH; + int mSurfaceLayer; + float mSurfaceAlpha; + + // Input channel and input window handle used by the input dispatcher. + InputWindowHandle mInputWindowHandle; + InputChannel mInputChannel; + + // Used to improve performance of toString() + String mStringNameCache; + CharSequence mLastTitle; + boolean mWasPaused; + + WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, + WindowState attachedWindow, WindowManager.LayoutParams a, + int viewVisibility) { + mService = service; + mSession = s; + mClient = c; + mToken = token; + mAttrs.copyFrom(a); + mViewVisibility = viewVisibility; + DeathRecipient deathRecipient = new DeathRecipient(); + mAlpha = a.alpha; + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Window " + this + " client=" + c.asBinder() + + " token=" + token + " (" + mAttrs.token + ")"); + try { + c.asBinder().linkToDeath(deathRecipient, 0); + } catch (RemoteException e) { + mDeathRecipient = null; + mAttachedWindow = null; + mLayoutAttached = false; + mIsImWindow = false; + mIsWallpaper = false; + mIsFloatingLayer = false; + mBaseLayer = 0; + mSubLayer = 0; + return; + } + mDeathRecipient = deathRecipient; + + if ((mAttrs.type >= FIRST_SUB_WINDOW && + mAttrs.type <= LAST_SUB_WINDOW)) { + // The multiplier here is to reserve space for multiple + // windows in the same type layer. + mBaseLayer = mService.mPolicy.windowTypeToLayerLw( + attachedWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER + + WindowManagerService.TYPE_LAYER_OFFSET; + mSubLayer = mService.mPolicy.subWindowTypeToLayerLw(a.type); + mAttachedWindow = attachedWindow; + if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(WindowManagerService.TAG, "Adding " + this + " to " + mAttachedWindow); + mAttachedWindow.mChildWindows.add(this); + mLayoutAttached = mAttrs.type != + WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; + mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD + || attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG; + mIsWallpaper = attachedWindow.mAttrs.type == TYPE_WALLPAPER; + mIsFloatingLayer = mIsImWindow || mIsWallpaper; + } else { + // The multiplier here is to reserve space for multiple + // windows in the same type layer. + mBaseLayer = mService.mPolicy.windowTypeToLayerLw(a.type) + * WindowManagerService.TYPE_LAYER_MULTIPLIER + + WindowManagerService.TYPE_LAYER_OFFSET; + mSubLayer = 0; + mAttachedWindow = null; + mLayoutAttached = false; + mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD + || mAttrs.type == TYPE_INPUT_METHOD_DIALOG; + mIsWallpaper = mAttrs.type == TYPE_WALLPAPER; + mIsFloatingLayer = mIsImWindow || mIsWallpaper; + } + + WindowState appWin = this; + while (appWin.mAttachedWindow != null) { + appWin = mAttachedWindow; + } + WindowToken appToken = appWin.mToken; + while (appToken.appWindowToken == null) { + WindowToken parent = mService.mTokenMap.get(appToken.token); + if (parent == null || appToken == parent) { + break; + } + appToken = parent; + } + mRootToken = appToken; + mAppToken = appToken.appWindowToken; + + mSurface = null; + mRequestedWidth = 0; + mRequestedHeight = 0; + mLastRequestedWidth = 0; + mLastRequestedHeight = 0; + mXOffset = 0; + mYOffset = 0; + mLayer = 0; + mAnimLayer = 0; + mLastLayer = 0; + mInputWindowHandle = new InputWindowHandle( + mAppToken != null ? mAppToken.mInputApplicationHandle : null, this); + } + + void attach() { + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Attaching " + this + " token=" + mToken + + ", list=" + mToken.windows); + mSession.windowAddedLocked(); + } + + public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) { + mHaveFrame = true; + + final Rect container = mContainingFrame; + container.set(pf); + + final Rect display = mDisplayFrame; + display.set(df); + + if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) { + container.intersect(mService.mCompatibleScreenFrame); + if ((mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) == 0) { + display.intersect(mService.mCompatibleScreenFrame); + } + } + + final int pw = container.right - container.left; + final int ph = container.bottom - container.top; + + int w,h; + if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) { + w = mAttrs.width < 0 ? pw : mAttrs.width; + h = mAttrs.height< 0 ? ph : mAttrs.height; + } else { + w = mAttrs.width == mAttrs.MATCH_PARENT ? pw : mRequestedWidth; + h = mAttrs.height== mAttrs.MATCH_PARENT ? ph : mRequestedHeight; + } + + if (!mParentFrame.equals(pf)) { + //Slog.i(TAG, "Window " + this + " content frame from " + mParentFrame + // + " to " + pf); + mParentFrame.set(pf); + mContentChanged = true; + } + + final Rect content = mContentFrame; + content.set(cf); + + final Rect visible = mVisibleFrame; + visible.set(vf); + + final Rect frame = mFrame; + final int fw = frame.width(); + final int fh = frame.height(); + + //System.out.println("In: w=" + w + " h=" + h + " container=" + + // container + " x=" + mAttrs.x + " y=" + mAttrs.y); + + Gravity.apply(mAttrs.gravity, w, h, container, + (int) (mAttrs.x + mAttrs.horizontalMargin * pw), + (int) (mAttrs.y + mAttrs.verticalMargin * ph), frame); + + //System.out.println("Out: " + mFrame); + + // Now make sure the window fits in the overall display. + Gravity.applyDisplay(mAttrs.gravity, df, frame); + + // Make sure the content and visible frames are inside of the + // final window frame. + if (content.left < frame.left) content.left = frame.left; + if (content.top < frame.top) content.top = frame.top; + if (content.right > frame.right) content.right = frame.right; + if (content.bottom > frame.bottom) content.bottom = frame.bottom; + if (visible.left < frame.left) visible.left = frame.left; + if (visible.top < frame.top) visible.top = frame.top; + if (visible.right > frame.right) visible.right = frame.right; + if (visible.bottom > frame.bottom) visible.bottom = frame.bottom; + + final Rect contentInsets = mContentInsets; + contentInsets.left = content.left-frame.left; + contentInsets.top = content.top-frame.top; + contentInsets.right = frame.right-content.right; + contentInsets.bottom = frame.bottom-content.bottom; + + final Rect visibleInsets = mVisibleInsets; + visibleInsets.left = visible.left-frame.left; + visibleInsets.top = visible.top-frame.top; + visibleInsets.right = frame.right-visible.right; + visibleInsets.bottom = frame.bottom-visible.bottom; + + if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) { + mService.updateWallpaperOffsetLocked(this, mService.mDisplay.getWidth(), + mService.mDisplay.getHeight(), false); + } + + if (WindowManagerService.localLOGV) { + //if ("com.google.android.youtube".equals(mAttrs.packageName) + // && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { + Slog.v(WindowManagerService.TAG, "Resolving (mRequestedWidth=" + + mRequestedWidth + ", mRequestedheight=" + + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph + + "): frame=" + mFrame.toShortString() + + " ci=" + contentInsets.toShortString() + + " vi=" + visibleInsets.toShortString()); + //} + } + } + + public Rect getFrameLw() { + return mFrame; + } + + public Rect getShownFrameLw() { + return mShownFrame; + } + + public Rect getDisplayFrameLw() { + return mDisplayFrame; + } + + public Rect getContentFrameLw() { + return mContentFrame; + } + + public Rect getVisibleFrameLw() { + return mVisibleFrame; + } + + public boolean getGivenInsetsPendingLw() { + return mGivenInsetsPending; + } + + public Rect getGivenContentInsetsLw() { + return mGivenContentInsets; + } + + public Rect getGivenVisibleInsetsLw() { + return mGivenVisibleInsets; + } + + public WindowManager.LayoutParams getAttrs() { + return mAttrs; + } + + public int getSurfaceLayer() { + return mLayer; + } + + public IApplicationToken getAppToken() { + return mAppToken != null ? mAppToken.appToken : null; + } + + public long getInputDispatchingTimeoutNanos() { + return mAppToken != null + ? mAppToken.inputDispatchingTimeoutNanos + : WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; + } + + public boolean hasAppShownWindows() { + return mAppToken != null ? mAppToken.firstWindowDrawn : false; + } + + public void setAnimation(Animation anim) { + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Setting animation in " + this + ": " + anim); + mAnimating = false; + mLocalAnimating = false; + mAnimation = anim; + mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION); + mAnimation.scaleCurrentDuration(mService.mWindowAnimationScale); + } + + public void clearAnimation() { + if (mAnimation != null) { + mAnimating = true; + mLocalAnimating = false; + mAnimation.cancel(); + mAnimation = null; + } + } + + Surface createSurfaceLocked() { + if (mSurface == null) { + mReportDestroySurface = false; + mSurfacePendingDestroy = false; + mDrawPending = true; + mCommitDrawPending = false; + mReadyToShow = false; + if (mAppToken != null) { + mAppToken.allDrawn = false; + } + + int flags = 0; + + if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) { + flags |= Surface.SECURE; + } + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v( + WindowManagerService.TAG, "Creating surface in session " + + mSession.mSurfaceSession + " window " + this + + " w=" + mFrame.width() + + " h=" + mFrame.height() + " format=" + + mAttrs.format + " flags=" + flags); + + int w = mFrame.width(); + int h = mFrame.height(); + if ((mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) { + // for a scaled surface, we always want the requested + // size. + w = mRequestedWidth; + h = mRequestedHeight; + } + + // Something is wrong and SurfaceFlinger will not like this, + // try to revert to sane values + if (w <= 0) w = 1; + if (h <= 0) h = 1; + + mSurfaceShown = false; + mSurfaceLayer = 0; + mSurfaceAlpha = 1; + mSurfaceX = 0; + mSurfaceY = 0; + mSurfaceW = w; + mSurfaceH = h; + try { + final boolean isHwAccelerated = (mAttrs.flags & + WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; + final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : mAttrs.format; + if (isHwAccelerated && mAttrs.format == PixelFormat.OPAQUE) { + flags |= Surface.OPAQUE; + } + mSurface = new Surface( + mSession.mSurfaceSession, mSession.mPid, + mAttrs.getTitle().toString(), + 0, w, h, format, flags); + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " CREATE SURFACE " + + mSurface + " IN SESSION " + + mSession.mSurfaceSession + + ": pid=" + mSession.mPid + " format=" + + mAttrs.format + " flags=0x" + + Integer.toHexString(flags) + + " / " + this); + } catch (Surface.OutOfResourcesException e) { + Slog.w(WindowManagerService.TAG, "OutOfResourcesException creating surface"); + mService.reclaimSomeSurfaceMemoryLocked(this, "create"); + return null; + } catch (Exception e) { + Slog.e(WindowManagerService.TAG, "Exception creating surface", e); + return null; + } + + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Got surface: " + mSurface + + ", set left=" + mFrame.left + " top=" + mFrame.top + + ", animLayer=" + mAnimLayer); + if (WindowManagerService.SHOW_TRANSACTIONS) { + Slog.i(WindowManagerService.TAG, ">>> OPEN TRANSACTION createSurfaceLocked"); + WindowManagerService.logSurface(this, "CREATE pos=(" + mFrame.left + "," + mFrame.top + ") (" + + mFrame.width() + "x" + mFrame.height() + "), layer=" + + mAnimLayer + " HIDE", null); + } + Surface.openTransaction(); + try { + try { + mSurfaceX = mFrame.left + mXOffset; + mSurfaceY = mFrame.top + mYOffset; + mSurface.setPosition(mSurfaceX, mSurfaceY); + mSurfaceLayer = mAnimLayer; + mSurface.setLayer(mAnimLayer); + mSurfaceShown = false; + mSurface.hide(); + if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) { + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "DITHER", null); + mSurface.setFlags(Surface.SURFACE_DITHER, + Surface.SURFACE_DITHER); + } + } catch (RuntimeException e) { + Slog.w(WindowManagerService.TAG, "Error creating surface in " + w, e); + mService.reclaimSomeSurfaceMemoryLocked(this, "create-init"); + } + mLastHidden = true; + } finally { + Surface.closeTransaction(); + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "<<< CLOSE TRANSACTION createSurfaceLocked"); + } + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Created surface " + this); + } + return mSurface; + } + + void destroySurfaceLocked() { + if (mAppToken != null && this == mAppToken.startingWindow) { + mAppToken.startingDisplayed = false; + } + + if (mSurface != null) { + mDrawPending = false; + mCommitDrawPending = false; + mReadyToShow = false; + + int i = mChildWindows.size(); + while (i > 0) { + i--; + WindowState c = mChildWindows.get(i); + c.mAttachedHidden = true; + } + + if (mReportDestroySurface) { + mReportDestroySurface = false; + mSurfacePendingDestroy = true; + try { + mClient.dispatchGetNewSurface(); + // We'll really destroy on the next time around. + return; + } catch (RemoteException e) { + } + } + + try { + if (WindowManagerService.DEBUG_VISIBILITY) { + RuntimeException e = null; + if (!WindowManagerService.HIDE_STACK_CRAWLS) { + e = new RuntimeException(); + e.fillInStackTrace(); + } + Slog.w(WindowManagerService.TAG, "Window " + this + " destroying surface " + + mSurface + ", session " + mSession, e); + } + if (WindowManagerService.SHOW_TRANSACTIONS) { + RuntimeException e = null; + if (!WindowManagerService.HIDE_STACK_CRAWLS) { + e = new RuntimeException(); + e.fillInStackTrace(); + } + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "DESTROY", e); + } + mSurface.destroy(); + } catch (RuntimeException e) { + Slog.w(WindowManagerService.TAG, "Exception thrown when destroying Window " + this + + " surface " + mSurface + " session " + mSession + + ": " + e.toString()); + } + + mSurfaceShown = false; + mSurface = null; + } + } + + boolean finishDrawingLocked() { + if (mDrawPending) { + if (WindowManagerService.SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) Slog.v( + WindowManagerService.TAG, "finishDrawingLocked: " + mSurface); + mCommitDrawPending = true; + mDrawPending = false; + return true; + } + return false; + } + + // This must be called while inside a transaction. + boolean commitFinishDrawingLocked(long currentTime) { + //Slog.i(TAG, "commitFinishDrawingLocked: " + mSurface); + if (!mCommitDrawPending) { + return false; + } + mCommitDrawPending = false; + mReadyToShow = true; + final boolean starting = mAttrs.type == TYPE_APPLICATION_STARTING; + final AppWindowToken atoken = mAppToken; + if (atoken == null || atoken.allDrawn || starting) { + performShowLocked(); + } + return true; + } + + // This must be called while inside a transaction. + boolean performShowLocked() { + if (WindowManagerService.DEBUG_VISIBILITY) { + RuntimeException e = null; + if (!WindowManagerService.HIDE_STACK_CRAWLS) { + e = new RuntimeException(); + e.fillInStackTrace(); + } + Slog.v(WindowManagerService.TAG, "performShow on " + this + + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay() + + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e); + } + if (mReadyToShow && isReadyForDisplay()) { + if (WindowManagerService.SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) WindowManagerService.logSurface(this, + "SHOW (performShowLocked)", null); + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Showing " + this + + " during animation: policyVis=" + mPolicyVisibility + + " attHidden=" + mAttachedHidden + + " tok.hiddenRequested=" + + (mAppToken != null ? mAppToken.hiddenRequested : false) + + " tok.hidden=" + + (mAppToken != null ? mAppToken.hidden : false) + + " animating=" + mAnimating + + " tok animating=" + + (mAppToken != null ? mAppToken.animating : false)); + if (!mService.showSurfaceRobustlyLocked(this)) { + return false; + } + mLastAlpha = -1; + mHasDrawn = true; + mLastHidden = false; + mReadyToShow = false; + mService.enableScreenIfNeededLocked(); + + mService.applyEnterAnimationLocked(this); + + int i = mChildWindows.size(); + while (i > 0) { + i--; + WindowState c = mChildWindows.get(i); + if (c.mAttachedHidden) { + c.mAttachedHidden = false; + if (c.mSurface != null) { + c.performShowLocked(); + // It hadn't been shown, which means layout not + // performed on it, so now we want to make sure to + // do a layout. If called from within the transaction + // loop, this will cause it to restart with a new + // layout. + mService.mLayoutNeeded = true; + } + } + } + + if (mAttrs.type != TYPE_APPLICATION_STARTING + && mAppToken != null) { + mAppToken.firstWindowDrawn = true; + + if (mAppToken.startingData != null) { + if (WindowManagerService.DEBUG_STARTING_WINDOW || WindowManagerService.DEBUG_ANIM) Slog.v(WindowManagerService.TAG, + "Finish starting " + mToken + + ": first real window is shown, no animation"); + // If this initial window is animating, stop it -- we + // will do an animation to reveal it from behind the + // starting window, so there is no need for it to also + // be doing its own stuff. + if (mAnimation != null) { + mAnimation.cancel(); + mAnimation = null; + // Make sure we clean up the animation. + mAnimating = true; + } + mService.mFinishedStarting.add(mAppToken); + mService.mH.sendEmptyMessage(H.FINISHED_STARTING); + } + mAppToken.updateReportedVisibilityLocked(); + } + } + return true; + } + + // This must be called while inside a transaction. Returns true if + // there is more animation to run. + boolean stepAnimationLocked(long currentTime, int dw, int dh) { + if (!mService.mDisplayFrozen && mService.mPolicy.isScreenOn()) { + // We will run animations as long as the display isn't frozen. + + if (!mDrawPending && !mCommitDrawPending && mAnimation != null) { + mHasTransformation = true; + mHasLocalTransformation = true; + if (!mLocalAnimating) { + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Starting animation in " + this + + " @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() + + " dw=" + dw + " dh=" + dh + " scale=" + mService.mWindowAnimationScale); + mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh); + mAnimation.setStartTime(currentTime); + mLocalAnimating = true; + mAnimating = true; + } + mTransformation.clear(); + final boolean more = mAnimation.getTransformation( + currentTime, mTransformation); + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Stepped animation in " + this + + ": more=" + more + ", xform=" + mTransformation); + if (more) { + // we're not done! + return true; + } + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Finished animation in " + this + + " @ " + currentTime); + + if (mAnimation != null) { + mAnimation.cancel(); + mAnimation = null; + } + //WindowManagerService.this.dump(); + } + mHasLocalTransformation = false; + if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null + && mAppToken.animation != null) { + // When our app token is animating, we kind-of pretend like + // we are as well. Note the mLocalAnimating mAnimationIsEntrance + // part of this check means that we will only do this if + // our window is not currently exiting, or it is not + // locally animating itself. The idea being that one that + // is exiting and doing a local animation should be removed + // once that animation is done. + mAnimating = true; + mHasTransformation = true; + mTransformation.clear(); + return false; + } else if (mHasTransformation) { + // Little trick to get through the path below to act like + // we have finished an animation. + mAnimating = true; + } else if (isAnimating()) { + mAnimating = true; + } + } else if (mAnimation != null) { + // If the display is frozen, and there is a pending animation, + // clear it and make sure we run the cleanup code. + mAnimating = true; + mLocalAnimating = true; + mAnimation.cancel(); + mAnimation = null; + } + + if (!mAnimating && !mLocalAnimating) { + return false; + } + + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Animation done in " + this + ": exiting=" + mExiting + + ", reportedVisible=" + + (mAppToken != null ? mAppToken.reportedVisible : false)); + + mAnimating = false; + mLocalAnimating = false; + if (mAnimation != null) { + mAnimation.cancel(); + mAnimation = null; + } + mAnimLayer = mLayer; + if (mIsImWindow) { + mAnimLayer += mService.mInputMethodAnimLayerAdjustment; + } else if (mIsWallpaper) { + mAnimLayer += mService.mWallpaperAnimLayerAdjustment; + } + if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Stepping win " + this + + " anim layer: " + mAnimLayer); + mHasTransformation = false; + mHasLocalTransformation = false; + if (mPolicyVisibility != mPolicyVisibilityAfterAnim) { + if (WindowManagerService.DEBUG_VISIBILITY) { + Slog.v(WindowManagerService.TAG, "Policy visibility changing after anim in " + this + ": " + + mPolicyVisibilityAfterAnim); + } + mPolicyVisibility = mPolicyVisibilityAfterAnim; + if (!mPolicyVisibility) { + if (mService.mCurrentFocus == this) { + mService.mFocusMayChange = true; + } + // Window is no longer visible -- make sure if we were waiting + // for it to be displayed before enabling the display, that + // we allow the display to be enabled now. + mService.enableScreenIfNeededLocked(); + } + } + mTransformation.clear(); + if (mHasDrawn + && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING + && mAppToken != null + && mAppToken.firstWindowDrawn + && mAppToken.startingData != null) { + if (WindowManagerService.DEBUG_STARTING_WINDOW) Slog.v(WindowManagerService.TAG, "Finish starting " + + mToken + ": first real window done animating"); + mService.mFinishedStarting.add(mAppToken); + mService.mH.sendEmptyMessage(H.FINISHED_STARTING); + } + + finishExit(); + + if (mAppToken != null) { + mAppToken.updateReportedVisibilityLocked(); + } + + return false; + } + + void finishExit() { + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "finishExit in " + this + + ": exiting=" + mExiting + + " remove=" + mRemoveOnExit + + " windowAnimating=" + isWindowAnimating()); + + final int N = mChildWindows.size(); + for (int i=0; i<N; i++) { + mChildWindows.get(i).finishExit(); + } + + if (!mExiting) { + return; + } + + if (isWindowAnimating()) { + return; + } + + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Exit animation finished in " + this + + ": remove=" + mRemoveOnExit); + if (mSurface != null) { + mService.mDestroySurface.add(this); + mDestroying = true; + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "HIDE (finishExit)", null); + mSurfaceShown = false; + try { + mSurface.hide(); + } catch (RuntimeException e) { + Slog.w(WindowManagerService.TAG, "Error hiding surface in " + this, e); + } + mLastHidden = true; + } + mExiting = false; + if (mRemoveOnExit) { + mService.mPendingRemove.add(this); + mRemoveOnExit = false; + } + } + + boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { + if (dsdx < .99999f || dsdx > 1.00001f) return false; + if (dtdy < .99999f || dtdy > 1.00001f) return false; + if (dtdx < -.000001f || dtdx > .000001f) return false; + if (dsdy < -.000001f || dsdy > .000001f) return false; + return true; + } + + void computeShownFrameLocked() { + final boolean selfTransformation = mHasLocalTransformation; + Transformation attachedTransformation = + (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation) + ? mAttachedWindow.mTransformation : null; + Transformation appTransformation = + (mAppToken != null && mAppToken.hasTransformation) + ? mAppToken.transformation : null; + + // Wallpapers are animated based on the "real" window they + // are currently targeting. + if (mAttrs.type == TYPE_WALLPAPER && mService.mLowerWallpaperTarget == null + && mService.mWallpaperTarget != null) { + if (mService.mWallpaperTarget.mHasLocalTransformation && + mService.mWallpaperTarget.mAnimation != null && + !mService.mWallpaperTarget.mAnimation.getDetachWallpaper()) { + attachedTransformation = mService.mWallpaperTarget.mTransformation; + if (WindowManagerService.DEBUG_WALLPAPER && attachedTransformation != null) { + Slog.v(WindowManagerService.TAG, "WP target attached xform: " + attachedTransformation); + } + } + if (mService.mWallpaperTarget.mAppToken != null && + mService.mWallpaperTarget.mAppToken.hasTransformation && + mService.mWallpaperTarget.mAppToken.animation != null && + !mService.mWallpaperTarget.mAppToken.animation.getDetachWallpaper()) { + appTransformation = mService.mWallpaperTarget.mAppToken.transformation; + if (WindowManagerService.DEBUG_WALLPAPER && appTransformation != null) { + Slog.v(WindowManagerService.TAG, "WP target app xform: " + appTransformation); + } + } + } + + final boolean screenAnimation = mService.mScreenRotationAnimation != null + && mService.mScreenRotationAnimation.isAnimating(); + if (selfTransformation || attachedTransformation != null + || appTransformation != null || screenAnimation) { + // cache often used attributes locally + final Rect frame = mFrame; + final float tmpFloats[] = mService.mTmpFloats; + final Matrix tmpMatrix = mTmpMatrix; + + // Compute the desired transformation. + tmpMatrix.setTranslate(0, 0); + if (selfTransformation) { + tmpMatrix.postConcat(mTransformation.getMatrix()); + } + tmpMatrix.postTranslate(frame.left + mXOffset, frame.top + mYOffset); + if (attachedTransformation != null) { + tmpMatrix.postConcat(attachedTransformation.getMatrix()); + } + if (appTransformation != null) { + tmpMatrix.postConcat(appTransformation.getMatrix()); + } + if (screenAnimation) { + tmpMatrix.postConcat( + mService.mScreenRotationAnimation.getEnterTransformation().getMatrix()); + } + + // "convert" it into SurfaceFlinger's format + // (a 2x2 matrix + an offset) + // Here we must not transform the position of the surface + // since it is already included in the transformation. + //Slog.i(TAG, "Transform: " + matrix); + + mHaveMatrix = true; + tmpMatrix.getValues(tmpFloats); + mDsDx = tmpFloats[Matrix.MSCALE_X]; + mDtDx = tmpFloats[Matrix.MSKEW_Y]; + mDsDy = tmpFloats[Matrix.MSKEW_X]; + mDtDy = tmpFloats[Matrix.MSCALE_Y]; + int x = (int)tmpFloats[Matrix.MTRANS_X]; + int y = (int)tmpFloats[Matrix.MTRANS_Y]; + int w = frame.width(); + int h = frame.height(); + mShownFrame.set(x, y, x+w, y+h); + + // Now set the alpha... but because our current hardware + // can't do alpha transformation on a non-opaque surface, + // turn it off if we are running an animation that is also + // transforming since it is more important to have that + // animation be smooth. + mShownAlpha = mAlpha; + if (!mService.mLimitedAlphaCompositing + || (!PixelFormat.formatHasAlpha(mAttrs.format) + || (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy) + && x == frame.left && y == frame.top))) { + //Slog.i(TAG, "Applying alpha transform"); + if (selfTransformation) { + mShownAlpha *= mTransformation.getAlpha(); + } + if (attachedTransformation != null) { + mShownAlpha *= attachedTransformation.getAlpha(); + } + if (appTransformation != null) { + mShownAlpha *= appTransformation.getAlpha(); + } + if (screenAnimation) { + mShownAlpha *= + mService.mScreenRotationAnimation.getEnterTransformation().getAlpha(); + } + } else { + //Slog.i(TAG, "Not applying alpha transform"); + } + + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Continuing animation in " + this + + ": " + mShownFrame + + ", alpha=" + mTransformation.getAlpha()); + return; + } + + mShownFrame.set(mFrame); + if (mXOffset != 0 || mYOffset != 0) { + mShownFrame.offset(mXOffset, mYOffset); + } + mShownAlpha = mAlpha; + mHaveMatrix = false; + mDsDx = 1; + mDtDx = 0; + mDsDy = 0; + mDtDy = 1; + } + + /** + * Is this window visible? It is not visible if there is no + * surface, or we are in the process of running an exit animation + * that will remove the surface, or its app token has been hidden. + */ + public boolean isVisibleLw() { + final AppWindowToken atoken = mAppToken; + return mSurface != null && mPolicyVisibility && !mAttachedHidden + && (atoken == null || !atoken.hiddenRequested) + && !mExiting && !mDestroying; + } + + /** + * Like {@link #isVisibleLw}, but also counts a window that is currently + * "hidden" behind the keyguard as visible. This allows us to apply + * things like window flags that impact the keyguard. + * XXX I am starting to think we need to have ANOTHER visibility flag + * for this "hidden behind keyguard" state rather than overloading + * mPolicyVisibility. Ungh. + */ + public boolean isVisibleOrBehindKeyguardLw() { + final AppWindowToken atoken = mAppToken; + return mSurface != null && !mAttachedHidden + && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested) + && !mDrawPending && !mCommitDrawPending + && !mExiting && !mDestroying; + } + + /** + * Is this window visible, ignoring its app token? It is not visible + * if there is no surface, or we are in the process of running an exit animation + * that will remove the surface. + */ + public boolean isWinVisibleLw() { + final AppWindowToken atoken = mAppToken; + return mSurface != null && mPolicyVisibility && !mAttachedHidden + && (atoken == null || !atoken.hiddenRequested || atoken.animating) + && !mExiting && !mDestroying; + } + + /** + * The same as isVisible(), but follows the current hidden state of + * the associated app token, not the pending requested hidden state. + */ + boolean isVisibleNow() { + return mSurface != null && mPolicyVisibility && !mAttachedHidden + && !mRootToken.hidden && !mExiting && !mDestroying; + } + + /** + * Can this window possibly be a drag/drop target? The test here is + * a combination of the above "visible now" with the check that the + * Input Manager uses when discarding windows from input consideration. + */ + boolean isPotentialDragTarget() { + return isVisibleNow() && (mInputChannel != null) && !mRemoved; + } + + /** + * Same as isVisible(), but we also count it as visible between the + * call to IWindowSession.add() and the first relayout(). + */ + boolean isVisibleOrAdding() { + final AppWindowToken atoken = mAppToken; + return ((mSurface != null && !mReportDestroySurface) + || (!mRelayoutCalled && mViewVisibility == View.VISIBLE)) + && mPolicyVisibility && !mAttachedHidden + && (atoken == null || !atoken.hiddenRequested) + && !mExiting && !mDestroying; + } + + /** + * Is this window currently on-screen? It is on-screen either if it + * is visible or it is currently running an animation before no longer + * being visible. + */ + boolean isOnScreen() { + final AppWindowToken atoken = mAppToken; + if (atoken != null) { + return mSurface != null && mPolicyVisibility && !mDestroying + && ((!mAttachedHidden && !atoken.hiddenRequested) + || mAnimation != null || atoken.animation != null); + } else { + return mSurface != null && mPolicyVisibility && !mDestroying + && (!mAttachedHidden || mAnimation != null); + } + } + + /** + * Like isOnScreen(), but we don't return true if the window is part + * of a transition that has not yet been started. + */ + boolean isReadyForDisplay() { + if (mRootToken.waitingToShow && + mService.mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { + return false; + } + final AppWindowToken atoken = mAppToken; + final boolean animating = atoken != null + ? (atoken.animation != null) : false; + return mSurface != null && mPolicyVisibility && !mDestroying + && ((!mAttachedHidden && mViewVisibility == View.VISIBLE + && !mRootToken.hidden) + || mAnimation != null || animating); + } + + /** Is the window or its container currently animating? */ + boolean isAnimating() { + final WindowState attached = mAttachedWindow; + final AppWindowToken atoken = mAppToken; + return mAnimation != null + || (attached != null && attached.mAnimation != null) + || (atoken != null && + (atoken.animation != null + || atoken.inPendingTransaction)); + } + + /** Is this window currently animating? */ + boolean isWindowAnimating() { + return mAnimation != null; + } + + /** + * Like isOnScreen, but returns false if the surface hasn't yet + * been drawn. + */ + public boolean isDisplayedLw() { + final AppWindowToken atoken = mAppToken; + return mSurface != null && mPolicyVisibility && !mDestroying + && !mDrawPending && !mCommitDrawPending + && ((!mAttachedHidden && + (atoken == null || !atoken.hiddenRequested)) + || mAnimating); + } + + /** + * Returns true if the window has a surface that it has drawn a + * complete UI in to. + */ + public boolean isDrawnLw() { + final AppWindowToken atoken = mAppToken; + return mSurface != null && !mDestroying + && !mDrawPending && !mCommitDrawPending; + } + + /** + * Return true if the window is opaque and fully drawn. This indicates + * it may obscure windows behind it. + */ + boolean isOpaqueDrawn() { + return (mAttrs.format == PixelFormat.OPAQUE + || mAttrs.type == TYPE_WALLPAPER) + && mSurface != null && mAnimation == null + && (mAppToken == null || mAppToken.animation == null) + && !mDrawPending && !mCommitDrawPending; + } + + /** + * Return whether this window is wanting to have a translation + * animation applied to it for an in-progress move. (Only makes + * sense to call from performLayoutAndPlaceSurfacesLockedInner().) + */ + boolean shouldAnimateMove() { + return mContentChanged && !mExiting && !mLastHidden && !mService.mDisplayFrozen + && (mFrame.top != mLastFrame.top + || mFrame.left != mLastFrame.left) + && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove()) + && mService.mPolicy.isScreenOn(); + } + + boolean needsBackgroundFiller(int screenWidth, int screenHeight) { + return + // only if the application is requesting compatible window + (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0 && + // only if it's visible + mHasDrawn && mViewVisibility == View.VISIBLE && + // and only if the application fills the compatible screen + mFrame.left <= mService.mCompatibleScreenFrame.left && + mFrame.top <= mService.mCompatibleScreenFrame.top && + mFrame.right >= mService.mCompatibleScreenFrame.right && + mFrame.bottom >= mService.mCompatibleScreenFrame.bottom; + } + + boolean isFullscreen(int screenWidth, int screenHeight) { + return mFrame.left <= 0 && mFrame.top <= 0 && + mFrame.right >= screenWidth && mFrame.bottom >= screenHeight; + } + + void removeLocked() { + disposeInputChannel(); + + if (mAttachedWindow != null) { + if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(WindowManagerService.TAG, "Removing " + this + " from " + mAttachedWindow); + mAttachedWindow.mChildWindows.remove(this); + } + destroySurfaceLocked(); + mSession.windowRemovedLocked(); + try { + mClient.asBinder().unlinkToDeath(mDeathRecipient, 0); + } catch (RuntimeException e) { + // Ignore if it has already been removed (usually because + // we are doing this as part of processing a death note.) + } + } + + void disposeInputChannel() { + if (mInputChannel != null) { + mService.mInputManager.unregisterInputChannel(mInputChannel); + + mInputChannel.dispose(); + mInputChannel = null; + } + } + + private class DeathRecipient implements IBinder.DeathRecipient { + public void binderDied() { + try { + synchronized(mService.mWindowMap) { + WindowState win = mService.windowForClientLocked(mSession, mClient, false); + Slog.i(WindowManagerService.TAG, "WIN DEATH: " + win); + if (win != null) { + mService.removeWindowLocked(mSession, win); + } + } + } catch (IllegalArgumentException ex) { + // This will happen if the window has already been + // removed. + } + } + } + + /** Returns true if this window desires key events. */ + public final boolean canReceiveKeys() { + return isVisibleOrAdding() + && (mViewVisibility == View.VISIBLE) + && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0); + } + + public boolean hasDrawnLw() { + return mHasDrawn; + } + + public boolean showLw(boolean doAnimation) { + return showLw(doAnimation, true); + } + + boolean showLw(boolean doAnimation, boolean requestAnim) { + if (mPolicyVisibility && mPolicyVisibilityAfterAnim) { + return false; + } + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility true: " + this); + if (doAnimation) { + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "doAnimation: mPolicyVisibility=" + + mPolicyVisibility + " mAnimation=" + mAnimation); + if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOn()) { + doAnimation = false; + } else if (mPolicyVisibility && mAnimation == null) { + // Check for the case where we are currently visible and + // not animating; we do not want to do animation at such a + // point to become visible when we already are. + doAnimation = false; + } + } + mPolicyVisibility = true; + mPolicyVisibilityAfterAnim = true; + if (doAnimation) { + mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true); + } + if (requestAnim) { + mService.requestAnimationLocked(0); + } + return true; + } + + public boolean hideLw(boolean doAnimation) { + return hideLw(doAnimation, true); + } + + boolean hideLw(boolean doAnimation, boolean requestAnim) { + if (doAnimation) { + if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOn()) { + doAnimation = false; + } + } + boolean current = doAnimation ? mPolicyVisibilityAfterAnim + : mPolicyVisibility; + if (!current) { + return false; + } + if (doAnimation) { + mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false); + if (mAnimation == null) { + doAnimation = false; + } + } + if (doAnimation) { + mPolicyVisibilityAfterAnim = false; + } else { + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility false: " + this); + mPolicyVisibilityAfterAnim = false; + mPolicyVisibility = false; + // Window is no longer visible -- make sure if we were waiting + // for it to be displayed before enabling the display, that + // we allow the display to be enabled now. + mService.enableScreenIfNeededLocked(); + if (mService.mCurrentFocus == this) { + mService.mFocusMayChange = true; + } + } + if (requestAnim) { + mService.requestAnimationLocked(0); + } + return true; + } + + public void getTouchableRegion(Region outRegion) { + final Rect frame = mFrame; + switch (mTouchableInsets) { + default: + case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME: + outRegion.set(frame); + break; + case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: { + final Rect inset = mGivenContentInsets; + outRegion.set( + frame.left + inset.left, frame.top + inset.top, + frame.right - inset.right, frame.bottom - inset.bottom); + break; + } + case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: { + final Rect inset = mGivenVisibleInsets; + outRegion.set( + frame.left + inset.left, frame.top + inset.top, + frame.right - inset.right, frame.bottom - inset.bottom); + break; + } + case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION: { + final Region givenTouchableRegion = mGivenTouchableRegion; + outRegion.set(givenTouchableRegion); + outRegion.translate(frame.left, frame.top); + break; + } + } + } + + void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("mSession="); pw.print(mSession); + pw.print(" mClient="); pw.println(mClient.asBinder()); + pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs); + if (mAttachedWindow != null || mLayoutAttached) { + pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow); + pw.print(" mLayoutAttached="); pw.println(mLayoutAttached); + } + if (mIsImWindow || mIsWallpaper || mIsFloatingLayer) { + pw.print(prefix); pw.print("mIsImWindow="); pw.print(mIsImWindow); + pw.print(" mIsWallpaper="); pw.print(mIsWallpaper); + pw.print(" mIsFloatingLayer="); pw.print(mIsFloatingLayer); + pw.print(" mWallpaperVisible="); pw.println(mWallpaperVisible); + } + pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer); + pw.print(" mSubLayer="); pw.print(mSubLayer); + pw.print(" mAnimLayer="); pw.print(mLayer); pw.print("+"); + pw.print((mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment + : (mAppToken != null ? mAppToken.animLayerAdjustment : 0))); + pw.print("="); pw.print(mAnimLayer); + pw.print(" mLastLayer="); pw.println(mLastLayer); + if (mSurface != null) { + pw.print(prefix); pw.print("mSurface="); pw.println(mSurface); + pw.print(prefix); pw.print("Surface: shown="); pw.print(mSurfaceShown); + pw.print(" layer="); pw.print(mSurfaceLayer); + pw.print(" alpha="); pw.print(mSurfaceAlpha); + pw.print(" rect=("); pw.print(mSurfaceX); + pw.print(","); pw.print(mSurfaceY); + pw.print(") "); pw.print(mSurfaceW); + pw.print(" x "); pw.println(mSurfaceH); + } + pw.print(prefix); pw.print("mToken="); pw.println(mToken); + pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken); + if (mAppToken != null) { + pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken); + } + if (mTargetAppToken != null) { + pw.print(prefix); pw.print("mTargetAppToken="); pw.println(mTargetAppToken); + } + pw.print(prefix); pw.print("mViewVisibility=0x"); + pw.print(Integer.toHexString(mViewVisibility)); + pw.print(" mLastHidden="); pw.print(mLastHidden); + pw.print(" mHaveFrame="); pw.print(mHaveFrame); + pw.print(" mObscured="); pw.println(mObscured); + if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) { + pw.print(prefix); pw.print("mPolicyVisibility="); + pw.print(mPolicyVisibility); + pw.print(" mPolicyVisibilityAfterAnim="); + pw.print(mPolicyVisibilityAfterAnim); + pw.print(" mAttachedHidden="); pw.println(mAttachedHidden); + } + if (!mRelayoutCalled) { + pw.print(prefix); pw.print("mRelayoutCalled="); pw.println(mRelayoutCalled); + } + pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth); + pw.print(" h="); pw.print(mRequestedHeight); + pw.print(" mLayoutSeq="); pw.println(mLayoutSeq); + if (mXOffset != 0 || mYOffset != 0) { + pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset); + pw.print(" y="); pw.println(mYOffset); + } + pw.print(prefix); pw.print("mGivenContentInsets="); + mGivenContentInsets.printShortString(pw); + pw.print(" mGivenVisibleInsets="); + mGivenVisibleInsets.printShortString(pw); + pw.println(); + if (mTouchableInsets != 0 || mGivenInsetsPending) { + pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets); + pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending); + } + pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration); + pw.print(prefix); pw.print("mShownFrame="); + mShownFrame.printShortString(pw); + pw.print(" last="); mLastShownFrame.printShortString(pw); + pw.println(); + pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw); + pw.print(" last="); mLastFrame.printShortString(pw); + pw.println(); + pw.print(prefix); pw.print("mContainingFrame="); + mContainingFrame.printShortString(pw); + pw.print(" mParentFrame="); + mParentFrame.printShortString(pw); + pw.print(" mDisplayFrame="); + mDisplayFrame.printShortString(pw); + pw.println(); + pw.print(prefix); pw.print("mContentFrame="); mContentFrame.printShortString(pw); + pw.print(" mVisibleFrame="); mVisibleFrame.printShortString(pw); + pw.println(); + pw.print(prefix); pw.print("mContentInsets="); mContentInsets.printShortString(pw); + pw.print(" last="); mLastContentInsets.printShortString(pw); + pw.print(" mVisibleInsets="); mVisibleInsets.printShortString(pw); + pw.print(" last="); mLastVisibleInsets.printShortString(pw); + pw.println(); + if (mAnimating || mLocalAnimating || mAnimationIsEntrance + || mAnimation != null) { + pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating); + pw.print(" mLocalAnimating="); pw.print(mLocalAnimating); + pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance); + pw.print(" mAnimation="); pw.println(mAnimation); + } + if (mHasTransformation || mHasLocalTransformation) { + pw.print(prefix); pw.print("XForm: has="); + pw.print(mHasTransformation); + pw.print(" hasLocal="); pw.print(mHasLocalTransformation); + pw.print(" "); mTransformation.printShortString(pw); + pw.println(); + } + if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) { + pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha); + pw.print(" mAlpha="); pw.print(mAlpha); + pw.print(" mLastAlpha="); pw.println(mLastAlpha); + } + if (mHaveMatrix) { + pw.print(prefix); pw.print("mDsDx="); pw.print(mDsDx); + pw.print(" mDtDx="); pw.print(mDtDx); + pw.print(" mDsDy="); pw.print(mDsDy); + pw.print(" mDtDy="); pw.println(mDtDy); + } + pw.print(prefix); pw.print("mDrawPending="); pw.print(mDrawPending); + pw.print(" mCommitDrawPending="); pw.print(mCommitDrawPending); + pw.print(" mReadyToShow="); pw.print(mReadyToShow); + pw.print(" mHasDrawn="); pw.println(mHasDrawn); + if (mExiting || mRemoveOnExit || mDestroying || mRemoved) { + pw.print(prefix); pw.print("mExiting="); pw.print(mExiting); + pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit); + pw.print(" mDestroying="); pw.print(mDestroying); + pw.print(" mRemoved="); pw.println(mRemoved); + } + if (mOrientationChanging || mAppFreezing || mTurnOnScreen) { + pw.print(prefix); pw.print("mOrientationChanging="); + pw.print(mOrientationChanging); + pw.print(" mAppFreezing="); pw.print(mAppFreezing); + pw.print(" mTurnOnScreen="); pw.println(mTurnOnScreen); + } + if (mHScale != 1 || mVScale != 1) { + pw.print(prefix); pw.print("mHScale="); pw.print(mHScale); + pw.print(" mVScale="); pw.println(mVScale); + } + if (mWallpaperX != -1 || mWallpaperY != -1) { + pw.print(prefix); pw.print("mWallpaperX="); pw.print(mWallpaperX); + pw.print(" mWallpaperY="); pw.println(mWallpaperY); + } + if (mWallpaperXStep != -1 || mWallpaperYStep != -1) { + pw.print(prefix); pw.print("mWallpaperXStep="); pw.print(mWallpaperXStep); + pw.print(" mWallpaperYStep="); pw.println(mWallpaperYStep); + } + } + + String makeInputChannelName() { + return Integer.toHexString(System.identityHashCode(this)) + + " " + mAttrs.getTitle(); + } + + @Override + public String toString() { + if (mStringNameCache == null || mLastTitle != mAttrs.getTitle() + || mWasPaused != mToken.paused) { + mLastTitle = mAttrs.getTitle(); + mWasPaused = mToken.paused; + mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this)) + + " " + mLastTitle + " paused=" + mWasPaused + "}"; + } + return mStringNameCache; + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/wm/WindowToken.java b/services/java/com/android/server/wm/WindowToken.java new file mode 100644 index 000000000000..3cd256e85054 --- /dev/null +++ b/services/java/com/android/server/wm/WindowToken.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2011 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 com.android.server.wm; + +import android.os.IBinder; + +import java.io.PrintWriter; +import java.util.ArrayList; + +/** + * Container of a set of related windows in the window manager. Often this + * is an AppWindowToken, which is the handle for an Activity that it uses + * to display windows. For nested windows, there is a WindowToken created for + * the parent window to manage its children. + */ +class WindowToken { + // The window manager! + final WindowManagerService service; + + // The actual token. + final IBinder token; + + // The type of window this token is for, as per WindowManager.LayoutParams. + final int windowType; + + // Set if this token was explicitly added by a client, so should + // not be removed when all windows are removed. + final boolean explicit; + + // For printing. + String stringName; + + // If this is an AppWindowToken, this is non-null. + AppWindowToken appWindowToken; + + // All of the windows associated with this token. + final ArrayList<WindowState> windows = new ArrayList<WindowState>(); + + // Is key dispatching paused for this token? + boolean paused = false; + + // Should this token's windows be hidden? + boolean hidden; + + // Temporary for finding which tokens no longer have visible windows. + boolean hasVisible; + + // Set to true when this token is in a pending transaction where it + // will be shown. + boolean waitingToShow; + + // Set to true when this token is in a pending transaction where it + // will be hidden. + boolean waitingToHide; + + // Set to true when this token is in a pending transaction where its + // windows will be put to the bottom of the list. + boolean sendingToBottom; + + // Set to true when this token is in a pending transaction where its + // windows will be put to the top of the list. + boolean sendingToTop; + + WindowToken(WindowManagerService _service, IBinder _token, int type, boolean _explicit) { + service = _service; + token = _token; + windowType = type; + explicit = _explicit; + } + + void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("token="); pw.println(token); + pw.print(prefix); pw.print("windows="); pw.println(windows); + pw.print(prefix); pw.print("windowType="); pw.print(windowType); + pw.print(" hidden="); pw.print(hidden); + pw.print(" hasVisible="); pw.println(hasVisible); + if (waitingToShow || waitingToHide || sendingToBottom || sendingToTop) { + pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow); + pw.print(" waitingToHide="); pw.print(waitingToHide); + pw.print(" sendingToBottom="); pw.print(sendingToBottom); + pw.print(" sendingToTop="); pw.println(sendingToTop); + } + } + + @Override + public String toString() { + if (stringName == null) { + StringBuilder sb = new StringBuilder(); + sb.append("WindowToken{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" token="); sb.append(token); sb.append('}'); + stringName = sb.toString(); + } + return stringName; + } +}
\ No newline at end of file |