当前位置: 首页 > news >正文

快站app浙江省一建建设集团网站

快站app,浙江省一建建设集团网站,浏览网站内下载文件,做响应式的网站前言 在Android系统中#xff0c;很多应用都需要根据具体情况来控制状态栏和导航栏的显示和隐藏#xff0c;又或者将状态栏透明#xff0c;实现诸如沉浸式、全面屏灯效果#xff0c;而要实现这些效果#xff0c;都离不开SystemUIVisibility属性。由于SystemUIVisibilityy…前言 在Android系统中很多应用都需要根据具体情况来控制状态栏和导航栏的显示和隐藏又或者将状态栏透明实现诸如沉浸式、全面屏灯效果而要实现这些效果都离不开SystemUIVisibility属性。由于SystemUIVisibilityy属性主要用来控制系统状态栏和导航栏的行为而状态栏和导航栏都属于SystemUI模块的StatusBar所以SystemUIVisibility属性的消费者肯定包含StatusBar。另外当状态栏和导航栏发生变化的时候窗口的布局一般也会跟着发生变化这就意味着窗口管理者PhoneWindowManager肯定也要消费SystemUIVisibility属性。本篇文章我们就来具体分析一下和这个属性有关的代码。 一、SystemUIVisibility属性常见常见取值 1、为窗口设置SystemUIVisibility属性的方式有两种一种是直接在窗口的WindowManager.LayoutParams对象的systemUiVisibility属性上进行设置并通过WindowManager.updateViewLayout()方法使其生效。 frameworks/base/core/java/android/view/WindowManager.java public interface WindowManager extends ViewManager {public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {//隐藏窗口的所有装饰比如状态栏和导航栏public static final int FLAG_FULLSCREEN 0x00000400;//控制窗口状态栏、导航栏的显示和隐藏public int systemUiVisibility;} } 2、另一种是在一个已经显示在窗口上的控件中调用setSystemUiVisibility方法传入如下属性。 frameworks/base/core/java/android/view/View.java public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource { //隐藏导航栏 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION 0x00000002; //隐藏状态栏 public static final int SYSTEM_UI_FLAG_FULLSCREEN 0x00000004; }这种方式最终影响的其实是窗口的WindowManager.LayoutParams对象的subtreeSystemUiVisibility属性。 public interface WindowManager extends ViewManager {public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {//控制窗口状态栏、导航栏的显示和隐藏public int subtreeSystemUiVisibility;} } 窗口的状态栏导航栏显示与否最终其实是受以上两个属性共同影响的。接下来我们具体来分析一下View的setSystemUiVisibility方法是如何生效的。 二、View的setSystemUiVisibility方法调用流程 1、View的setSystemUiVisibility方法如下所示。 public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource {int mSystemUiVisibility;protected ViewParent mParent;public void setSystemUiVisibility(int visibility) {if (visibility ! mSystemUiVisibility) {mSystemUiVisibility visibility;//保存SystemUIVisibility属性if (mParent ! null mAttachInfo ! null !mAttachInfo.mRecomputeGlobalAttributes) {mParent.recomputeViewAttributes(this);//通知父控件子控件属性发生了变化}}} }setSystemUiVisibility方法首先将属性赋值给mSystemUiVisibility然后会调用父控件的recomputeViewAttributes方法通知父控件子控件属性发生了变化。ViewParent是一个接口在Android中有两个类实现了这个接口它们分别是ViewGroup和ViewRootImpl。 2、ViewGroup和ViewRootImpl和recomputeViewAttributes方法相关的代码如下所示。 frameworks/base/core/java/android/view/View.java public abstract class ViewGroup extends View implements ViewParent, ViewManager {Overridepublic void recomputeViewAttributes(View child) {if (mAttachInfo ! null !mAttachInfo.mRecomputeGlobalAttributes) {ViewParent parent mParent;if (parent ! null) parent.recomputeViewAttributes(this);}} }frameworks/base/core/java/android/view/ViewRootImpl.java public final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,AttachedSurfaceControl {final View.AttachInfo mAttachInfo;Overridepublic void recomputeViewAttributes(View child) {checkThread();//检测线程是不是UI线程if (mView child) {mAttachInfo.mRecomputeGlobalAttributes true;//标记需要重新计算本地属性if (!mWillDrawSoon) {scheduleTraversals();//进一步调用scheduleTraversals方法。}}} }结合Android 9.0系统源码_窗口管理二WindowManager对窗口的管理过程我们知道包括Activity的跟布局DecorView在内的任何ViewWindowManager在将它添加到窗口上的过程中最终都会创建一个ViewRootImpl并将View设置给ViewRootImpl这样根View的父类就变成了ViewRootImpl。这就意味着不管任何子View调用recomputeViewAttributes方法最终所触发的都是ViewRootImpl的recomputeViewAttributes而ViewRootImpl会进一步调用scheduleTraversals方法。 3、ViewRootImpl和scheduleTraversals方法相关的代码如下所示。 public final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,AttachedSurfaceControl {final Choreographer mChoreographer;//编舞者final TraversalRunnable mTraversalRunnable new TraversalRunnable();//回调对象void scheduleTraversals() {if (!mTraversalScheduled) {mTraversalScheduled true;mTraversalBarrier mHandler.getLooper().getQueue().postSyncBarrier();//等待系统垂直刷新同步信号回调TraversalRunnable对象的run方法mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);notifyRendererOfFramePending();pokeDrawLockIfNeeded();}}final class TraversalRunnable implements Runnable {Overridepublic void run() {doTraversal();//继续执行doTraversal}}void doTraversal() {if (mTraversalScheduled) {mTraversalScheduled false;mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);if (mProfile) {Debug.startMethodTracing(ViewAncestor);}//执行performTraversalsperformTraversals();if (mProfile) {Debug.stopMethodTracing();mProfile false;}}} }scheduleTraversals方法会为编舞者对象设置回调最终会等待系统垂直刷新同步信号回调TraversalRunnable对象的run方法该方法会调用doTraversal方法然后进一步调用performTraversals方法。 4、ViewRootImpl的performTraversals方法代码逻辑非常多这里只列出了我们需要关注的代码。 public final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,AttachedSurfaceControl {final IWindowSession mWindowSession;//和WMS通信的Binder对象具体为Session对象public final WindowManager.LayoutParams mWindowAttributes new WindowManager.LayoutParams();//窗口属性final View.AttachInfo mAttachInfo;//控件信息private void performTraversals() {final View host mView;if (host null || !mAdded) {return;}if (mWaitForBlastSyncComplete) {mRequestedTraverseWhilePaused true;return;}mIsInTraversal true;mWillDrawSoon true;boolean windowSizeMayChange false;WindowManager.LayoutParams lp mWindowAttributes;//将当前窗口的最新属性赋值给lpint desiredWindowWidth;int desiredWindowHeight;final int viewVisibility getHostVisibility();final boolean viewVisibilityChanged !mFirst (mViewVisibility ! viewVisibility || mNewSurfaceNeeded|| mAppVisibilityChanged);mAppVisibilityChanged false;final boolean viewUserVisibilityChanged !mFirst ((mViewVisibility View.VISIBLE) ! (viewVisibility View.VISIBLE));WindowManager.LayoutParams params null;...代码省略...//收集mView的属性判断是否需要更新paramsif (collectViewAttributes()) {params lp;}...代码省略...//此方法最终会触发WindowManagerService的relayoutWindow方法relayoutWindow(params, viewVisibility, insetsPending);...代码省略... //测量performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);...代码省略... //布局performLayout(lp, mWidth, mHeight);...代码省略... //绘制performDraw();...代码省略... }private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,boolean insetsPending) throws RemoteException {...代码省略... //调用IWindowSession的relayout方法该方法最终会触发WindowManagerService的relayoutWindow方法int relayoutResult mWindowSession.relayout(mWindow, mSeq, params,(int) (mView.getMeasuredWidth() * appScale 0.5f),(int) (mView.getMeasuredHeight() * appScale 0.5f), viewVisibility,insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,mPendingMergedConfiguration, mSurface);}}performTraversals首先调用collectViewAttributes方法收集所有子View的属性然后调用relayoutWindow方法该方法最终会触发WindowManagerService的relayoutWindow方法然后回继续调用触发View测量的performMeasure方法触发View布局的performLayout方法和触发View绘制的performDraw方法。 三、获取最新的SystemUIVisibility属性 1、ViewRootImpl的collectViewAttributes方法是一个很关键的方法此方法会重新计算最新的SystemUIVisibility属性。 public final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,AttachedSurfaceControl {public final WindowManager.LayoutParams mWindowAttributes new WindowManager.LayoutParams();//窗口属性final View.AttachInfo mAttachInfo;//控件信息private boolean collectViewAttributes() {//判断是否需要重新计算本地属性if (mAttachInfo.mRecomputeGlobalAttributes) {//Log.i(mTag, Computing view hierarchy attributes!);mAttachInfo.mRecomputeGlobalAttributes false;boolean oldScreenOn mAttachInfo.mKeepScreenOn;mAttachInfo.mKeepScreenOn false;//清空已经存在的SystemUiVisibility属性mAttachInfo.mSystemUiVisibility 0;mAttachInfo.mHasSystemUiListeners false;//重新获取窗口视图mView最新的的SystemUI属性赋值给mAttachInfomView.dispatchCollectViewAttributes(mAttachInfo, 0);...代码暂时省略...}return false;}}collectViewAttributes首先会清空当前窗口视图mView已经存在的SystemUiVisibility属性然后调用View的dispatchCollectViewAttributes方法重新获取最新的的SystemUiVisibility属性。 2、View的dispatchCollectViewAttributes方法如下所示。 public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource {int mSystemUiVisibility;void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {performCollectViewAttributes(attachInfo, visibility);}void performCollectViewAttributes(AttachInfo attachInfo, int visibility) {if ((visibility VISIBILITY_MASK) VISIBLE) {if ((mViewFlags KEEP_SCREEN_ON) KEEP_SCREEN_ON) {attachInfo.mKeepScreenOn true;}//将最新的systemuivisiblity赋予AttachInfo的mSystemUiVisibility 属性attachInfo.mSystemUiVisibility | mSystemUiVisibility;//设置最新的SystemUiVisibility监听对象如果不为空则将AttachInfo的mHasSystemUiListeners属性设置为true。ListenerInfo li mListenerInfo;if (li ! null li.mOnSystemUiVisibilityChangeListener ! null) {attachInfo.mHasSystemUiListeners true;}}}} 3、接着看ViewRootImpl的collectViewAttributes方法。 public final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,AttachedSurfaceControl {public final WindowManager.LayoutParams mWindowAttributes new WindowManager.LayoutParams();//窗口属性final View.AttachInfo mAttachInfo;//控件信息private boolean collectViewAttributes() {//判断是否需要重新计算本地属性if (mAttachInfo.mRecomputeGlobalAttributes) {...代码省略...//移除被禁用的SystemUiVisibility属性mAttachInfo.mSystemUiVisibility ~mAttachInfo.mDisabledSystemUiVisibility;//让params引用指向mWindowAttributes对象WindowManager.LayoutParams params mWindowAttributes;mAttachInfo.mSystemUiVisibility | getImpliedSystemUiVisibility(params);if (mAttachInfo.mKeepScreenOn ! oldScreenOn|| mAttachInfo.mSystemUiVisibility ! params.subtreeSystemUiVisibility|| mAttachInfo.mHasSystemUiListeners ! params.hasSystemUiListeners) {applyKeepScreenOnFlag(params);//将重新获取的窗口视图mView的SystemUiVisibility保存到窗口的LayoutParams属性中params.subtreeSystemUiVisibility mAttachInfo.mSystemUiVisibility;params.hasSystemUiListeners mAttachInfo.mHasSystemUiListeners;//调用View的dispatchWindowSystemUiVisiblityChanged方法mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);return true;}}return false;}}在重新获得mView的SystemUiVisibility属性之后首先会从该属性中移除被禁用的SystemUiVisibility属性然后让params引用指向mWindowAttributes对象并将重新获取的保存在mAttachInfo对象中的SystemUiVisibility属性保存到当前窗口的LayoutParams属性中最后会调用当前View的dispatchWindowSystemUiVisiblityChanged方法。 4、View的dispatchWindowSystemUiVisiblityChanged方法如下所示。 public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource {Deprecatedpublic void dispatchWindowSystemUiVisiblityChanged(int visible) {onWindowSystemUiVisibilityChanged(visible);//调用onWindowSystemUiVisibilityChanged方法}public void onWindowSystemUiVisibilityChanged(int visible) {//默认为空实现} }该方法会进一步调用onWindowSystemUiVisibilityChanged方法onWindowSystemUiVisibilityChanged方法默认为空实现但是如果当前mView为DecorView时则不同DecorView实现了此方法。 四、DecorView更新状态栏和导航栏背景颜色 1、DecorView的onWindowSystemUiVisibilityChanged方法如下所示。 frameworks/base/core/java/com/android/internal/policy/DecorView.java public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {Overridepublic void onWindowSystemUiVisibilityChanged(int visible) {//调用updateColorViews方法updateColorViews(null /* insets */, true /* animate */);}}onWindowSystemUiVisibilityChanged方法会调用一个updateColorViews这个关键方法。 2、updateColorViews会调用updateColorViewInt方法更新导航栏和状态栏的背景颜色。 public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {WindowInsets updateColorViews(WindowInsets insets, boolean animate) {//获取窗口的SystemUIVisibility属性int sysUiVisibility attrs.systemUiVisibility | getWindowSystemUiVisibility();//判断窗口类型是否是输入法final boolean isImeWindow mWindow.getAttributes().type WindowManager.LayoutParams.TYPE_INPUT_METHOD;//判断窗口类型不是浮动窗口和输入法则让SystemUIVisibility属性生效if (!mWindow.mIsFloating || isImeWindow) {//获取是否禁止窗口动画的标记boolean disallowAnimate !isLaidOut();disallowAnimate | ((mLastWindowFlags ^ attrs.flags) FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) ! 0;mLastWindowFlags attrs.flags;if (insets ! null) {mLastTopInset getColorViewTopInset(insets.getStableInsetTop(),insets.getSystemWindowInsetTop());mLastBottomInset getColorViewBottomInset(insets.getStableInsetBottom(),insets.getSystemWindowInsetBottom());mLastRightInset getColorViewRightInset(insets.getStableInsetRight(),insets.getSystemWindowInsetRight());mLastLeftInset getColorViewRightInset(insets.getStableInsetLeft(),insets.getSystemWindowInsetLeft());// Dont animate if the presence of stable insets has changed, because that// indicates that the window was either just added and received them for the// first time, or the window size or position has changed.boolean hasTopStableInset insets.getStableInsetTop() ! 0;disallowAnimate | (hasTopStableInset ! mLastHasTopStableInset);mLastHasTopStableInset hasTopStableInset;boolean hasBottomStableInset insets.getStableInsetBottom() ! 0;disallowAnimate | (hasBottomStableInset ! mLastHasBottomStableInset);mLastHasBottomStableInset hasBottomStableInset;boolean hasRightStableInset insets.getStableInsetRight() ! 0;disallowAnimate | (hasRightStableInset ! mLastHasRightStableInset);mLastHasRightStableInset hasRightStableInset;boolean hasLeftStableInset insets.getStableInsetLeft() ! 0;disallowAnimate | (hasLeftStableInset ! mLastHasLeftStableInset);mLastHasLeftStableInset hasLeftStableInset;mLastShouldAlwaysConsumeNavBar insets.shouldAlwaysConsumeNavBar();}boolean navBarToRightEdge isNavBarToRightEdge(mLastBottomInset, mLastRightInset);boolean navBarToLeftEdge isNavBarToLeftEdge(mLastBottomInset, mLastLeftInset);int navBarSize getNavBarSize(mLastBottomInset, mLastRightInset, mLastLeftInset);//更新导航栏颜色mNavigationColorViewState为导航栏的相关筛选条件updateColorViewInt(mNavigationColorViewState, sysUiVisibility,mWindow.mNavigationBarColor, mWindow.mNavigationBarDividerColor, navBarSize/*导航栏高度*/,navBarToRightEdge || navBarToLeftEdge, navBarToLeftEdge,0 /* sideInset */, animate !disallowAnimate, false /* force */);boolean statusBarNeedsRightInset navBarToRightEdge mNavigationColorViewState.present;boolean statusBarNeedsLeftInset navBarToLeftEdge mNavigationColorViewState.present;int statusBarSideInset statusBarNeedsRightInset ? mLastRightInset: statusBarNeedsLeftInset ? mLastLeftInset : 0;//更新状态栏颜色mStatusColorViewState为状态栏的相关筛选条件updateColorViewInt(mStatusColorViewState, sysUiVisibility,calculateStatusBarColor(), 0, mLastTopInset/*状态栏高度*/,false /* matchVertical */, statusBarNeedsLeftInset, statusBarSideInset,animate !disallowAnimate,mForceWindowDrawsStatusBarBackground);}...代码省略...}}关于DecorView更新状态栏、导航栏背景颜色的具体过程请参考Android 9.0系统源码_SystemUI八PhoneWindow更新状态栏和导航栏背景颜色的流程解析。 五、WindowManagerService的relayoutWindow方法 1、重新回到第二节第4步ViewRootImpl的performTraversals方法中。 public final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,AttachedSurfaceControl {final IWindowSession mWindowSession;//和WMS通信的Binder对象具体为Session对象public final WindowManager.LayoutParams mWindowAttributes new WindowManager.LayoutParams();//窗口属性final View.AttachInfo mAttachInfo;//控件信息private void performTraversals() {...代码省略...//收集mView的属性判断是否需要更新paramsif (collectViewAttributes()) {params lp;}...代码省略...//此方法最终会触发WindowManagerService的relayoutWindow方法relayoutWindow(params, viewVisibility, insetsPending);...代码省略... //测量performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);...代码省略... //布局performLayout(lp, mWidth, mHeight);...代码省略... //绘制performDraw();...代码省略... }private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,boolean insetsPending) throws RemoteException {...代码省略... //调用IWindowSession的relayout方法该方法最终会触发WindowManagerService的relayoutWindow方法int relayoutResult mWindowSession.relayout(mWindow, mSeq, params,(int) (mView.getMeasuredWidth() * appScale 0.5f),(int) (mView.getMeasuredHeight() * appScale 0.5f), viewVisibility,insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,mPendingMergedConfiguration, mSurface);}}在调用collectViewAttributes获取最新的systemUIVisibiliy属性之后会调用relayoutWindow方法该方法进一步调用IWindowSession的relayout方法IWindowSession的具体实现类为Session。 2、Session的relayout方法如下所示。 frameworks/base/services/core/java/com/android/server/wm/Session.java class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {final WindowManagerService mService;Overridepublic int relayout(IWindow window, WindowManager.LayoutParams attrs,int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,SurfaceControl outSurfaceControl, InsetsState outInsetsState,InsetsSourceControl[] outActiveControls, Point outSurfaceSize) {int res mService.relayoutWindow(this, window, attrs,requestedWidth, requestedHeight, viewFlags, flags, frameNumber,outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,outActiveControls, outSurfaceSize);return res;} }relayout方法会进一步调用WindowManagerService的relayoutWindow方法。 3、WindowManagerService的relayoutWindow方法如下所示。 frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs/**窗口属性**/,int requestedWidth, int requestedHeight, int viewVisibility/**根View控件是否可见**/, 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;//是否有状态栏的使用权限final boolean hasStatusBarPermission mContext.checkCallingOrSelfPermission(permission.STATUS_BAR) PackageManager.PERMISSION_GRANTED;//是否有状态栏服务的使用权限final boolean hasStatusBarServicePermission mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE) PackageManager.PERMISSION_GRANTED;long origId Binder.clearCallingIdentity();final int displayId;synchronized(mWindowMap) {//获取当前要操作的窗口对象WindowState win windowForClientLocked(session, client, false);if (win null) {return 0;}//获取窗口所属的屏幕设备iddisplayId win.getDisplayId();//窗口动画WindowStateAnimator winAnimator win.mWinAnimator;if (viewVisibility ! View.GONE) {win.setRequestedSize(requestedWidth, requestedHeight);}win.setFrameNumber(frameNumber);int attrChanges 0;int flagChanges 0;if (attrs ! null) {//如果窗口属性不为空这里会对窗口的相关属性进行一次预处理mPolicy.adjustWindowParamsLw(win, attrs, hasStatusBarServicePermission);// if they dont have the permission, mask out the status bar bitsif (seq win.mSeq) {int systemUiVisibility attrs.systemUiVisibility| attrs.subtreeSystemUiVisibility;if ((systemUiVisibility DISABLE_MASK) ! 0) {if (!hasStatusBarPermission) {systemUiVisibility ~DISABLE_MASK;}}win.mSystemUiVisibility systemUiVisibility;}if (win.mAttrs.type ! attrs.type) {throw new IllegalArgumentException(Window type can not be changed after the window is added.);}// Odd choice but less odd than embedding in copyFrom()if ((attrs.privateFlags WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY)! 0) {attrs.x win.mAttrs.x;attrs.y win.mAttrs.y;attrs.width win.mAttrs.width;attrs.height win.mAttrs.height;}//检测窗口标记和样式是否发生了变化flagChanges win.mAttrs.flags ^ attrs.flags;attrChanges win.mAttrs.copyFrom(attrs);if ((attrChanges (WindowManager.LayoutParams.LAYOUT_CHANGED| WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) ! 0) {win.mLayoutNeeded true;}if (win.mAppToken ! null ((flagChanges FLAG_SHOW_WHEN_LOCKED) ! 0|| (flagChanges FLAG_DISMISS_KEYGUARD) ! 0)) {win.mAppToken.checkKeyguardFlagsChanged();}if (((attrChanges LayoutParams.ACCESSIBILITY_TITLE_CHANGED) ! 0) (mAccessibilityController ! null) (win.getDisplayId() DEFAULT_DISPLAY)) {// No move or resize, but the controller checks for title changes as wellmAccessibilityController.onSomeWindowResizedOrMovedLocked();}if ((flagChanges PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) ! 0) {updateNonSystemOverlayWindowsVisibilityIfNeeded(win, win.mWinAnimator.getShown());}}...代码省略... if (focusMayChange) {//System.out.println(Focus may change: win.mAttrs.getTitle());if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,false /*updateInputWindows*/)) {imMayMove false;}//System.out.println(Relayout win : focus mCurrentFocus);}...代码省略... } }relayoutWindow方法会调用一个关键方法updateFocusedWindowLocked。 4、WindowManagerService的updateFocusedWindowLocked方法如下所示。 public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {//窗口管理策略的接口类WindowManagerPolicyWMP它用来定义一个窗口策略所要遵循的通用规范。final WindowManagerPolicy mPolicy;//根窗口RootWindowContainer mRoot;boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {//获取当前最新的焦点窗口WindowState newFocus mRoot.computeFocusedWindow();if (mCurrentFocus ! newFocus) {//如果窗口焦点发生了变化Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, wmUpdateFocus);// This check makes sure that we dont already have the focus// change message pending.mH.removeMessages(H.REPORT_FOCUS_CHANGE);mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);// TODO(multidisplay): Focused windows on default display only.final DisplayContent displayContent getDefaultDisplayContentLocked();boolean imWindowChanged false;if (mInputMethodWindow ! null) {//如果输入法窗口不为空final WindowState prevTarget mInputMethodTarget;final WindowState newTarget displayContent.computeImeTarget(true /* updateImeTarget*/);imWindowChanged prevTarget ! newTarget;if (mode ! UPDATE_FOCUS_WILL_ASSIGN_LAYERS mode ! UPDATE_FOCUS_WILL_PLACE_SURFACES) {final int prevImeAnimLayer mInputMethodWindow.mWinAnimator.mAnimLayer;displayContent.assignWindowLayers(false /* setLayoutNeeded */);imWindowChanged |prevImeAnimLayer ! mInputMethodWindow.mWinAnimator.mAnimLayer;}}if (imWindowChanged) {//输入法窗口发生了变化mWindowsChanged true;displayContent.setLayoutNeeded();newFocus mRoot.computeFocusedWindow();}if (DEBUG_FOCUS_LIGHT || localLOGV) Slog.v(TAG_WM, Changing focus from mCurrentFocus to newFocus Callers Debug.getCallers(4));final WindowState oldFocus mCurrentFocus;mCurrentFocus newFocus;mLosingFocus.remove(newFocus);if (mCurrentFocus ! null) {mWinAddedSinceNullFocus.clear();mWinRemovedSinceNullFocus.clear();}//调用WindowManagerPolicy的focusChangedLw方法int focusChanged mPolicy.focusChangedLw(oldFocus, newFocus);if (imWindowChanged oldFocus ! mInputMethodWindow) {// Focus of the input method window changed. Perform layout if needed.if (mode UPDATE_FOCUS_PLACING_SURFACES) {displayContent.performLayout(true /*initial*/, updateInputWindows);focusChanged ~FINISH_LAYOUT_REDO_LAYOUT;} else if (mode UPDATE_FOCUS_WILL_PLACE_SURFACES) {// Client will do the layout, but we need to assign layers// for handleNewWindowLocked() below.displayContent.assignWindowLayers(false /* setLayoutNeeded */);}}if ((focusChanged FINISH_LAYOUT_REDO_LAYOUT) ! 0) {// The change in focus caused us to need to do a layout. Okay.displayContent.setLayoutNeeded();if (mode UPDATE_FOCUS_PLACING_SURFACES) {displayContent.performLayout(true /*initial*/, updateInputWindows);}}if (mode ! UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {// If we defer assigning layers, then the caller is responsible for// doing this part.mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);}displayContent.adjustForImeIfNeeded();// We may need to schedule some toast windows to be removed. The toasts for an app that// does not have input focus are removed within a timeout to prevent apps to redress// other apps UI.displayContent.scheduleToastWindowsTimeoutIfNeededLocked(oldFocus, newFocus);Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);return true;}return false;}}updateFocusedWindowLocked首先是获取最新的焦点窗口之后还会判断当前窗口焦点是否发生了变化如果发生了变化则会调用WindowManagerPolicy的focusChangedLw方法。 五、PhoneWindowManager的updateSystemUiVisibilityLw方法 1、WindowManagerPolicy是一个抽象接口。 frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java public interface WindowManagerPolicy extends WindowManagerPolicyConstants {/*** 一个新的窗口持有了焦点*/public int focusChangedLw(WindowState lastFocus, WindowState newFocus); }结合Android 9.0系统源码_窗口管理一WindowManagerService的启动流程这篇文章我们可以知道SystemServer在窗口WindowManagerService对象的时候将PhoneWindowManager对象实例赋值给了mPolicy。 2、来看下PhoneWindowManager是如何实现focusChangedLw方法的。 frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java public class PhoneWindowManager implements WindowManagerPolicy {Overridepublic int focusChangedLw(WindowState lastFocus, WindowState newFocus) {mFocusedWindow newFocus;if ((updateSystemUiVisibilityLw()SYSTEM_UI_CHANGING_LAYOUT) ! 0) {// If the navigation bar has been hidden or shown, we need to do another// layout pass to update that window.return FINISH_LAYOUT_REDO_LAYOUT;}return 0;}//更新窗口的SystemUiVisibility属性参数private int updateSystemUiVisibilityLw() {//获取当前的焦点窗口WindowState winCandidate mFocusedWindow ! null ? mFocusedWindow: mTopFullscreenOpaqueWindowState;//如果不存在焦点窗口则直接返回if (winCandidate null) {return 0;}if (winCandidate.getAttrs().token mImmersiveModeConfirmation.getWindowToken()) {winCandidate isStatusBarKeyguard() ? mStatusBar : mTopFullscreenOpaqueWindowState;if (winCandidate null) {return 0;}}final WindowState win winCandidate;if ((win.getAttrs().privateFlags PRIVATE_FLAG_KEYGUARD) ! 0 mKeyguardOccluded) {return 0;}int tmpVisibility PolicyControl.getSystemUiVisibility(win, null) ~mResettingSystemUiFlags ~mForceClearedSystemUiFlags;if (mForcingShowNavBar win.getSurfaceLayer() mForcingShowNavBarLayer) {tmpVisibility ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);}//获取和SystemUIVisibility相关的各种窗口参数final int fullscreenVisibility updateLightStatusBarLw(0 /* vis */,mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);final int dockedVisibility updateLightStatusBarLw(0 /* vis */,mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);mWindowManagerFuncs.getStackBounds(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds);mWindowManagerFuncs.getStackBounds(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);final int visibility updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);final int diff visibility ^ mLastSystemUiFlags;final int fullscreenDiff fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;final int dockedDiff dockedVisibility ^ mLastDockedStackSysUiFlags;final boolean needsMenu win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);if (diff 0 fullscreenDiff 0 dockedDiff 0 mLastFocusNeedsMenu needsMenu mFocusedApp win.getAppToken() mLastNonDockedStackBounds.equals(mNonDockedStackBounds) mLastDockedStackBounds.equals(mDockedStackBounds)) {return 0;}mLastSystemUiFlags visibility;mLastFullscreenStackSysUiFlags fullscreenVisibility;mLastDockedStackSysUiFlags dockedVisibility;mLastFocusNeedsMenu needsMenu;mFocusedApp win.getAppToken();final Rect fullscreenStackBounds new Rect(mNonDockedStackBounds);final Rect dockedStackBounds new Rect(mDockedStackBounds);mHandler.post(new Runnable() {Overridepublic void run() {StatusBarManagerInternal statusbar getStatusBarManagerInternal();if (statusbar ! null) {//最终会触发状态栏管理服务StatusBarManagerService的setSystemUiVisibility方法//通知状态栏和底部栏进行样式调整statusbar.setSystemUiVisibility(visibility, fullscreenVisibility,dockedVisibility, 0xffffffff, fullscreenStackBounds,dockedStackBounds, win.toString());statusbar.topAppWindowChanged(needsMenu);}}});return diff;} }PhoneWindowManager的focusChangedLw方法直接调用了updateSystemUiVisibilityLw方法此方法会对窗口的SystemUiVisibility属性做一些处理最终调用状态栏管理服务StatusBarManagerService的setSystemUiVisibility方法通知状态栏和底部栏进行样式调整。 3、updateSystemUiVisibilityLw方法中有用到对SystemUIVisibility属性做处理的几个关键方法updateLightStatusBarLw、chooseNavigationColorWindowLw、updateLightNavigationBarLw和updateSystemBarsLw这里一并贴出有兴趣的可以看下。 public class PhoneWindowManager implements WindowManagerPolicy {private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {final boolean onKeyguard isStatusBarKeyguard() !mKeyguardOccluded;final WindowState statusColorWin onKeyguard ? mStatusBar : opaqueOrDimming;if (statusColorWin ! null (statusColorWin opaque || onKeyguard)) {// If the top fullscreen-or-dimming window is also the top fullscreen, respect// its light flag.vis ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;vis | PolicyControl.getSystemUiVisibility(statusColorWin, null) View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;} else if (statusColorWin ! null statusColorWin.isDimming()) {// Otherwise if its dimming, clear the light flag.vis ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;}return vis;}VisibleForTestingNullablestatic WindowState chooseNavigationColorWindowLw(WindowState opaque,WindowState opaqueOrDimming, WindowState imeWindow,NavigationBarPosition int navBarPosition) {// If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME// window can be navigation color window.final boolean imeWindowCanNavColorWindow imeWindow ! null imeWindow.isVisibleLw() navBarPosition NAV_BAR_BOTTOM (PolicyControl.getWindowFlags(imeWindow, null) WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) ! 0;if (opaque ! null opaqueOrDimming opaque) {// If the top fullscreen-or-dimming window is also the top fullscreen, respect it// unless IME window is also eligible, since currently the IME window is always show// above the opaque fullscreen app window, regardless of the IME target window.// TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.return imeWindowCanNavColorWindow ? imeWindow : opaque;}if (opaqueOrDimming null || !opaqueOrDimming.isDimming()) {// No dimming window is involved. Determine the result only with the IME window.return imeWindowCanNavColorWindow ? imeWindow : null;}if (!imeWindowCanNavColorWindow) {// No IME window is involved. Determine the result only with opaqueOrDimming.return opaqueOrDimming;}// The IME window and the dimming window are competing. Check if the dimming window can be// IME target or not.if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {// The IME window is above the dimming window.return imeWindow;} else {// The dimming window is above the IME window.return opaqueOrDimming;}}VisibleForTestingstatic int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,WindowState imeWindow, WindowState navColorWin) {if (navColorWin ! null) {if (navColorWin imeWindow || navColorWin opaque) {// Respect the light flag.vis ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;vis | PolicyControl.getSystemUiVisibility(navColorWin, null) View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;} else if (navColorWin opaqueOrDimming navColorWin.isDimming()) {// Clear the light flag for dimming window.vis ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;}}return vis;}private int updateSystemBarsLw(WindowState win, int oldVis, int vis) {final boolean dockedStackVisible mWindowManagerInternal.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);final boolean freeformStackVisible mWindowManagerInternal.isStackVisible(WINDOWING_MODE_FREEFORM);final boolean resizing mWindowManagerInternal.isDockedDividerResizing();// We need to force system bars when the docked stack is visible, when the freeform stack// is visible but also when we are resizing for the transitions when docked stack// visibility changes.mForceShowSystemBars dockedStackVisible || freeformStackVisible || resizing;final boolean forceOpaqueStatusBar mForceShowSystemBars !mForceStatusBarFromKeyguard;// apply translucent bar vis flagsWindowState fullscreenTransWin isStatusBarKeyguard() !mKeyguardOccluded? mStatusBar: mTopFullscreenOpaqueWindowState;vis mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);vis mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);final int dockedVis mStatusBarController.applyTranslucentFlagLw(mTopDockedOpaqueWindowState, 0, 0);final boolean fullscreenDrawsStatusBarBackground drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);final boolean dockedDrawsStatusBarBackground drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);// prevent status bar interaction from clearing certain flagsint type win.getAttrs().type;boolean statusBarHasFocus type TYPE_STATUS_BAR;if (statusBarHasFocus !isStatusBarKeyguard()) {int flags View.SYSTEM_UI_FLAG_FULLSCREEN| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION| View.SYSTEM_UI_FLAG_IMMERSIVE| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;if (mKeyguardOccluded) {flags | View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;}vis (vis ~flags) | (oldVis flags);}if (fullscreenDrawsStatusBarBackground dockedDrawsStatusBarBackground) {vis | View.STATUS_BAR_TRANSPARENT;vis ~View.STATUS_BAR_TRANSLUCENT;} else if ((!areTranslucentBarsAllowed() fullscreenTransWin ! mStatusBar)|| forceOpaqueStatusBar) {vis ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);}vis configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing);// update status barboolean immersiveSticky (vis View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) ! 0;final boolean hideStatusBarWM mTopFullscreenOpaqueWindowState ! null (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null) WindowManager.LayoutParams.FLAG_FULLSCREEN) ! 0;final boolean hideStatusBarSysui (vis View.SYSTEM_UI_FLAG_FULLSCREEN) ! 0;final boolean hideNavBarSysui (vis View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) ! 0;final boolean transientStatusBarAllowed mStatusBar ! null (statusBarHasFocus || (!mForceShowSystemBars (hideStatusBarWM || (hideStatusBarSysui immersiveSticky))));final boolean transientNavBarAllowed mNavigationBar ! null !mForceShowSystemBars hideNavBarSysui immersiveSticky;final long now SystemClock.uptimeMillis();final boolean pendingPanic mPendingPanicGestureUptime ! 0 now - mPendingPanicGestureUptime PANIC_GESTURE_EXPIRATION;if (pendingPanic hideNavBarSysui !isStatusBarKeyguard() mKeyguardDrawComplete) {// The user performed the panic gesture recently, were about to hide the bars,// were no longer on the Keyguard and the screen is ready. We can now request the bars.mPendingPanicGestureUptime 0;mStatusBarController.showTransient();if (!isNavBarEmpty(vis)) {mNavigationBarController.showTransient();}}final boolean denyTransientStatus mStatusBarController.isTransientShowRequested() !transientStatusBarAllowed hideStatusBarSysui;final boolean denyTransientNav mNavigationBarController.isTransientShowRequested() !transientNavBarAllowed;if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {// clear the clearable flags insteadclearClearableFlagsLw();vis ~View.SYSTEM_UI_CLEARABLE_FLAGS;}final boolean immersive (vis View.SYSTEM_UI_FLAG_IMMERSIVE) ! 0;immersiveSticky (vis View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) ! 0;final boolean navAllowedHidden immersive || immersiveSticky;if (hideNavBarSysui !navAllowedHidden getWindowLayerLw(win) getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {// We cant hide the navbar from this window otherwise the input consumer would not get// the input events.vis (vis ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);}vis mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);// update navigation barboolean oldImmersiveMode isImmersiveMode(oldVis);boolean newImmersiveMode isImmersiveMode(vis);if (win ! null oldImmersiveMode ! newImmersiveMode) {final String pkg win.getOwningPackage();mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,isUserSetupComplete(), isNavBarEmpty(win.getSystemUiVisibility()));}vis mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);final WindowState navColorWin chooseNavigationColorWindowLw(mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,mWindowManagerFuncs.getInputMethodWindowLw(), mNavigationBarPosition);vis updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,mTopFullscreenOpaqueOrDimmingWindowState,mWindowManagerFuncs.getInputMethodWindowLw(), navColorWin);return vis;} }
http://www.zqtcl.cn/news/754552/

