// TODO Push resumeArgs into the activity for consideration final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); ...... final Activity a = r.activity;
if (localLOGV) { Slog.v(TAG, "Resume " + r + " started activity: " + a.mStartedActivity + ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished); }
X:\frameworks\base\core\java\android\view\ViewRootImpl.java final W mWindow; publicfinal Surface mSurface = new Surface(); final ViewRootHandler mHandler = new ViewRootHandler(); ......
publicViewRootImpl(Context context, Display display){ mContext = context; mWindowSession = WindowManagerGlobal.getWindowSession(); mDisplay = display; mBasePackageName = context.getBasePackageName(); mThread = Thread.currentThread(); mLocation = new WindowLeaked(null); mLocation.fillInStackTrace(); mWidth = -1; mHeight = -1; mDirty = new Rect(); mTempRect = new Rect(); mVisRect = new Rect(); mWinFrame = new Rect(); mWindow = new W(this); mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; mViewVisibility = View.GONE; mTransparentRegion = new Region(); mPreviousTransparentRegion = new Region(); mFirst = true; // true for the first time the view is added mPerformContentCapture = true; // also true for the first time the view is added mAdded = false; mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this, context); mAccessibilityManager = AccessibilityManager.getInstance(context); mAccessibilityManager.addAccessibilityStateChangeListener( mAccessibilityInteractionConnectionManager, mHandler); mHighContrastTextManager = new HighContrastTextManager(); mAccessibilityManager.addHighTextContrastStateChangeListener( mHighContrastTextManager, mHandler); mViewConfiguration = ViewConfiguration.get(context); mDensity = context.getResources().getDisplayMetrics().densityDpi; mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi; mFallbackEventHandler = new PhoneFallbackEventHandler(context); mChoreographer = Choreographer.getInstance(); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
String processorOverrideName = context.getResources().getString( R.string.config_inputEventCompatProcessorOverrideClassName); if (processorOverrideName.isEmpty()) { // No compatibility processor override, using default. mInputCompatProcessor = new InputEventCompatProcessor(context); } else { InputEventCompatProcessor compatProcessor = null; try { final Class<? extends InputEventCompatProcessor> klass = (Class<? extends InputEventCompatProcessor>) Class.forName( processorOverrideName); compatProcessor = klass.getConstructor(Context.class).newInstance(context); } catch (Exception e) { Log.e(TAG, "Unable to create the InputEventCompatProcessor. ", e); } finally { mInputCompatProcessor = compatProcessor; } }
if (!sCompatibilityDone) { sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P;
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; for (int i = 0; i <= CALLBACK_LAST; i++) { mCallbackQueues[i] = new CallbackQueue(); } // b/68769804: For low FPS experiments. setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1)); }
void EventThread::Connection::onFirstRef() { // NOTE: mEventThread doesn't hold a strong reference on us mEventThread->registerDisplayEventConnection(this); }
scheduleFrameLocked(long now) { if (!mFrameScheduled) { mFrameScheduled = true; ...... if (USE_VSYNC) { if (DEBUG_FRAMES) { Log.d(TAG, "Scheduling next frame on vsync."); }
// If running on the Looper thread, then schedule the vsync immediately, // otherwise post a message to schedule the vsync from the UI thread // as soon as possible. if (isRunningOnLooperThreadLocked()) { scheduleVsyncLocked(); } else { Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); msg.setAsynchronous(true); mHandler.sendMessageAtFrontOfQueue(msg); } } else { finallong nextFrameTime = Math.max( mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now); if (DEBUG_FRAMES) { Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms."); } Message msg = mHandler.obtainMessage(MSG_DO_FRAME); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, nextFrameTime); } } }
X:\frameworks\base\core\java\android\view\DisplayEventReceiver.java publicvoidscheduleVsync(){ if (mReceiverPtr == 0) { Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event " + "receiver has already been disposed."); } else { nativeScheduleVsync(mReceiverPtr); } }
1 2 3 4 5 6 7 8 9 10 11
X:\frameworks\base\core\jni\android_view_DisplayEventReceiver.cpp staticvoidnativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr){ sp<NativeDisplayEventReceiver> receiver = reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr); status_t status = receiver->scheduleVsync(); if (status) { String8 message; message.appendFormat("Failed to schedule next vertical sync pulse. status=%d", status); jniThrowRuntimeException(env, message.string()); } }
// dispatch events to listeners... constsize_t count = signalConnections.size(); for (size_t i = 0; i < count; i++) { const sp<Connection>& conn(signalConnections[i]); // now see if we still need to report this event status_t err = conn->postEvent(event); if (err == -EAGAIN || err == -EWOULDBLOCK) { // The destination doesn't accept events anymore, it's probably // full. For now, we just drop the events on the floor. // FIXME: Note that some events cannot be dropped and would have // to be re-sent later. // Right-now we don't have the ability to do this. ALOGW("EventThread: dropping event (%08x) for connection %p", event.header.type, conn.get()); } elseif (err < 0) { // handle any other error on the pipe as fatal. the only // reasonable thing to do is to clean-up this connection. // The most common error we'll get here is -EPIPE. removeDisplayEventConnectionLocked(signalConnections[i]); } } } }
publicintaddWindow(Session session, IWindow client, int seq, LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel){ int[] appOp = newint[1]; ......
boolean reportNewConfig = false; WindowState parentWindow = null; long origId; finalint callingUid = Binder.getCallingUid(); finalint type = attrs.type;
mFocusingActivity = attrs.getTitle().toString();
synchronized(mWindowMap) { ....... final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
......
AppWindowToken atoken = null; finalboolean hasParent = parentWindow != null; // Use existing parent window token for child windows since they go in the same token // as there parent window so we can apply the same policy on them. WindowToken token = displayContent.getWindowToken( hasParent ? parentWindow.mAttrs.token : attrs.token); // If this is a child window, we want to apply the same type checking rules as the // parent window type. finalint rootType = hasParent ? parentWindow.mAttrs.type : type;
boolean addToastWindowRequiresToken = false;
if (token == null) { ....... final IBinder binder = attrs.token != null ? attrs.token : client.asBinder(); finalboolean isRoundedCornerOverlay = (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0; token = new WindowToken(this, binder, type, false, displayContent, session.mCanAddInternalSystemWindow, isRoundedCornerOverlay); } ...... } elseif (token.asAppWindowToken() != null) { Slog.w(TAG_WM, "Non-null appWindowToken for system window of rootType=" + rootType); // It is not valid to use an app token with other system types; we will // instead make a new token for it (as if null had been passed in for the token). attrs.token = null; token = new WindowToken(this, client.asBinder(), type, false, displayContent, session.mCanAddInternalSystemWindow); }
final WindowState win = new WindowState(this, session, client, token, parentWindow, appOp[0], seq, attrs, viewVisibility, session.mUid, session.mCanAddInternalSystemWindow); ......
if (type == TYPE_INPUT_METHOD) { win.mGivenInsetsPending = true; setInputMethodWindowLocked(win); imMayMove = false; } elseif (type == TYPE_INPUT_METHOD_DIALOG) { displayContent.computeImeTarget(true/* updateImeTarget */); imMayMove = false; } else { if (type == TYPE_WALLPAPER) { displayContent.mWallpaperController.clearLastWallpaperTimeoutTime(); displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; } elseif ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) { displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; } elseif (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) { // If there is currently a wallpaper being shown, and // the base layer of the new window is below the current // layer of the target window, then adjust the wallpaper. // This is to avoid a new window being placed between the // wallpaper and its target. displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; } }
// If the window is being added to a stack that's currently adjusted for IME, // make sure to apply the same adjust to this new window. win.applyAdjustForImeIfNeeded();
if (type == TYPE_DOCK_DIVIDER) { mRoot.getDisplayContent(displayId).getDockedDividerController().setWindow(win); }
final WindowStateAnimator winAnimator = win.mWinAnimator; winAnimator.mEnterAnimationPending = true; winAnimator.mEnteringAnimation = true; // Check if we need to prepare a transition for replacing window first. if (atoken != null && atoken.isVisible() && !prepareWindowReplacementTransition(atoken)) { // If not, check if need to set up a dummy transition during display freeze // so that the unfreeze wait for the apps to draw. This might be needed if // the app is relaunching. prepareNoneTransitionForRelaunching(atoken); }
final DisplayFrames displayFrames = displayContent.mDisplayFrames; // TODO: Not sure if onDisplayInfoUpdated() call is needed. final DisplayInfo displayInfo = displayContent.getDisplayInfo(); displayFrames.onDisplayInfoUpdated(displayInfo, displayContent.calculateDisplayCutoutForRotation(displayInfo.rotation)); final Rect taskBounds; if (atoken != null && atoken.getTask() != null) { taskBounds = mTmpRect; atoken.getTask().getBounds(mTmpRect); } else { taskBounds = null; } if (mPolicy.getLayoutHintLw(win.mAttrs, taskBounds, displayFrames, outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout)) { res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR; }
if (mInTouchMode) { res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE; } if (win.mAppToken == null || !win.mAppToken.isClientHidden()) { res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE; }
mInputMonitor.setUpdateInputWindowsNeededLw();
boolean focusChanged = false; if (win.canReceiveKeys()) { focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS, false/*updateInputWindows*/); if (focusChanged) { imMayMove = false; } }
if (imMayMove) { displayContent.computeImeTarget(true/* updateImeTarget */); }
// Don't do layout here, the window must call // relayout to be displayed, so we'll do it there. win.getParent().assignChildLayers();
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.getWindowLayerLw(parentWindow) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type); mIsChildWindow = true;
if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + parentWindow); parentWindow.addChild(this, sWindowSubLayerComparator);
mLayoutAttached = mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; mIsImWindow = parentWindow.mAttrs.type == TYPE_INPUT_METHOD || parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG; mIsWallpaper = parentWindow.mAttrs.type == TYPE_WALLPAPER; } else { // The multiplier here is to reserve space for multiple // windows in the same type layer. mBaseLayer = mPolicy.getWindowLayerLw(this) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; mSubLayer = 0; mIsChildWindow = false; mLayoutAttached = false; mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD || mAttrs.type == TYPE_INPUT_METHOD_DIALOG; mIsWallpaper = mAttrs.type == TYPE_WALLPAPER; } mIsFloatingLayer = mIsImWindow || mIsWallpaper;
if (mAppToken != null && mAppToken.mShowForAllUsers) { // Windows for apps that can show for all users should also show when the device is // locked. mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED; }
mWinAnimator = new WindowStateAnimator(this); mWinAnimator.mAlpha = a.alpha;
11-1203:14:13.746432912 V WindowManager: First window added to Session{91898491050:u0a10056}, creating SurfaceSession 11-1203:14:13.746432912 I WindowManager: NEW SURFACE SESSION android.view.SurfaceSession@4497005 ---------------------------------------------------------------- if (WindowManagerService.localLOGV) Slog.v( TAG_WM, "First window added to " + this + ", creating SurfaceSession"); mSurfaceSession = new SurfaceSession(); if (SHOW_TRANSACTIONS) Slog.i( TAG_WM, " NEW SURFACE SESSION " + mSurfaceSession); mService.mSessions.add(this); if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) { mService.dispatchNewAnimatorScaleLocked(this); } } mNumWindow++; }
/** * An instance of this class represents a connection to the surface * flinger, from which you can create one or more Surface instances that will * be composited to the screen. * {@hide} */ publicfinalclassSurfaceSession{ // Note: This field is accessed by native code. privatelong mNativeClient; // SurfaceComposerClient* /** Create a new connection with the surface flinger. */ publicSurfaceSession(){ mNativeClient = nativeCreate(); } ...... }
if (win.isChildWindow()) { // Child windows are added to their parent windows. return; } if (!mChildren.contains(win)) { if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this); addChild(win, mWindowComparator); mService.mWindowsChanged = true; // TODO: Should we also be setting layout needed here and other places? } }
// dispatch events to listeners... constsize_t count = signalConnections.size(); for (size_t i = 0; i < count; i++) { const sp<Connection>& conn(signalConnections[i]); // now see if we still need to report this event status_t err = conn->postEvent(event); if (err == -EAGAIN || err == -EWOULDBLOCK) { // The destination doesn't accept events anymore, it's probably // full. For now, we just drop the events on the floor. // FIXME: Note that some events cannot be dropped and would have // to be re-sent later. // Right-now we don't have the ability to do this. ALOGW("EventThread: dropping event (%08x) for connection %p", event.header.type, conn.get()); } elseif (err < 0) { // handle any other error on the pipe as fatal. the only // reasonable thing to do is to clean-up this connection. // The most common error we'll get here is -EPIPE. removeDisplayEventConnectionLocked(signalConnections[i]); } } } }
// should never happen because of SOCK_SEQPACKET LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)), "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were sent!)", count, objSize, size);
// should never happen because of SOCK_SEQPACKET LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)), "BitTube::recvObjects(count=%zu, size=%zu), res=%zd (partial events were " "received!)", count, objSize, size);
X:\frameworks\native\libs\sensor\BitTube.cpp ssize_tBitTube::read(void* vaddr, size_t size){ ssize_t err, len; do { len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT); err = len < 0 ? errno : 0; } while (err == EINTR); if (err == EAGAIN || err == EWOULDBLOCK) { // EAGAIN means that we have non-blocking I/O but there was no data to be read. Nothing the // client should care about. return0; } return err == 0 ? len : -err; }
intDisplayEventDispatcher::handleEvent(int, int events, void*){ if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { ALOGE("Display event receiver pipe was closed or an error occurred. " "events=0x%x", events); return0; // remove the callback }
if (!(events & Looper::EVENT_INPUT)) { ALOGW("Received spurious callback for unhandled poll event. " "events=0x%x", events); return1; // keep the callback }
Rect frame = mWinFrame; if (mFirst) { mFullRedrawNeeded = true; mLayoutRequested = true;
final Configuration config = mContext.getResources().getConfiguration(); if (shouldUseDisplaySize(lp)) { // NOTE -- system code, won't try to do compat mode. Point size = new Point(); mDisplay.getRealSize(size); desiredWindowWidth = size.x; desiredWindowHeight = size.y; } else { desiredWindowWidth = mWinFrame.width(); desiredWindowHeight = mWinFrame.height(); }
...... // Set the layout direction if it has not been set before (inherit is the default) if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { host.setLayoutDirection(config.getLayoutDirection()); } host.dispatchAttachedToWindow(mAttachInfo, 0); mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true); dispatchApplyInsets(host); } else { desiredWindowWidth = frame.width(); desiredWindowHeight = frame.height(); ...... }
final Resources res = mView.getContext().getResources();
if (mFirst) { // make sure touch mode code executes by setting cached value // to opposite of the added touch mode. mAttachInfo.mInTouchMode = !mAddedTouchMode; ensureTouchModeLocally(mAddedTouchMode); } else { ...... if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) { mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets); if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: " + mAttachInfo.mVisibleInsets); } ...... if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { windowSizeMayChange = true;
if (shouldUseDisplaySize(lp)) { // NOTE -- system code, won't try to do compat mode. Point size = new Point(); mDisplay.getRealSize(size); desiredWindowWidth = size.x; desiredWindowHeight = size.y; } else { Configuration config = res.getConfiguration(); desiredWindowWidth = dipToPx(config.screenWidthDp); desiredWindowHeight = dipToPx(config.screenHeightDp); } } }
// Ask host how big it wants to be windowSizeMayChange |= measureHierarchy(host, lp, res, desiredWindowWidth, desiredWindowHeight); }
if (collectViewAttributes()) { params = lp; } if (mAttachInfo.mForceReportNewAttributes) { mAttachInfo.mForceReportNewAttributes = false; params = lp; } ......
/****************执行窗口测量******************/ if (mApplyInsetsRequested) { mApplyInsetsRequested = false; mLastOverscanRequested = mAttachInfo.mOverscanRequested; dispatchApplyInsets(host); if (mLayoutRequested) { // Short-circuit catching a new layout request here, so // we don't need to go through two layout passes when things // change due to fitting system windows, which can happen a lot. ---------------------------------------------------------------- 对应Log: 11-1203:14:13.77310501050 I System.out: ====================================== 11-1203:14:13.77310501050 I System.out: performTraversals -- after measure ---------------------------------------------------------------- windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight); } }
if (layoutRequested) { // Clear this now, so that if anything requests a layout in the // rest of this function we will catch it and re-run a full // layout pass. mLayoutRequested = false; }
if (params != null) { if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
if (mOrigWindowType != params.type) { // For compatibility with old apps, don't crash here. if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { Slog.w(mTag, "Window type can not be changed after " + "the window is added; ignoring change of " + mView); params.type = mOrigWindowType; } } }
long frameNumber = -1; if (mSurface.isValid()) { frameNumber = mSurface.getNextFrameNumber(); }
[解压后在线反编译](http://www.javadecompilers.com/) or [解压后在线反编译](http://javare.cn/) ----------------------------------------------------------------------------------------------- IWindowSession.java publicinterfaceIWindowSessionextendsIInterface{ ...... intaddToDisplay(IWindow var1, int var2, LayoutParams var3, int var4, int var5, Rect var6, Rect var7, Rect var8, Rect var9, ParcelableWrapper var10, InputChannel var11)throws RemoteException;
......
intrelayout(IWindow var1, int var2, LayoutParams var3, int var4, int var5, int var6, int var7, long var8, Rect var10, Rect var11, Rect var12, Rect var13, Rect var14, Rect var15, Rect var16, ParcelableWrapper var17, MergedConfiguration var18, Surface var19)throws RemoteException;
@Override publicintrelayout(IWindow window, int seq, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, Surface outSurface){ if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from " + Binder.getCallingPid()); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag); int res = mService.relayoutWindow(this, window, seq, attrs, requestedWidth, requestedHeight, viewFlags, flags, frameNumber, outFrame, outOverscanInsets, outContentInsets, outVisibleInsets, outStableInsets, outsets, outBackdropFrame, cutout, mergedConfiguration, outSurface); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to " + Binder.getCallingPid()); return res; }
X:\frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java publicintrelayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, int flags, long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration, Surface outSurface){ int result = 0; boolean configChanged; ...... long origId = Binder.clearCallingIdentity(); finalint displayId; synchronized(mWindowMap) { ---------------------------------------------------------------- 对应Log: 11-1203:14:13.786432912 V WindowManager: Looking up client android.os.BinderProxy@ac0766f: Window{e26f7c u0 com.android.testred/com.android.testred.TestActivity}
....... win.mViewVisibility = viewVisibility; if (DEBUG_SCREEN_ON) { ---------------------------------------------------------------- 对应Log: 11-1203:14:13.793432912 I WindowManager: Relayout Window{e26f7c u0 com.android.testred/com.android.testred.TestActivity}: oldVis=4 newVis=0 11-1203:14:13.793432912 I WindowManager: java.lang.RuntimeException 11-1203:14:13.793432912 I WindowManager: at com.android.server.wm.WindowManagerService.relayoutWindow(WindowManagerService.java:2134) 11-1203:14:13.793432912 I WindowManager: at com.android.server.wm.Session.relayout(Session.java:194) 11-1203:14:13.793432912 I WindowManager: at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:684) 11-1203:14:13.793432912 I WindowManager: at com.android.server.wm.Session.onTransact(Session.java:134) 11-1203:14:13.793432912 I WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1021) 11-1203:14:13.793432912 I WindowManager: at android.os.Binder.execTransact(Binder.java:994) ---------------------------------------------------------------- RuntimeException stack = new RuntimeException(); stack.fillInStackTrace(); Slog.i(TAG_WM, "Relayout " + win + ": oldVis=" + oldVisibility + " newVis=" + viewVisibility, stack); }
---------------------------------------------------------------- 对应Log: 11-1203:14:13.793432912 W WindowManager: setLayoutNeeded: callers=com.android.server.wm.WindowState.setDisplayLayoutNeeded:2270 com.android.server.wm.WindowManagerService.relayoutWindow:2139 com.android.server.wm.Session.relayout:194
...... // We may be deferring layout passes at the moment, but since the client is interested // in the new out values right now we need to force a layout. mWindowPlacerLocked.performSurfacePlacement(true/* force */);
if (shouldRelayout) { result = win.relayoutVisibleWindow(result, attrChanges, oldVisibility);
if (focusMayChange) { //System.out.println("Focus may change: " + win.mAttrs.getTitle()); //更新Focus窗口 if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, false/*updateInputWindows*/)) { imMayMove = false; } }
// updateFocusedWindowLocked() already assigned layers so we only need to // reassign them at this point if the IM window state gets shuffled boolean toBeDisplayed = (result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0; final DisplayContent dc = win.getDisplayContent(); if (imMayMove) { dc.computeImeTarget(true/* updateImeTarget */); if (toBeDisplayed) { dc.assignWindowLayers(false/* setLayoutNeeded */); } }
....... ---------------------------------------------------------------- 对应Log: 11-1203:14:13.819432912 V WindowManager: Relayout given client android.os.BinderProxy@ac0766f, requestedWidth=1920, requestedHeight=1088, viewVisibility=0 11-1203:14:13.819432912 V WindowManager: Relayout returning frame=Rect(0, 0 - 1920, 1088), surface=Surface(name=com.android.testred/com.android.testred.TestActivity)/@0x1d354e5 11-1203:14:13.819432912 V WindowManager: Relayout of Window{e26f7c u0 com.android.testred/com.android.testred.TestActivity}: focusMayChange=true 11-1203:14:13.819432912 V WindowManager: Relayout complete Window{e26f7c u0 com.android.testred/com.android.testred.TestActivity}: outFrame=[0,0][1920,1088] ---------------------------------------------------------------- if (localLOGV) Slog.v( TAG_WM, "Relayout given client " + client.asBinder() + ", requestedWidth=" + requestedWidth + ", requestedHeight=" + requestedHeight + ", viewVisibility=" + viewVisibility + "\nRelayout returning frame=" + outFrame + ", surface=" + outSurface);
if (localLOGV || DEBUG_FOCUS) Slog.v( TAG_WM, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
1.2.1、WindowSurfacePlacer.performSurfacePlaRelayout complete cement(true /* force */)
首先看下堆栈信息:
1 2
04-1613:08:37.001 V/RootWindowContainer( 1049): performSurfacePlacementInner: entry. Called by com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop:207 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement:155 com.android.server.wm.WindowManagerService.relayoutWindow:2031
voidperformSurfacePlacement(boolean recoveringMemory){ if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by " + Debug.getCallers(3));
final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked; // If we are ready to perform an app transition, check through all of the app tokens to be // shown and see if they are ready to go. if (mService.mAppTransition.isReady()) { // This needs to be split into two expressions, as handleAppTransitionReadyLocked may // modify dc.pendingLayoutChanges, which would get lost when writing // defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked() finalint layoutChanges = surfacePlacer.handleAppTransitionReadyLocked(); defaultDisplay.pendingLayoutChanges |= layoutChanges; if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("after handleAppTransitionReadyLocked", defaultDisplay.pendingLayoutChanges); }
...... // Check to see if we are now in a state where the screen should // be enabled, because the window obscured flags have changed. mService.enableScreenIfNeededLocked();
mService.scheduleAnimationLocked();
if (DEBUG_WINDOW_TRACE) Slog.e(TAG, "performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating()); }
if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) { setLayoutNeeded(); }
// FIRST LOOP: Perform a layout, if needed. if (repeats < LAYOUT_REPEAT_THRESHOLD) { performLayout(repeats == 1, false/* updateInputWindows */); } else { Slog.w(TAG, "Layout repeat skipped after too many iterations"); }
// FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think it is animating. pendingLayoutChanges = 0;
if (isDefaultDisplay) { mService.mPolicy.beginPostLayoutPolicyLw(dw, dh); ---------------------------------------------------------------- 对应Log:
mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo, calculateDisplayCutoutForRotation(mDisplayInfo.rotation)); // TODO: Not sure if we really need to set the rotation here since we are updating from the // display info above... mDisplayFrames.mRotation = mRotation; //处理NavigationBar StatusBar窗口布局 mService.mPolicy.beginLayoutLw(mDisplayFrames, getConfiguration().uiMode); if (isDefaultDisplay) { // Not needed on non-default displays. mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw(); mService.mScreenRect.set(0, 0, dw, dh); }
int seq = mLayoutSeq + 1; if (seq < 0) seq = 0; mLayoutSeq = seq;
// Used to indicate that we have processed the dream window and all additional windows are // behind it. mTmpWindow = null; mTmpInitial = initial;
// First perform layout of any root windows (not attached to another window). forAllWindows(mPerformLayout, true/* traverseTopToBottom */);
// Used to indicate that we have processed the dream window and all additional attached // windows are behind it. mTmpWindow2 = mTmpWindow; mTmpWindow = null;
// Now perform layout of attached windows, which usually depend on the position of the // window they are attached to. XXX does not deal with windows that are attached to windows // that are themselves attached. forAllWindows(mPerformLayoutAttached, true/* traverseTopToBottom */);
// Window frames may have changed. Tell the input dispatcher about it. mService.mInputMonitor.layoutInputConsumers(dw, dh); mService.mInputMonitor.setUpdateInputWindowsNeededLw(); if (updateInputWindows) { mService.mInputMonitor.updateInputWindowsLw(false/*force*/); }
privatefinal Consumer<WindowState> mPerformLayout = w -> { // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid // wasting time and funky changes while a window is animating away. finalboolean gone = (mTmpWindow != null && mService.mPolicy.canBeHiddenByKeyguardLw(w)) || w.isGoneForLayoutLw();
// If this view is GONE, then skip it -- keep the current frame, and let the caller know // so they can ignore it if they want. (We do the normal layout for INVISIBLE windows, // since that means "perform layout as normal, just don't display"). if (!gone || !w.mHaveFrame || w.mLayoutNeeded || ((w.isConfigChanged() || w.setReportResizeHints()) && !w.isGoneForLayoutLw() && ((w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 || (w.mHasSurface && w.mAppToken != null && w.mAppToken.layoutConfigChanges)))) { if (!w.mLayoutAttached) { if (mTmpInitial) { //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); w.mContentChanged = false; } if (w.mAttrs.type == TYPE_DREAM) { // Don't layout windows behind a dream, so that if it does stuff like hide // the status bar we won't get a bad transition when it goes away. mTmpWindow = w; } w.mLayoutNeeded = false; w.prelayout(); finalboolean firstLayout = !w.isLaidOut(); mService.mPolicy.layoutWindowLw(w, null, mDisplayFrames); w.mLayoutSeq = mLayoutSeq;
// If this is the first layout, we need to initialize the last inset values as // otherwise we'd immediately cause an unnecessary resize. if (firstLayout) { w.updateLastInsetValues(); }
X:\frameworks\base\services\core\java\com\android\server\wm\DisplayPolicy.java publicvoidlayoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames){ // We've already done the navigation bar, status bar, and all screen decor windows. If the // status bar can receive input, we need to layout it again to accommodate for the IME // window. if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar || mScreenDecorWindows.contains(win)) { return; } final WindowManager.LayoutParams attrs = win.getAttrs(); finalboolean isDefaultDisplay = win.isDefaultDisplay();
final WindowFrames windowFrames = win.getWindowFrames();
windowFrames.setHasOutsets(false); sTmpLastParentFrame.set(windowFrames.mParentFrame); final Rect pf = windowFrames.mParentFrame; final Rect df = windowFrames.mDisplayFrame; final Rect of = windowFrames.mOverscanFrame; final Rect cf = windowFrames.mContentFrame; final Rect vf = windowFrames.mVisibleFrame; final Rect dcf = windowFrames.mDecorFrame; final Rect sf = windowFrames.mStableFrame; dcf.setEmpty(); windowFrames.setParentFrameWasClippedByDisplayCutout(false); windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
if (type == TYPE_INPUT_METHOD) { vf.set(displayFrames.mDock); cf.set(displayFrames.mDock); of.set(displayFrames.mDock); df.set(displayFrames.mDock); windowFrames.mParentFrame.set(displayFrames.mDock); // IM dock windows layout below the nav bar... pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom; // ...with content insets above the nav bar cf.bottom = vf.bottom = displayFrames.mStable.bottom; if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) { // The status bar forces the navigation bar while it's visible. Make sure the IME // avoids the navigation bar in that case. if (mNavigationBarPosition == NAV_BAR_RIGHT) { pf.right = df.right = of.right = cf.right = vf.right = displayFrames.mStable.right; } elseif (mNavigationBarPosition == NAV_BAR_LEFT) { pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left; } }
// In case the navigation bar is on the bottom, we use the frame height instead of the // regular height for the insets we send to the IME as we need some space to show // additional buttons in SystemUI when the IME is up. if (mNavigationBarPosition == NAV_BAR_BOTTOM) { finalint rotation = displayFrames.mRotation; finalint uimode = mService.mPolicy.getUiMode(); finalint navHeightOffset = getNavigationBarFrameHeight(rotation, uimode) - getNavigationBarHeight(rotation, uimode); if (navHeightOffset > 0) { cf.bottom -= navHeightOffset; sf.bottom -= navHeightOffset; vf.bottom -= navHeightOffset; dcf.bottom -= navHeightOffset; } }
// IM dock windows always go to the bottom of the screen. attrs.gravity = Gravity.BOTTOM; } elseif (type == TYPE_VOICE_INTERACTION) { of.set(displayFrames.mUnrestricted); df.set(displayFrames.mUnrestricted); pf.set(displayFrames.mUnrestricted); if (adjust != SOFT_INPUT_ADJUST_RESIZE) { cf.set(displayFrames.mDock); } else { cf.set(displayFrames.mContent); } if (adjust != SOFT_INPUT_ADJUST_NOTHING) { vf.set(displayFrames.mCurrent); } else { vf.set(cf); } } elseif (type == TYPE_WALLPAPER) { layoutWallpaper(displayFrames, pf, df, of, cf); } elseif (win == mStatusBar) { of.set(displayFrames.mUnrestricted); df.set(displayFrames.mUnrestricted); pf.set(displayFrames.mUnrestricted); cf.set(displayFrames.mStable); vf.set(displayFrames.mStable);
if (layoutInScreen && layoutInsetDecor) { if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN, INSET_DECOR"); // This is the case for a normal activity window: we want it to cover all of the // screen space, and it can take care of moving its contents to account for screen // decorations that intrude into that space. if (attached != null) { // If this window is attached to another, our display // frame is the same as the one we are attached to. setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf, displayFrames); } else { if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) { // Status bar panels are the only windows who can go on top of the status // bar. They are protected by the STATUS_BAR_SERVICE permission, so they // have the same privileges as the status bar itself. // // However, they should still dodge the navigation bar if it exists.
if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf); } elseif ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0 && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) { // Asking to layout into the overscan region, so give it that pure // unrestricted area. of.set(displayFrames.mOverscan); df.set(displayFrames.mOverscan); pf.set(displayFrames.mOverscan); } elseif ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW || type == TYPE_VOLUME_OVERLAY || type == TYPE_KEYGUARD_DIALOG)) { // Asking for layout as if the nav bar is hidden, lets the application // extend into the unrestricted overscan screen area. We only do this for // application windows and certain system windows to ensure no window that // can be above the nav bar can do this. df.set(displayFrames.mOverscan); pf.set(displayFrames.mOverscan); // We need to tell the app about where the frame inside the overscan is, so // it can inset its content by that amount -- it didn't ask to actually // extend itself into the overscan region. of.set(displayFrames.mUnrestricted); } else { df.set(displayFrames.mRestrictedOverscan); pf.set(displayFrames.mRestrictedOverscan); // We need to tell the app about where the frame inside the overscan // is, so it can inset its content by that amount -- it didn't ask // to actually extend itself into the overscan region. of.set(displayFrames.mUnrestricted); }
if ((fl & FLAG_FULLSCREEN) == 0) { if (win.isVoiceInteraction()) { cf.set(displayFrames.mVoiceContent); } else { // IME Insets are handled on the client for ADJUST_RESIZE in the new // insets world if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE || adjust != SOFT_INPUT_ADJUST_RESIZE) { cf.set(displayFrames.mDock); } else { cf.set(displayFrames.mContent); } } } else { // Full screen windows are always given a layout that is as if the status // bar and other transient decors are gone. This is to avoid bad states when // moving from a window that is not hiding the status bar to one that is. cf.set(displayFrames.mRestricted); } applyStableConstraints(sysUiFl, fl, cf, displayFrames); if (adjust != SOFT_INPUT_ADJUST_NOTHING) { vf.set(displayFrames.mCurrent); } else { vf.set(cf); } } } elseif (layoutInScreen || (sysUiFl & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) { if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN"); // A window that has requested to fill the entire screen just // gets everything, period. if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) { cf.set(displayFrames.mUnrestricted); of.set(displayFrames.mUnrestricted); df.set(displayFrames.mUnrestricted); pf.set(displayFrames.mUnrestricted); if (hasNavBar) { pf.left = df.left = of.left = cf.left = displayFrames.mDock.left; pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right; pf.bottom = df.bottom = of.bottom = cf.bottom = displayFrames.mRestricted.bottom; } if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf); } elseif (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) { // The navigation bar has Real Ultimate Power. of.set(displayFrames.mUnrestricted); df.set(displayFrames.mUnrestricted); pf.set(displayFrames.mUnrestricted); if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf); } elseif ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT) && ((fl & FLAG_FULLSCREEN) != 0)) { // Fullscreen secure system overlays get what they ask for. Screenshot region // selection overlay should also expand to full screen. cf.set(displayFrames.mOverscan); of.set(displayFrames.mOverscan); df.set(displayFrames.mOverscan); pf.set(displayFrames.mOverscan); } elseif (type == TYPE_BOOT_PROGRESS) { // Boot progress screen always covers entire display. cf.set(displayFrames.mOverscan); of.set(displayFrames.mOverscan); df.set(displayFrames.mOverscan); pf.set(displayFrames.mOverscan); } elseif ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0 && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) { // Asking to layout into the overscan region, so give it that pure unrestricted // area. cf.set(displayFrames.mOverscan); of.set(displayFrames.mOverscan); df.set(displayFrames.mOverscan); pf.set(displayFrames.mOverscan); } elseif ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 && (type == TYPE_STATUS_BAR || type == TYPE_TOAST || type == TYPE_DOCK_DIVIDER || type == TYPE_VOICE_INTERACTION_STARTING || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) { // Asking for layout as if the nav bar is hidden, lets the // application extend into the unrestricted screen area. We // only do this for application windows (or toasts) to ensure no window that // can be above the nav bar can do this. // XXX This assumes that an app asking for this will also // ask for layout in only content. We can't currently figure out // what the screen would be if only laying out to hide the nav bar. cf.set(displayFrames.mUnrestricted); of.set(displayFrames.mUnrestricted); df.set(displayFrames.mUnrestricted); pf.set(displayFrames.mUnrestricted); } elseif ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) { of.set(displayFrames.mRestricted); df.set(displayFrames.mRestricted); pf.set(displayFrames.mRestricted);
// IME Insets are handled on the client for ADJUST_RESIZE in the new insets // world if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE || adjust != SOFT_INPUT_ADJUST_RESIZE) { cf.set(displayFrames.mDock); } else { cf.set(displayFrames.mContent); } } else { cf.set(displayFrames.mRestricted); of.set(displayFrames.mRestricted); df.set(displayFrames.mRestricted); pf.set(displayFrames.mRestricted); }
if (adjust != SOFT_INPUT_ADJUST_NOTHING) { vf.set(displayFrames.mCurrent); } else { vf.set(cf); } } elseif (attached != null) { if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached); // A child window should be placed inside of the same visible // frame that its parent had. setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf, displayFrames); } else { if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window"); // Otherwise, a normal window must be placed inside the content // of all screen decorations. if (type == TYPE_STATUS_BAR_PANEL) { // Status bar panels can go on // top of the status bar. They are protected by the STATUS_BAR_SERVICE // permission, so they have the same privileges as the status bar itself. cf.set(displayFrames.mRestricted); of.set(displayFrames.mRestricted); df.set(displayFrames.mRestricted); pf.set(displayFrames.mRestricted); } elseif (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) { // These dialogs are stable to interim decor changes. cf.set(displayFrames.mStable); of.set(displayFrames.mStable); df.set(displayFrames.mStable); pf.set(displayFrames.mStable); } else { pf.set(displayFrames.mContent); if (win.isVoiceInteraction()) { cf.set(displayFrames.mVoiceContent); of.set(displayFrames.mVoiceContent); df.set(displayFrames.mVoiceContent); } elseif (adjust != SOFT_INPUT_ADJUST_RESIZE) { cf.set(displayFrames.mDock); of.set(displayFrames.mDock); df.set(displayFrames.mDock); } else { cf.set(displayFrames.mContent); of.set(displayFrames.mContent); df.set(displayFrames.mContent); } if (adjust != SOFT_INPUT_ADJUST_NOTHING) { vf.set(displayFrames.mCurrent); } else { vf.set(cf); } } } }
// TYPE_BASE_APPLICATION windows are never considered floating here because they don't get // cropped / shifted to the displayFrame in WindowState. finalboolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen && type != TYPE_BASE_APPLICATION;
// Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in // the cutout safe zone. if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) { final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect; displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe); if (layoutInScreen && layoutInsetDecor && !requestedFullscreen && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) { // At the top we have the status bar, so apps that are // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN // already expect that there's an inset there and we don't need to exclude // the window from that area. displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE; } if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) { // Same for the navigation bar. switch (mNavigationBarPosition) { case NAV_BAR_BOTTOM: displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE; break; case NAV_BAR_RIGHT: displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE; break; case NAV_BAR_LEFT: displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE; break; } } if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) { // The IME can always extend under the bottom cutout if the navbar is there. displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE; } // Windows that are attached to a parent and laid out in said parent already avoid // the cutout according to that parent and don't need to be further constrained. // Floating IN_SCREEN windows get what they ask for and lay out in the full screen. // They will later be cropped or shifted using the displayFrame in WindowState, // which prevents overlap with the DisplayCutout. if (!attachedInParent && !floatingInScreenWindow) { sTmpRect.set(pf); pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars); windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf)); } // Make sure that NO_LIMITS windows clipped to the display don't extend under the // cutout. df.intersectUnchecked(displayCutoutSafeExceptMaybeBars); }
// Content should never appear in the cutout. cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
// TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it. // Also, we don't allow windows in multi-window mode to extend out of the screen. if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR && !win.inMultiWindowMode()) { df.left = df.top = -10000; df.right = df.bottom = 10000; if (type != TYPE_WALLPAPER) { of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000; of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000; } }
// If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we // need to provide information to the clients that want to pretend that you can draw there. // We only want to apply outsets to certain types of windows. For example, we never want to // apply the outsets to floating dialogs, because they wouldn't make sense there. finalboolean useOutsets = shouldUseOutsets(attrs, fl); if (isDefaultDisplay && useOutsets) { final Rect osf = windowFrames.mOutsetFrame; osf.set(cf.left, cf.top, cf.right, cf.bottom); windowFrames.setHasOutsets(true); int outset = mWindowOutsetBottom; if (outset > 0) { int rotation = displayFrames.mRotation; if (rotation == Surface.ROTATION_0) { osf.bottom += outset; } elseif (rotation == Surface.ROTATION_90) { osf.right += outset; } elseif (rotation == Surface.ROTATION_180) { osf.top -= outset; } elseif (rotation == Surface.ROTATION_270) { osf.left -= outset; } if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset + " with rotation " + rotation + ", result: " + osf); } } -------------------------------------------- 11-12 03:14:14.109 432 450 V DisplayPolicy: Compute frame com.android.testred/com.android.testred.TestActivity: sim=#120 attach=null type=1 flags=0x01810100 pf=[0,0][1920,1088] df=[0,0][1920,1088] of=[0,0][1920,1088] cf=[0,0][1920,1088] vf=[0,0][1920,1088] dcf=[0,0][1920,1088] sf=[0,0][1920,1088] osf=[0,0][0,0] Window{e26f7c u0 com.android.testred/com.android.testred.TestActivity}
if (!sTmpLastParentFrame.equals(pf)) { windowFrames.setContentChanged(true); }
win.computeFrameLw(); // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. if (type == TYPE_INPUT_METHOD && win.isVisibleLw() && !win.getGivenInsetsPendingLw()) { offsetInputMethodWindowLw(win, displayFrames); } if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw() && !win.getGivenInsetsPendingLw()) { offsetVoiceInputWindowLw(win, displayFrames); } }
@Override publicvoidcomputeFrameLw(Rect parentFrame, Rect displayFrame, Rect overscanFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, Rect outsetFrame, WmDisplayCutout displayCutout, boolean parentFrameWasClippedByDisplayCutout){ ...... mHaveFrame = true; mParentFrameWasClippedByDisplayCutout = parentFrameWasClippedByDisplayCutout;
final Task task = getTask(); finalboolean inFullscreenContainer = inFullscreenContainer(); finalboolean windowsAreFloating = task != null && task.isFloating(); final DisplayContent dc = getDisplayContent();
// Offset the actual frame by the amount layout frame is off. mFrame.offset(-layoutXDiff, -layoutYDiff); mCompatFrame.offset(-layoutXDiff, -layoutYDiff); mContentFrame.offset(-layoutXDiff, -layoutYDiff); mVisibleFrame.offset(-layoutXDiff, -layoutYDiff); mStableFrame.offset(-layoutXDiff, -layoutYDiff);
mCompatFrame.set(mFrame); ...... ---------------------------------------------------------------- 对应Log: 11-1203:14:14.109432450 V WindowState: Resolving (mRequestedWidth=1920, mRequestedheight=1088) to (pw=1920, ph=1088): frame=[0,0][1920,1088] ci=[0,0][0,0] vi=[0,0][0,0] si=[0,0][0,0] of=[0,0][0,0] com.android.testred/com.android.testred.TestActivity
privateintcreateSurfaceControl(Surface outSurface, int result, WindowState win, WindowStateAnimator winAnimator){ if (!win.mHasSurface) { result |= RELAYOUT_RES_SURFACE_CHANGED; }
WindowSurfaceController surfaceController; try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl"); surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid); } finally { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } if (surfaceController != null) { surfaceController.getSurface(outSurface); if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " OUT SURFACE " + outSurface + ": copied"); } else { // For some reason there isn't a surface. Clear the // caller's object so they see the same state. Slog.w(TAG_WM, "Failed to create surface control for " + win); outSurface.release(); }
---------------------------------------------------------------- // We may abort, so initialize to defaults. mLastClipRect.set(0, 0, 0, 0);
// Set up surface control with initial size. try {
finalboolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0; finalint format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format; if (!PixelFormat.formatHasAlpha(attrs.format) // Don't make surface with surfaceInsets opaque as they display a // translucent shadow. && attrs.surfaceInsets.left == 0 && attrs.surfaceInsets.top == 0 && attrs.surfaceInsets.right == 0 && attrs.surfaceInsets.bottom == 0 // Don't make surface opaque when resizing to reduce the amount of // artifacts shown in areas the app isn't drawing content to. && !w.isDragResizing()) { flags |= SurfaceControl.OPAQUE; }
mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession, attrs.getTitle().toString(), width, height, format, flags, this, windowType, ownerUid);
publicWindowSurfaceController(SurfaceSession s, String name, int w, int h, int format, int flags, WindowStateAnimator animator, int windowType, int ownerUid){ mAnimator = animator;
/** * Create a surface with a name. * <p> * The surface creation flags specify what kind of surface to create and * certain options such as whether the surface can be assumed to be opaque * and whether it should be initially hidden. Surfaces should always be * created with the {@link #HIDDEN} flag set to ensure that they are not * made visible prematurely before all of the surface's properties have been * configured. * <p> * Good practice is to first create the surface with the {@link #HIDDEN} flag * specified, open a transaction, set the surface layer, layer stack, alpha, * and position, call {@link #show} if appropriate, and close the transaction. * * @param session The surface session, must not be null. * @param name The surface name, must not be null. * @param w The surface initial width. * @param h The surface initial height. * @param flags The surface creation flags. Should always include {@link #HIDDEN} * in the creation flags. * @param windowType The type of the window as specified in WindowManager.java. * @param ownerUid A unique per-app ID. * * @throws throws OutOfResourcesException If the SurfaceControl cannot be created. */ privateSurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags, SurfaceControl parent, int windowType, int ownerUid) throws OutOfResourcesException, IllegalArgumentException { ......
if ((flags & SurfaceControl.HIDDEN) == 0) { Log.w(TAG, "Surfaces should always be created with the HIDDEN flag set " + "to ensure that they are not made visible prematurely before " + "all of the surface's properties have been configured. " + "Set the other properties and make the surface visible within " + "a transaction. New surface name: " + name, new Throwable()); }
switch (format) { case PIXEL_FORMAT_TRANSPARENT: case PIXEL_FORMAT_TRANSLUCENT: format = PIXEL_FORMAT_RGBA_8888; break; case PIXEL_FORMAT_OPAQUE: format = PIXEL_FORMAT_RGBX_8888; break; }
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer, true); mProducer = new MonitoredProducer(producer, mFlinger, this); { // Grab the SF state lock during this since it's the only safe way to access RenderEngine Mutex::Autolock lock(mFlinger->mStateLock); mConsumer = new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this); } mConsumer->setConsumerUsageBits(getEffectiveUsage(0)); mConsumer->setContentsChangedListener(this); mConsumer->setName(mName);
// BufferQueueCore::mMaxDequeuedBufferCount is default to 1 if (!mFlinger->isLayerTripleBufferingDisabled()) { mProducer->setMaxDequeuedBufferCount(2); }
if (constauto display = mFlinger->getDefaultDisplayDevice()) { updateTransformHint(display); } }
// Use rk ashmem ------- if ( NULL == g_gralloc ) { int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (consthw_module_t **)&g_gralloc); if (ret) { ALOGE("Failed to open gralloc module %d", ret); } } // Use rk ashmem ------- }
ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) : mAbandoned(false), mConsumer(bufferQueue), mPrevFinalReleaseFence(Fence::NO_FENCE) { // Choose a name using the PID and a process-unique ID. mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
// Note that we can't create an sp<...>(this) in a ctor that will not keep a // reference once the ctor ends, as that would cause the refcount of 'this' // dropping to 0 at the end of the ctor. Since all we need is a wp<...> // that's what we create. wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this); sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
privateintcreateSurfaceControl(Surface outSurface, int result, WindowState win, WindowStateAnimator winAnimator){ if (!win.mHasSurface) { result |= RELAYOUT_RES_SURFACE_CHANGED; }
WindowSurfaceController surfaceController; try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl"); surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid); } finally { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } if (surfaceController != null) { surfaceController.getSurface(outSurface); ---------------------------------------------------------------- 对应Log: 04-1613:08:37.012 I/WindowManager( 1049): OUT SURFACE Surface(name=null)/@0xe493bef: copied ---------------------------------------------------------------- if(SHOW_TRANSACTIONS) Slog.i(TAG_WM, " OUT SURFACE " + outSurface + ": copied"); } else { // For some reason there isn't a surface. Clear the // caller's object so they see the same state. Slog.w(TAG_WM, "Failed to create surface control for " + win); outSurface.release(); }
static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz, jlong surfaceControlNativeObj){ /* * This is used by the WindowManagerService just after constructing * a Surface and is necessary for returning the Surface reference to * the caller. At this point, we should only have a SurfaceControl. */
sp<Surface> SurfaceControl::generateSurfaceLocked()const { // This surface is always consumed by SurfaceFlinger, so the // producerControlledByApp value doesn't matter; using false. mSurfaceData = new Surface(mGraphicBufferProducer, false);
@Override publicvoidwriteToParcel(Parcel dest, int flags){ if (dest == null) { thrownew IllegalArgumentException("dest must not be null"); } synchronized (mLock) { // NOTE: This must be kept synchronized with the native parceling code // in frameworks/native/libs/Surface.cpp dest.writeString(mName); dest.writeInt(mIsSingleBuffered ? 1 : 0); nativeWriteToParcel(mNativeObject, dest); } if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { release(); } }
staticvoidnativeWriteToParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj){ Parcel* parcel = parcelForJavaObject(env, parcelObj); if (parcel == NULL) { doThrowNPE(env); return; } sp<Surface> self(reinterpret_cast<Surface *>(nativeObject)); android::view::Surface surfaceShim; if (self != nullptr) { surfaceShim.graphicBufferProducer = self->getIGraphicBufferProducer(); } // Calling code in Surface.java has already written the name of the Surface // to the Parcel surfaceShim.writeToParcel(parcel, /*nameAlreadyWritten*/true); }
2.2.6、Surface跨进程传递( App->WMS)readFromParcel()
[->IWindowSession$Stub$Proxy.java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
publicintrelayout(IWindow window, int seq, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, int flags, long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper displayCutout, MergedConfiguration outMergedConfiguration, Surface outSurface)throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); try { ...... mRemote.transact(6, _data, _reply, 0); _reply.readException(); int _result = _reply.readInt(); ...... if (0 != _reply.readInt()) { outSurface.readFromParcel(_reply); } }
publicvoidreadFromParcel(Parcel source){ if (source == null) { thrownew IllegalArgumentException("source must not be null"); }
synchronized (mLock) { // nativeReadFromParcel() will either return mNativeObject, or // create a new native Surface and return it after reducing // the reference count on mNativeObject. Either way, it is // not necessary to call nativeRelease() here. // NOTE: This must be kept synchronized with the native parceling code // in frameworks/native/libs/Surface.cpp mName = source.readString(); mIsSingleBuffered = source.readInt() != 0; setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source)); } }
// Calling code in Surface.java has already read the name of the Surface // from the Parcel surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);
// update the Surface only if the underlying IGraphicBufferProducer // has changed. if (self != nullptr && (IInterface::asBinder(self->getIGraphicBufferProducer()) == IInterface::asBinder(surfaceShim.graphicBufferProducer))) { // same IGraphicBufferProducer, return ourselves return jlong(self.get()); }
sp<Surface> sur; if (surfaceShim.graphicBufferProducer != nullptr) { // we have a new IGraphicBufferProducer, create a new Surface for it sur = new Surface(surfaceShim.graphicBufferProducer, true); // and keep a reference before passing to java sur->incStrong(&sRefBaseOwner); }
if (self != NULL) { // and loose the java reference to ourselves self->decStrong(&sRefBaseOwner); }
// For whatever reason we didn't create a HardwareRenderer, end any // hardware animations that are now dangling if (mAttachInfo.mPendingAnimatingRenderNodes != null) { finalint count = mAttachInfo.mPendingAnimatingRenderNodes.size(); for (int i = 0; i < count; i++) { mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators(); } mAttachInfo.mPendingAnimatingRenderNodes.clear(); }
if (mReportNextDraw) { mReportNextDraw = false;
// if we're using multi-thread renderer, wait for the window frame draws if (mWindowDrawCountDown != null) { try { mWindowDrawCountDown.await(); } catch (InterruptedException e) { Log.e(mTag, "Window redraw count down interrupted!"); } mWindowDrawCountDown = null; }
if (!sFirstDrawComplete) { synchronized (sFirstDrawHandlers) { sFirstDrawComplete = true; finalint count = sFirstDrawHandlers.size(); for (int i = 0; i< count; i++) { mHandler.post(sFirstDrawHandlers.get(i)); } } }
scrollToRectOrFocus(null, false); ..... final Rect dirty = mDirty; if (mSurfaceHolder != null) { // The app owns the surface, we won't draw. dirty.setEmpty(); ...... returnfalse; }
// now select correct colorspace and dataspace based on user's attribute list EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, window, format, attrib_list, &colorSpace, &strippedAttribList)) { ...... } attrib_list = strippedAttribList.data();
{ int err = native_window_set_buffers_format(window, format); ...... } }
android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace); if (dataSpace != HAL_DATASPACE_UNKNOWN) { int err = native_window_set_buffers_data_space(window, dataSpace); ...... } }
// the EGL spec requires that a new EGLSurface default to swap interval // 1, so explicitly set that on the window here. ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window); anw->setSwapInterval(anw, 1);
/frameworks/base/services/core/java/com/android/server/wm/WindowState.java voidsetDisplayLayoutNeeded(){ final DisplayContent dc = getDisplayContent(); if (dc != null) { dc.setLayoutNeeded(); } }
if (isDisplayed && w.isObscuringDisplay()) { // This window completely covers everything behind it, so we want to leave all // of them as undimmed (for performance reasons). root.mObscuringWindow = w; mTmpApplySurfaceChangesTransactionState.obscured = true; }
if (w.mHasSurface && isDisplayed) { finalint type = w.mAttrs.type; if (type == TYPE_SYSTEM_DIALOG || type == TYPE_SYSTEM_ERROR || (w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { mTmpApplySurfaceChangesTransactionState.syswin = true; } if (mTmpApplySurfaceChangesTransactionState.preferredRefreshRate == 0 && w.mAttrs.preferredRefreshRate != 0) { mTmpApplySurfaceChangesTransactionState.preferredRefreshRate = w.mAttrs.preferredRefreshRate; } if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0 && w.mAttrs.preferredDisplayModeId != 0) { mTmpApplySurfaceChangesTransactionState.preferredModeId = w.mAttrs.preferredDisplayModeId; } } }
if (isDefaultDisplay && obscuredChanged && w.isVisibleLw() && mWallpaperController.isWallpaperTarget(w)) { // This is the wallpaper target and its obscured state changed... make sure the // current wallpaper's visibility has been updated accordingly. mWallpaperController.updateWallpaperVisibility(); }
w.handleWindowMovedIfNeeded();
final WindowStateAnimator winAnimator = w.mWinAnimator;
// Moved from updateWindowsAndWallpaperLocked(). if (w.mHasSurface) { // Take care of the window being ready to display. finalboolean committed = winAnimator.commitFinishDrawingLocked(); if (isDefaultDisplay && committed) { if (w.mAttrs.type == TYPE_DREAM) { // HACK: When a dream is shown, it may at that point hide the lock screen. // So we need to redo the layout to let the phone window manager make this // happen. pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT; if (DEBUG_LAYOUT_REPEATS) { surfacePlacer.debugLayoutRepeats( "dream and commitFinishDrawingLocked true", pendingLayoutChanges); } } if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) { if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "First draw done in potential wallpaper target " + w); root.mWallpaperMayChange = true; pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; if (DEBUG_LAYOUT_REPEATS) { surfacePlacer.debugLayoutRepeats( "wallpaper and commitFinishDrawingLocked true", pendingLayoutChanges); } } } }
final AppWindowToken atoken = w.mAppToken; if (atoken != null) { atoken.updateLetterboxSurface(w); finalboolean updateAllDrawn = atoken.updateDrawnWindowStates(w); if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(atoken)) { mTmpUpdateAllDrawn.add(atoken); } }
if (isDefaultDisplay && someoneLosingFocus && w == mService.mCurrentFocus && w.isDisplayedLw()) { mTmpApplySurfaceChangesTransactionState.focusDisplayed = true; }
// There is the main base application window, even if it is exiting, wait for it mNumInterestingWindows = findMainWindow(false/* includeStartingApp */) != null ? 1 : 0; }
final WindowStateAnimator winAnimator = w.mWinAnimator;
if (w != startingWindow) { if (w.isInteresting()) { // Add non-main window as interesting since the main app has already been added if (findMainWindow(false/* includeStartingApp */) != w) { mNumInterestingWindows++; } if (w.isDrawnLw()) { mNumDrawnWindows++;
if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: " + this + " w=" + w + " numInteresting=" + mNumInterestingWindows + " freezingScreen=" + mFreezingScreen + " mAppFreezing=" + w.mAppFreezing);
// If a leash has been set when the transaction was committed, then the leash reparent has // been committed. mCommittedReparentToAnimationLeash = mSurfaceAnimator.hasLeash(); for (int i = 0; i < mChildren.size(); i++) { mChildren.get(i).prepareSurfaces(); } }
/frameworks/base/services/core/java/com/android/server/wm/WindowState.java @Override voidprepareSurfaces(){ final Dimmer dimmer = getDimmer(); mIsDimming = false; if (dimmer != null) { applyDims(dimmer); } updateSurfacePosition();
voidprepareSurfaceLocked(finalboolean recoveringMemory){ final WindowState w = mWin; if (!hasSurface()) {
// There is no need to wait for an animation change if our window is gone for layout // already as we'll never be visible. if (w.getOrientationChanging() && w.isGoneForLayoutLw()) { if (DEBUG_ORIENTATION) { Slog.v(TAG, "Orientation change skips hidden " + w); } w.setOrientationChanging(false); } return; }
boolean displayed = false;
computeShownFrameLocked();
setSurfaceBoundariesLocked(recoveringMemory);
if (mIsWallpaper && !w.mWallpaperVisible) { // Wallpaper is no longer visible and there is no wp target => hide it. hide("prepareSurfaceLocked"); } elseif (w.isParentWindowHidden() || !w.isOnScreen()) { hide("prepareSurfaceLocked"); mWallpaperControllerLocked.hideWallpapers(w);
// If we are waiting for this window to handle an orientation change. If this window is // really hidden (gone for layout), there is no point in still waiting for it. // Note that this does introduce a potential glitch if the window becomes unhidden // before it has drawn for the new orientation. if (w.getOrientationChanging() && w.isGoneForLayoutLw()) { w.setOrientationChanging(false); if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change skips hidden " + w); } } elseif (mLastLayer != mAnimLayer || mLastAlpha != mShownAlpha || mLastDsDx != mDsDx || mLastDtDx != mDtDx || mLastDsDy != mDsDy || mLastDtDy != mDtDy || w.mLastHScale != w.mHScale || w.mLastVScale != w.mVScale || mLastHidden) { displayed = true; mLastAlpha = mShownAlpha; mLastLayer = mAnimLayer; mLastDsDx = mDsDx; mLastDtDx = mDtDx; mLastDsDy = mDsDy; mLastDtDy = mDtDy; w.mLastHScale = w.mHScale; w.mLastVScale = w.mVScale;
if (prepared && mDrawState == HAS_DRAWN) { if (mLastHidden) { if (showSurfaceRobustlyLocked()) { markPreservedSurfaceForDestroy(); mAnimator.requestRemovalOfReplacedWindows(w); mLastHidden = false; if (mIsWallpaper) { w.dispatchWallpaperVisibility(true); } // This draw means the difference between unique content and mirroring. // Run another pass through performLayout to set mHasContent in the // LogicalDisplay. mAnimator.setPendingLayoutChanges(w.getDisplayId(), FINISH_LAYOUT_REDO_ANIM); if (DEBUG_LAYOUT_REPEATS) { mService.mWindowPlacerLocked.debugLayoutRepeats( "showSurfaceRobustlyLocked " + w, mAnimator.getPendingLayoutChanges(w.getDisplayId())); } } else { w.setOrientationChanging(false); } } } if (hasSurface()) { w.mToken.hasVisible = true; } } else { if (DEBUG_ANIM && isAnimationSet()) { Slog.v(TAG, "prepareSurface: No changes in animation for " + this); } displayed = true; }
if (w.getOrientationChanging()) { if (!w.isDrawnLw()) { mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE; mAnimator.mLastWindowFreezeSource = w; if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation continue waiting for draw in " + w); } else { w.setOrientationChanging(false); if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change complete in " + w); } }
if (screenAnimation) { // cache often used attributes locally final Rect frame = mWin.mFrame; finalfloat tmpFloats[] = mService.mTmpFloats; final Matrix tmpMatrix = mWin.mTmpMatrix;
// Compute the desired transformation. if (screenRotationAnimation.isRotating()) { finalfloat w = frame.width(); finalfloat h = frame.height(); if (w>=1 && h>=1) { tmpMatrix.setScale(1 + 2/w, 1 + 2/h, w/2, h/2); } else { tmpMatrix.reset(); } } else { tmpMatrix.reset(); }
voidsetSurfaceBoundariesLocked(finalboolean recoveringMemory){ ...... final WindowState w = mWin; final LayoutParams attrs = mWin.getAttrs(); final Task task = w.getTask();
if (!w.mSeamlesslyRotated) { // Used to offset the WSA when stack position changes before a resize. int xOffset = mXOffset; int yOffset = mYOffset; if (mOffsetPositionForStackResize) { if (relayout) { setOffsetPositionForStackResize(false); mSurfaceController.deferTransactionUntil(mSurfaceController.getHandle(), mWin.getFrameNumber()); } else { final TaskStack stack = mWin.getStack(); mTmpPos.x = 0; mTmpPos.y = 0; if (stack != null) { stack.getRelativePosition(mTmpPos); }
xOffset = -mTmpPos.x; yOffset = -mTmpPos.y;
// Crop also needs to be extended so the bottom isn't cut off when the WSA // position is moved. if (clipRect != null) { clipRect.right += mTmpPos.x; clipRect.bottom += mTmpPos.y; } } } mSurfaceController.setPositionInTransaction(xOffset, yOffset, recoveringMemory); } }
privatebooleancalculateCrop(Rect clipRect){ final WindowState w = mWin; final DisplayContent displayContent = w.getDisplayContent(); clipRect.setEmpty();
if (displayContent == null) { returnfalse; }
if (w.inPinnedWindowingMode()) { returnfalse; }
// If we're animating, the wallpaper should only // be updated at the end of the animation. if (w.mAttrs.type == TYPE_WALLPAPER) { returnfalse; } --------------------------------------------------------- 看看Log: 04-1613:08:37.124 D/WindowStateAnimator( 1049): Updating crop win=Window{c1255cd u0 com.android.testred/com.android.testred.TestActivity} mLastCrop=Rect(0, 36 - 160, 782) 04-1613:08:37.124 D/WindowStateAnimator( 1049): Applying decor to crop win=Window{c1255cd u0 com.android.testred/com.android.testred.TestActivity} mDecorFrame=Rect(0, 36 - 480, 782) mSystemDecorRect=Rect(0, 36 - 160, 782) 04-1613:08:37.124 D/WindowStateAnimator( 1049): win=Window{c1255cd u0 com.android.testred/com.android.testred.TestActivity} Initial clip rect: Rect(0, 36 - 160, 782) fullscreen=true 04-1613:08:37.124 D/WindowStateAnimator( 1049): win=Window{c1255cd u0 com.android.testred/com.android.testred.TestActivity} Clip rect after stack adjustment=Rect(0, 36 - 160, 782) 04-1613:08:37.124 D/WindowStateAnimator( 1049): --------------------------------------------------------- if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Updating crop win=" + w + " mLastCrop=" + mLastClipRect);
w.calculatePolicyCrop(mSystemDecorRect);
if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame=" + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect);
// We use the clip rect as provided by the tranformation for non-fullscreen windows to // avoid premature clipping with the system decor rect. clipRect.set(mSystemDecorRect); if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect + " fullscreen=" + fullscreen);
w.expandForSurfaceInsets(clipRect);
// The clip rect was generated assuming (0,0) as the window origin, // so we need to translate to match the actual surface coordinates. clipRect.offset(w.mAttrs.surfaceInsets.left, w.mAttrs.surfaceInsets.top);
if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Clip rect after stack adjustment=" + clipRect);