基于Android R版本分析
WMS&View关系架构
View 树
例如在布局中给Activity设置一个布局xml,最顶层的布局LinearLayout就是view树的根,它包含的所有view都是该View树的节点,View树对应一个window;
在Android系统中,几乎所有的UI元素都是基于View和ViewGroup创建的,ViewGroup和View是组合模式的典型应用;
-
View:一块可以用来进行绘画,可以处理输入事件进行交互的矩形区域;
View是基本的控件元素,ViewManager接口定义了添加、删除View的接口addView、removeView;
-
ViewGroup:可以容纳View的矩形容器;
ViewGroup实现了ViewParent的接口,因此可以作为容器管理View,同时ViewGroup又继承自View,可以被其他的ViewGroup管理。这样ViewGroup和View就可以组成上面的树状结构了;
View树创建
View树的创建方式有两种:
- 通过Layout资源创建View树;
- 通过代码动态创建View树;
Layout资源创建View
同样也有两种方式创建:
- 通过LayoutInflater.inflater()方法加载Layout布局;
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.main, null);
- 通过setContentView()方法加载Layout布局;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
}
通过Layout资源创建View树的优势是层次结构清晰,管理方便。同时View树中各个View的属性也可以在layout资源里进行设置。缺点是无法在应用运行时对View树结构进行变化;
代码动态创建View树
通过代码调用ViewGroup的addView()、removeView()等接口实现View树的创建;
TextView text = new TextView(this);
Button button = new Button(this);
FrameLayout frame = new FrameLayout(this);
frame.addView(text);
LinearLayout linear = new LinearLayout(this);
linear.setOrientation(LinearLayout.VERTICAL);
linear.addView(frame);
linear.addView(button);
Window
在Android系统中,屏幕的抽象是DisplayContent,在屏幕的抽象上,通过不同的窗口,展示不同的应用程序页面和一些其他UI组件(Activity、Dialog、StatusBar等)。Window通过在Z轴叠放,从而实现了复杂的交互逻辑;
- Window: 是一个处理顶级窗口外观和行为策略的抽象基类,它的具体实现是 PhoneWindow 类,PhoneWindow 对 View 进行管理;
- ViewRootImpl:代表的是Android视图层次结构的顶部,是View和WindowManager之间的桥梁。Android的视图层次结构是树结构,ViewRootImpl实际上就是输的根节点的抽象,WindowManager通过根节点对象,来更新整个树结构上的View节点的内容;
- Session:用于其他应用程序和WMS通信之间的通道,每个应用程序都会有一个Session,在WMS通过mSessions属性保存,它的类型为ArraySet;
- WindowState:代表WMS管理的一个窗口,继承自WindowContainer,并实现了一些其他接口;
WindowToken & WindowState
- WindowToken:WindowToken将同一应用组件(Activity、InputMethod、Wallpaper或者Dream)的窗口(WindowState)组织到一起;
class WindowToken extends WindowContainer<WindowState>
表明WindowToken是容器,其中存放WindowState;
WMS对窗口的管理过程中,用WindowToken指代一个应用组件。例如在进行窗口ZOrder排序的时候,同属于一个WindowToken的窗口(WindowState)会被排在一起,且其中定义的属性会影响到所有属于这个WindowToken的窗口;
Window add
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
...
//1
int res = mPolicy.checkAddPermission(attrs, appOp);
...
synchronized(mWindowMap) {
//2
final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
//3
parentWindow = windowForClientLocked(null, attrs.token, false);
}
...
//4
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
if (token == null) {
final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
//5
token = new WindowToken(this, binder, type, false, displayContent,
session.mCanAddInternalSystemWindow);
}
...
//6
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
...
//7
mPolicy.adjustWindowParamsLw(win.mAttrs);
...
if (openInputChannels) {
//8
win.openInputChannel(outInputChannel);
}
...
//9
mWindowMap.put(client.asBinder(), win);
...
//10
win.mToken.addWindow(win);
...
//11
displayContent.assignWindowLayers(false /* setLayoutNeeded */);
//12
if (focusChanged) {
mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
}
mInputMonitor.updateInputWindowsLw(false /*force*/);
}
...
return res;
}
- 检查当前 Window 的 token 等权限合法性;
- 使用 RootWindowContainer 的子容器中获取一个 DisplayContent,如果子容器集合中不存在,则去获取一个,并添加到 child 集合中;
- 如果是 Dialog 等子窗口,则获取父窗口,没有就报找不到父窗口的异常;
- 使用 attr.token 去 displayContent 的键值对 mTokenMap 中获取对应的 WindowToken,WindowToken 中保存了一组 Window;
- 如果4中 WindowToken 为 null,则创建一个 WindowToken,传入 app 层传入的 attr.token 以及 displayContent 对象,内部会将这个创建的 WindowToken 保存到 displayContent 中;
- 创建一个 WindowState,并传入所有关于 Window 相关的属性,这样 WindowState 在 WMS 中就是以一个 Window 性质存在了、WindowState 构造过程中会将其添加到 WindowToken 中去;
- 根据 mPolicy 调整 window 的 attr 属性,mPolicy 的实现类是PhoneManagerPolicy;
- 执行 WindowState 的 openInputChannel,这里主要是打通和 Input 系统的通道,用于接收 IMS 的输入事件请求;
- 将客户端 app 层的 Window 对象和 WindowState 关联上,这样 WMS 就可以通过 Window 找到 WMS 中的 WindowState 对象;
- win.mToken 是前面创建的 WindowToken 对象,所以此处就是将WindowState 加入到 WindowToken 的子容器集合中;
- 分配窗口的层级,这里的 setLayoutNeeded 参数为 false,说明不需要进行 Layout 操作;
根据addWindow的逻辑,DisplayContent、WindowToken、WindowState之间的映射关系:
- WindowContainer:定义了一组可以直接或通过其子类以层次结构形式保存Window的类的常用功能;
主要就是创建了一个和 Window 一一对应的 WindowState 对象,并将 WindowState 插入到父容器 WindowToken 的子容器集合中,而 WindowToken 又保存在 DisplayContent 的键值对集合中;
WindowInsets
Insets:插入物,屏幕上除了App绘制的内容还有系统的插入物,例如:StatusBar、NavigationBar、IME(软键盘)等,这些系统UI和应用UI有可能出现冲突。Insets可以将所需要绘制的View从屏幕边缘向内移动到一个合适的位置;
public final class Insets implements Parcelable {
public static final @NonNull Insets NONE = new Insets(0, 0, 0, 0);
public final int left;
public final int top;
public final int right;
public final int bottom;
private Insets(int left, int top, int right, int bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
……………………
}
Insets定义了窗口上下左右对其他SystemUI等系统UI的偏移;
在Android 中,Insets区域则由WindowInsets类表示;
dumpsys window
WindowInsetsStateController
InsetsState
InsetsSource type=ITYPE_STATUS_BAR frame=[0,0][1440,171] visible=true
InsetsSource type=ITYPE_NAVIGATION_BAR frame=[0,2792][1440,2960] visible=true
InsetsSource type=ITYPE_TOP_GESTURES frame=[0,0][1440,171] visible=true
InsetsSource type=ITYPE_BOTTOM_GESTURES frame=[0,2792][1440,2960] visible=true
InsetsSource type=ITYPE_LEFT_GESTURES frame=[0,0][0,2960] visible=true
InsetsSource type=ITYPE_RIGHT_GESTURES frame=[1440,0][1440,2960] visible=true
InsetsSource type=ITYPE_TOP_TAPPABLE_ELEMENT frame=[0,0][1440,171] visible=true
InsetsSource type=ITYPE_BOTTOM_TAPPABLE_ELEMENT frame=[0,2792][1440,2960] visible=true
InsetsSource type=ITYPE_LEFT_DISPLAY_CUTOUT frame=[0,0][-2147483648,2960] visible=true
InsetsSource type=ITYPE_TOP_DISPLAY_CUTOUT frame=[0,0][1440,171] visible=true
InsetsSource type=ITYPE_RIGHT_DISPLAY_CUTOUT frame=[2147483647,0][1440,2960] visible=true
InsetsSource type=ITYPE_BOTTOM_DISPLAY_CUTOUT frame=[0,2147483647][1440,2960] visible=true
InsetsSource type=ITYPE_IME frame=[0,0][0,0] visible=false
Control map:
ITYPE_IME -> Window{c97004c u0 com.example.android.pictureinpicture/com.example.android.pictureinpicture.MainActivity}
ITYPE_NAVIGATION_BAR -> Window{c97004c u0 com.example.android.pictureinpicture/com.example.android.pictureinpicture.MainActivity}
ITYPE_STATUS_BAR -> Window{c97004c u0 com.example.android.pictureinpicture/com.example.android.pictureinpicture.MainActivity}
InsetsSourceProviders map:
ITYPE_IME ->
WindowInsets
WindowInsets用于描述窗口内容的一组插入。简单就是用来获取系统控件的位置,然后来适配我们自己的View的位置;
public final class WindowInsets {
//
private final Insets[] mTypeInsetsMap;
private final Insets[] mTypeMaxInsetsMap;
private final boolean[] mTypeVisibilityMap;
@Nullable private Rect mTempRect;
private final boolean mIsRound;
@Nullable private final DisplayCutout mDisplayCutout;
/**
* In multi-window we force show the navigation bar. Because we don't want that the surface size
* changes in this mode, we instead have a flag whether the navigation bar size should always
* be consumed, so the app is treated like there is no virtual navigation bar at all.
*/
private final boolean mAlwaysConsumeSystemBars;
// 判断SystemInsets是否已经被使用
private final boolean mSystemWindowInsetsConsumed;
// 判断StableInsets是否已经被使用
private final boolean mStableInsetsConsumed;
private final boolean mDisplayCutoutConsumed;
private final int mCompatInsetsTypes;
private final boolean mCompatIgnoreVisibility;
……………………
}
在Android P版本中,WindowInsets还定义了三个变量(类型为Rect):
- mSystemWindowInsets:代表着整个屏幕窗口上,状态栏,导航栏,输入法等系统窗口占用的区域;
- mWindowDecorInsets:表示内容窗口下,被Android FrameWork提供的窗体,诸如ActionBar, TitleBar, ToolBar部分或全部覆盖区域,也可以简单理解为装饰区域,出去状态栏、导航栏等系统区域的区域;
- mStableInsets:代表着整个屏幕窗口上,被系统UI部分或者全部覆盖的区域;
在Android R版本中,这个概念移除了上述定义;
WindowInsets.Type
WindowInsets.Type来表示不同的窗口装饰区域类型的,该类使用二进制整数的每一位来标识特定的窗口装饰区域类型
/**
* Class that defines different types of sources causing window insets.
*/
public static final class Type {
static final int FIRST = 1 << 0;
static final int STATUS_BARS = FIRST;
static final int NAVIGATION_BARS = 1 << 1;
static final int CAPTION_BAR = 1 << 2;
static final int IME = 1 << 3;
static final int SYSTEM_GESTURES = 1 << 4;
static final int MANDATORY_SYSTEM_GESTURES = 1 << 5;
static final int TAPPABLE_ELEMENT = 1 << 6;
static final int DISPLAY_CUTOUT = 1 << 7;
static final int LAST = 1 << 8;
static final int SIZE = 9;
static final int WINDOW_DECOR = LAST;
static int indexOf(@InsetsType int type) {
switch (type) {
case STATUS_BARS: // 状态栏
return 0;
case NAVIGATION_BARS: // 导航栏
return 1;
case CAPTION_BAR: // 标题栏
return 2;
case IME: // 软键盘
return 3;
case SYSTEM_GESTURES: // 系统手势
return 4;
case MANDATORY_SYSTEM_GESTURES: // 强制系统手势
return 5;
case TAPPABLE_ELEMENT:
return 6;
case DISPLAY_CUTOUT:
return 7;
case WINDOW_DECOR:
return 8;
default:
throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
+ " type=" + type);
}
}
……………………
private Type() {
}
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, value = {STATUS_BARS, NAVIGATION_BARS, CAPTION_BAR, IME, WINDOW_DECOR,
SYSTEM_GESTURES, MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT, DISPLAY_CUTOUT})
public @interface InsetsType {
}
/**
* @return An insets type representing any system bars for displaying status.
*/
// 这个就是我们常用的方法,在应用层中,通过WindowInsets.的方式获取需要调整的SystemWindow Type
public static @InsetsType int statusBars() {
return STATUS_BARS;
}
}
InsetsSource
表示产生Insets的Window状态信息,例如 Insets 大小、是否可见等信息;
public class InsetsSource implements Parcelable {
private final @InternalInsetsType int mType;
/** Frame of the source in screen coordinate space */
// Frame的Window窗口在屏幕坐标空间
private final Rect mFrame;
// 可见区域
private @Nullable Rect mVisibleFrame;
// 可见性状态
private boolean mVisible;
private final Rect mTmpFrame = new Rect();
}
InsetsSource type=ITYPE_STATUS_BAR frame=[0,0][1440,171] visible=true
- mType:ITYPE_STATUS_BAR
- mFrame:
[0,0][1440,171] - mVisibleFrame:null
- mVisible:true
InsetsSourceControl
对InsetsSource的控制者,用来控制Insets的产生者,内部持有控制动画的Leash;
InsetsSourceControl被 InsetsController 所持有,同样也是在 ViewRootImpl:: relayoutWindow 时从 WMS 中获得;
public class InsetsSourceControl implements Parcelable {
// 指定了该Control的类型,映射到InsetsState.InternalInsetsType
private final @InternalInsetsType int mType;
// Insets窗口的父节点,可以用来控制窗口的属性
private final @Nullable SurfaceControl mLeash;
private final Point mSurfacePosition;
public InsetsSourceControl(@InternalInsetsType int type, @Nullable SurfaceControl leash,
Point surfacePosition) {
mType = type;
mLeash = leash;
mSurfacePosition = surfacePosition;
}
public InsetsSourceControl(InsetsSourceControl other) {
mType = other.mType;
if (other.mLeash != null) {
mLeash = new SurfaceControl(other.mLeash, "InsetsSourceControl");
} else {
mLeash = null;
}
mSurfacePosition = new Point(other.mSurfacePosition);
}
}
InsetsSourceControl会根据Type类型的InsetsSource信息来控制动画的绘制逻辑;
InsetsSourceProvider
代表特定InsetsSource在server端的控制者,他被称作Provider是因为他提供InsetsSource给客户端(客户端通过InsetsSourceConsumer使用InsetsSource);
class InsetsSourceProvider {
protected final DisplayContent mDisplayContent;
// 代表持有的InsetsSource实例
protected final @NonNull InsetsSource mSource;
// 代表了对应的Window窗口,该WindowState和InsetsSource有一一映射关系
protected WindowState mWin;
private final Rect mTmpRect = new Rect();
private final InsetsStateController mStateController;
private final InsetsSourceControl mFakeControl;
private @Nullable InsetsSourceControl mControl;
private @Nullable InsetsControlTarget mControlTarget;
private @Nullable InsetsControlTarget mPendingControlTarget;
private @Nullable InsetsControlTarget mFakeControlTarget;
private @Nullable ControlAdapter mAdapter;
private TriConsumer<DisplayFrames, WindowState, Rect> mFrameProvider;
private TriConsumer<DisplayFrames, WindowState, Rect> mImeFrameProvider;
private final Rect mImeOverrideFrame = new Rect();
private boolean mIsLeashReadyForDispatching;
/** The visibility override from the current controlling window. */
private boolean mClientVisible;
/**
* Whether the window is available and considered visible as in {@link WindowState#isVisible}.
*/
private boolean mServerVisible;
private boolean mSeamlessRotating;
private long mFinishSeamlessRotateFrameNumber = -1;
private final boolean mControllable;
}
InsetsSourceConsumer
对单一 InsetsSource 的消费者,其内部持有 InsetsSourceControl,可以控制其leash的可见性和动画;
public class InsetsSourceConsumer {
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {ShowResult.SHOW_IMMEDIATELY, ShowResult.IME_SHOW_DELAYED, ShowResult.IME_SHOW_FAILED})
@interface ShowResult {
/**
* Window type is ready to be shown, will be shown immidiately.
*/
int SHOW_IMMEDIATELY = 0;
/**
* Result will be delayed. Window needs to be prepared or request is not from controller.
* Request will be delegated to controller and may or may not be shown.
*/
int IME_SHOW_DELAYED = 1;
/**
* Window will not be shown because one of the conditions couldn't be met.
* (e.g. in IME's case, when no editor is focused.)
*/
int IME_SHOW_FAILED = 2;
}
// 所属的InsetController
protected final InsetsController mController;
// 单一Insets的可见性
protected boolean mRequestedVisible;
// 本地state
protected final InsetsState mState;
// InsetsSource type
protected final @InternalInsetsType int mType;
private static final String TAG = "InsetsSourceConsumer";
private final Supplier<Transaction> mTransactionSupplier;
// 持有InsetsSourceControl变量可以实现对单一InsetsSource的控制
private @Nullable InsetsSourceControl mSourceControl;
private boolean mHasWindowFocus;
private Rect mPendingFrame;
private Rect mPendingVisibleFrame;
/**
* Indicates if we have the pending animation. When we have the control, we need to play the
* animation if the requested visibility is different from the current state. But if we haven't
* had a leash yet, we will set this flag, and play the animation once we get the leash.
*/
private boolean mIsAnimationPending;
public InsetsSourceConsumer(@InternalInsetsType int type, InsetsState state,
Supplier<Transaction> transactionSupplier, InsetsController controller) {
mType = type;
mState = state;
mTransactionSupplier = transactionSupplier;
mController = controller;
mRequestedVisible = getDefaultVisibility(type);
}
}
InsetsState
保存系统中所有的Insets的状态,他是状态描述者,持有系统中可以产生Window Insets的window状态;
当一个 Window 在客户端被添加、更新的时候,ViewRootImpl 将会调用 relayoutWindow 方法,从 WMS 获取当前 Window 的 InsetsState 信息;
public class InsetsState implements Parcelable {
public static final InsetsState EMPTY = new InsetsState();
/**
* Internal representation of inset source types. This is different from the public API in
* {@link WindowInsets.Type} as one type from the public API might indicate multiple windows
* at the same time.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "ITYPE", value = {
ITYPE_STATUS_BAR,
ITYPE_NAVIGATION_BAR,
ITYPE_CAPTION_BAR,
ITYPE_TOP_GESTURES,
ITYPE_BOTTOM_GESTURES,
ITYPE_LEFT_GESTURES,
ITYPE_RIGHT_GESTURES,
ITYPE_TOP_MANDATORY_GESTURES,
ITYPE_BOTTOM_MANDATORY_GESTURES,
ITYPE_LEFT_MANDATORY_GESTURES,
ITYPE_RIGHT_MANDATORY_GESTURES,
ITYPE_TOP_TAPPABLE_ELEMENT,
ITYPE_BOTTOM_TAPPABLE_ELEMENT,
ITYPE_LEFT_DISPLAY_CUTOUT,
ITYPE_TOP_DISPLAY_CUTOUT,
ITYPE_RIGHT_DISPLAY_CUTOUT,
ITYPE_BOTTOM_DISPLAY_CUTOUT,
ITYPE_IME,
ITYPE_CLIMATE_BAR,
ITYPE_EXTRA_NAVIGATION_BAR
})
public @interface InternalInsetsType {}
// 通过mSources集合来维护所有的Window Insets Info
// mSources变量维护所有产生Insets的window(也就是InsetsSource)的状态
private InsetsSource[] mSources = new InsetsSource[SIZE];
/**
* The frame of the display these sources are relative to.
*/
// 默认情况下是指整个显示屏幕,也就是屏幕的区域
private final Rect mDisplayFrame = new Rect();
public InsetsState() {
}
public InsetsState(InsetsState copy) {
set(copy);
}
public InsetsState(InsetsState copy, boolean copySources) {
set(copy, copySources);
}
……………………
public void set(InsetsState other) {
set(other, false /* copySources */);
}
public void set(InsetsState other, boolean copySources) {
mDisplayFrame.set(other.mDisplayFrame);
if (copySources) {
for (int i = 0; i < SIZE; i++) {
InsetsSource source = other.mSources[i];
mSources[i] = source != null ? new InsetsSource(source) : null;
}
} else {
for (int i = 0; i < SIZE; i++) {
mSources[i] = other.mSources[i];
}
}
}
}
InsetsState的核心方法:
- WindowInsets calculateInsets:基于当前InsetsSource设置计算新的WindowInsets;
- void processSource:根据计算值更新Source值;
InsetsStateController
管理所有窗口的Insets的state;
class InsetsStateController {
// 代表最后一次屏幕持有的所有类型的Insets状态信息
private final InsetsState mLastState = new InsetsState();
// 代表当前屏幕的所有类型的Insets状态信息
private final InsetsState mState = new InsetsState();
private final DisplayContent mDisplayContent;
// 用于维护InsetSource生产者的集合,后续DisplayContent、InsetsPolicy都是通过InsetsStateController中的mProviders集合来获取对应类型的InsetsSourceProvider来获取对应类型的InsetsSource实例
private final ArrayMap<Integer, InsetsSourceProvider> mProviders = new ArrayMap<>();
private final ArrayMap<InsetsControlTarget, ArrayList<Integer>> mControlTargetTypeMap =
new ArrayMap<>();
private final SparseArray<InsetsControlTarget> mTypeControlTargetMap = new SparseArray<>();
/** @see #onControlFakeTargetChanged */
private final SparseArray<InsetsControlTarget> mTypeFakeControlTargetMap = new SparseArray<>();
private final ArraySet<InsetsControlTarget> mPendingControlChanged = new ArraySet<>();
}
InsetsControlTarget是一个接口,代表了可以控制Insets状态的对象,WindowState实现了该接口,WindowState是每个Window在WMs的状态描述,所以每一个Window都具有控制Insets的能力;
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState,
InsetsControlTarget {
InsetsController
它是WindowInsets在client端的实现,用来控制Insets ,InsetsController只在ViewRootImpl里面创建的,每个Window会对应一个ViewRootImpl,同样每个ViewRootImpl会对应每个InsetsController;
public class InsetsController implements WindowInsetsController, InsetsAnimationControlCallbacks {
/** The local state */
// 记录本地State (Client端的Insetsstate)
private final InsetsState mState = new InsetsState();
/** The state dispatched from server */
// 从system端传来的InsetsState
private final InsetsState mLastDispatchedState = new InsetsState();
/** The state sent to server */
// 发送给系统端的InsetsState
private final InsetsState mRequestedState = new InsetsState();
private final Rect mFrame = new Rect();
private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator;
// 持有InsetsSourceConsumer
private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>();
private final Host mHost;
private final Handler mHandler;
private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>();
private final ArrayList<WindowInsetsAnimation> mTmpRunningAnims = new ArrayList<>();
private final List<WindowInsetsAnimation> mUnmodifiableTmpRunningAnims =
Collections.unmodifiableList(mTmpRunningAnims);
private final ArrayList<InsetsAnimationControlImpl> mTmpFinishedControls = new ArrayList<>();
private WindowInsets mLastInsets;
}
总结
InsetsState作为InsetsSource的存储集合,维护着insets信息的状态,InsetsState在Client和Server端都分别持有一组;
- Client InsetsState:在InsetsController中定义,用于存储本地的InsetsState,当本地InsetsState发生变更之后,会将其同步到mRequestedState的InsetsState中,这个InsetsState就是作为向Server发送变更后的InsetsState信息;
- Server InsetsState:在WindowState中定义,每一个ViewRootImpl基本对应一个WindowState,这个InsetsState记录的是Client请求变更的InsetsState;
- 每个ViewRootImpl对应一个InsetsController实例,他是一个App进程中控制Insets的核心类,用于保存传递系统中产生Insets的window的状态和动画需要的leash以及控制播放动画;
- InsetsSource是对产生Insets的窗口的状态描述,包括可见性以及Insets的大小;
- 每个InsetsController会持有一个成员变量mState(InsetsState),它保存了系统中所有产生Insets的Window(InsetsSource)的状态列表,状态主要是指可见性以及产生Insets的window的区域大小;
- InsetsSourceConsumer 是用来消费特定InsetsSource,消费主要是指对产生Insets 的window即InsetsSource进行可见性控制以及播放动画,通过持有的window的Leash来实现,也就是mSourceControl(InsetsSourceControl);
- 每个InsetsController会持有多个InsetsSourceConsumer,他持有一个InsetsSourceConsumers列表,SparseArray mSourceConsumers;