相关文章:

  • 青岛海川建设集团有限公司网站wordpress 变私有云
  • 网站备案人可以改吗石大网页设计与网站建设客观题
  • 宁波网站优化方案免费关键词挖掘工具
  • 网站制作想法免费做效果图网站
  • 晓风彩票网站建设软件微信上发的链接网站怎么做的
  • 关键词有哪几种台州优秀关键词优化
  • 盐田区住房和建设局网站软件开发文档怎么编写
  • 网站响应式建设seo排名优化怎样
  • 山东 网站备案德清县建设局网站
  • 中英语双语网站咋做提供网站建设设计外包
  • 云网站功能江门网站seo关键词排名优化
  • 潍坊网站建设外贸制作html网站
  • 网站友情链接怎么添加定制酒营销方案
  • 目前最流行网站开发软件泰州市建设工程招标网
  • 福州网站优化me域名网站
  • 网站 案例互联网外包公司值得去吗
  • 做医疗护具网站浙江立鹏建设有限公司网站
  • 织梦制作手机网站c 网站开发需要学什么软件
  • 罗湖网站制作阿里巴巴开店网站怎么做
  • 深圳住房和建设局网站 招标怎样建设自己的视频网站
  • 网站建设的目的模板茶网站建设需要多少钱
  • 珠海市城乡住房建设局网站网站外链
  • 福田做网站需要多少钱做淘宝客网站性质
  • html网站怎么进入后台网站主题怎么写
  • wordpress怎么ftp建站高端网站建设域名注册
  • 我用织梦5.7做个网站应该把淘宝客店铺链接放到哪聊天软件开发需要多少钱
  • 站长工具爱站竞价单页网站制作
  • 网站分类目录大全购物网站大全棉鞋
  • 网站镜像做排名建立外贸英文网站应该怎么做
  • 上海做网站就用乐云seo手机网站cms 下载