Recently, some contents related to Insets have always been involved in my work. However, there are few Insets analysis and introduction on the Internet. Here, SOME concepts and methods related to Insets are summarized.
What are Insets?
A series of interpolated sets of window content that an Activity needs to leave empty relative to the phone screen to make room for system Windows such as statusBar, Ime, Navigationbar, etc. Specifically, it refers to the width and height of the region. For example, the area of the input window is an Inset.
WindowInsets include SystemWindowInsets, StableInsets, and WIndowDecorInsets
- SystemWindowInsets: The area of a full window covered by navigationBar, StatusBar, IME, or other system Windows
- StableInsets: the area covered by the system UI in the full window
- WIndowDecorInsets: System reserved property
Insets related classes
InsetsState
Private InsetsSource[] mSources = new InsetsSource[SIZE]; private InsetsSource[] mSources = new InsetsSource[SIZE] The mSources variable maintains the state of all the Windows that generate the Insets
It mainly holds the following types of Insets
ITYPE_STATUS_BAR,
ITYPE_NAVIGATION_BAR,
ITYPE_CAPTION_BAR,
ITYPE_TOP_GESTURES,
ITYPE_BOTTOM_GESTURES,
ITYPE_LEFT_GESTURES,
ITYPE_RIGHT_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
Copy the code
If the InsetsState changes, the MSG_INSETS_CHANGED message is sent to the InsetsController, where the changes are made and saved to the variable mState
public boolean onStateChanged(InsetsState state) {
booleanstateChanged = ! mState.equals(state,true /* excludingCaptionInsets */.false /* excludeInvisibleIme */) | |! captionInsetsUnchanged();if(! stateChanged && mLastDispatchedState.equals(state)) {return false;
}
updateState(state);
booleanlocalStateChanged = ! mState.equals(mLastDispatchedState,true /* excludingCaptionInsets */.true /* excludeInvisibleIme */);
mLastDispatchedState.set(state, true /* copySources */);
applyLocalVisibilityOverride();
if (localStateChanged) {
if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged, send state to WM: " + mState);
mHost.notifyInsetsChanged();
updateRequestedState();
}
return true;
}
Copy the code
The key method for InsetsState:
CalculateInsets (...) : Computes new windowInsets based on the current source settingvoidProcessSource (InsetsSource,...) : Updates the source value based on the calculated valueCopy the code
InsetsStateController
Manages the state of the Insets of all Windows
private final InsetsState mLastState = new InsetsState(); / / the old InsetsState
private final InsetsState mState = new InsetsState(); / / new InsetsState
Copy the code
Several important methods:
private boolean isAboveIme(WindowContainer target) // Determines whether the current window is in the input window hierarchyvoid onImeControlTargetChanged(@Nullable InsetsControlTarget imeTarget) // Triggered when the input method target window changes
InsetsState getInsetsForDispatch(@NonNull WindowState target) // Distribute Insets to further update Insets (update frame or visible)
Copy the code
InsetsSource
Is the description of the Insets producer, which records the state of each window that generates Insets, mainly recording the generated Insets area
private final @InternalInsetsType int mType; //Insets类型 nav或者status或者...
private final Rect mFrame; // represents the Insets area
private boolean mVisible; / / Insets visibility
Copy the code
/* Several important methods /
public void setFrame(Rect frame) // Set the Insets size
public void setVisible(boolean visible) // Set the visibility of Insets
private Insets calculateInsets(Rect relativeFrame, Rect frame, boolean ignoreVisibility) // Compute Insets according to frame and ignoRevisionibility
Copy the code
InsetsSourceConsumer (ImeInsetsSourceConsumer)
If a consumer has a single InsetsSource, it has an InsetsSourceControl that can control its visibility and animation. The input method has a dedicated ImeInsetsSourceConsumer to consume the Insets of the input method
protected boolean mRequestedVisible; // Visibility of a single inset
private @Nullable InsetsSourceControl mSourceControl; // Hold the InsetsSourceControl variable to control a single InsetsSource
protected final InsetsController mController; // Owning InsetController
protected final InsetsState mState; / / the local state
Copy the code
/ Several important ways /
public void updateSource(InsetsSource newSource, @AnimationType int animationType) // Update source in mstate to update frame
public void show(boolean fromIme) / / show Insets
protected void setRequestedVisible(boolean requestedVisible) // Set the visibility of Insets
public void setControl(@Nullable InsetsSourceControl control,
@InsetsType int[] showTypes, @InsetsType int[] hideTypes) / / behind
public void hide(a) / / hide Insets
boolean applyLocalVisibilityOverride(a) // Update state visibility primarily
protected boolean isRequestedVisibleAwaitingControl(a) // Determine whether the current Insets update visibility when they get control, i.e. whether there is a pending show (equivalent to isRequestedVisible for bars)
Copy the code
ImeInsetsSourceConsumer
private boolean mIsRequestedVisibleAwaitingControl; // Determine if there is a request for the input method to display (but cannot do this because control is not currently available)
void notifyHidden(a) // Control IMM hidden input method
public @ShowResult int requestShow(boolean fromIme) // Control the IMM display input method
public void removeSurface(a) // Remove the input method surface- InsetsSourceControl Specifies the minleash that controls the InsetsSource. It is used to control the generation of Insets. Minleash internally holds a minleash animationprivate final @InternalInsetsType int mType; / / InsetsSource type
private final @Nullable SurfaceControl mLeash; Mindy, mindy, Mindy, Mindy, Mindy, Mindy, Mindy, Mindy, Mindy, Mindy, Mindy, Mindy, Mindy
private final Point mSurfacePosition; Mindy (mindy) mindy (mindy) mindy- InsetsSourceProvider Controls a specific InsetsSource on the server. It is called a provider because it provides InsetsSource to the client (the client uses InsetsSource through InsetsSourceConsumer)Copy the code
The focus here is on ImeInsetsSourceProvider
private InsetsControlTarget mImeTargetFromIme; // Insets need to have a control, otherwise they will get out of control.
private Runnable mShowImeRunner; // Displays the input method thread
private boolean mIsImeLayoutDrawn; // Whether the input method has been drawn
Copy the code
void scheduleShowImePostLayout(InsetsControlTarget imeTarget) // Start displaying input method Create an input method display thread
void checkShowImePostLayout(a) // Check whether the current input method meets the requirements. If so, run input method displays the thread
boolean isImeTargetFromDisplayContentAndImeSame(a) // Determine whether the target window of the input method meets the conditions for displaying the input method (including whether it is closing, whether it is consistent, etc.). The code of S is a little more complex and redundant than that of R
Copy the code
InsetsController
It’s the WindowInsets implementation on the client that controls the Insets. The InsetsController is only created in the View Windows PL, so each Window has a view Windows PL, Again, each view file will correspond to each InsetsController
/* Key member variable */
InsetsState mState = new InsetsState(); // Record local State (Client Insetsstate)
InsetsState mLastDispatchedState = new InsetsState(); // InsetsState from the system side
InsetsState mRequestedState = new InsetsState(); // Send to the system side InsetsState
SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>(); / / hold sourceConsumers
/* Key method */
public void applyImeVisibility(boolean setVisible) // Update input method visibility
public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) // The callback method when the animation ends
public void onControlsChanged(InsetsSourceControl[] activeControls) // called when the system side distributes new Insets Controls
public boolean onStateChanged(InsetsState state) //Insets or InsetsControl changes
public void setSystemBarsBehavior(@Behavior int behavior)
public void setSystemBarsAppearance(@Appearance int appearance, @Appearance int mask) // Change the behavior of Systembar
public void show(@InsetsType int types, boolean fromIme) / / show Insets
void hide(@InsetsType int types, boolean fromIme) / / hide Insets
private void updateState(InsetsState newState) / / update the state
private void updateRequestedState(a) // If the Insets change on the client side, they are re-sent to the server side
public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme) // Update the Insets animation
Copy the code
InsetsChanged, InsetsControlChanged methods
Insets changes are generally changed through the message mechanism. Two main changes are InsetsChanged and InsetsControlChanged, which are called by System_server to the App process through WindowState.
WindowState.java // Belongs to the Server
void notifyInsetsChanged(a) {
ProtoLog.d(WM_DEBUG_IME, "notifyInsetsChanged for %s ".this);
try {
mClient.insetsChanged(getInsetsState());
} catch (RemoteException e) {
Slog.w(TAG, "Failed to deliver inset state change w=" + this, e);
}
}
ViewRootImpl#W
@Override
public void insetsChanged(InsetsState insetsState) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if(viewAncestor ! =null) { viewAncestor.dispatchInsetsChanged(insetsState); }}@Override
public void insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if(viewAncestor ! =null) { viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls); }}Copy the code
Send messages asynchronously: MSG_INSETS_CHANGED, MSG_INSETS_CONTROL_CHANGED
case MSG_INSETS_CHANGED:
mInsetsController.onStateChanged((InsetsState) msg.obj);
break;
case MSG_INSETS_CONTROL_CHANGED: {
mInsetsController.onStateChanged((InsetsState) args.arg1);
mInsetsController.onControlsChanged((InsetsSourceControl[]) args.arg2);
break; // The onStateChanged method of InsetsController is called first
}
Copy the code
onStateChanged
public boolean onStateChanged(InsetsState state) {
booleanstateChanged = ! mState.equals(state,true /* excludingCaptionInsets */.false /* excludeInvisibleIme */) // Check whether the client state is consistent with the transmitted state| |! captionInsetsUnchanged();// Check whether the last state sent from the server is the same as the current state
if(! stateChanged && mLastDispatchedState.equals(state)) {return false;
}
if (DEBUG) Log.d(TAG, "onStateChanged: " + state);
updateState(state);
// Check whether the local state of the client has changed
booleanlocalStateChanged = ! mState.equals(mLastDispatchedState,true /* excludingCaptionInsets */.true /* excludeInvisibleIme */);
// Update mLastDispatchedState (mLastDispatchedState
mLastDispatchedState.set(state, true /* copySources */);
// Update apply locally
applyLocalVisibilityOverride();
if (localStateChanged) {
if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged, send state to WM: " + mState);
// If the local Insets have changed, notify the server that the Insets have changed
mHost.notifyInsetsChanged();
// Update the InsetsState passed to the server
updateRequestedState();
}
return true;
}
Copy the code
onControlsChanged
This method is also called when the window gains focus or loses focus
public void onControlsChanged(InsetsSourceControl[] activeControls) {
if(activeControls ! =null) {
for (InsetsSourceControl activeControl : activeControls) {
if(activeControl ! =null) {
// TODO(b/122982984): Figure out why it can be null.mTmpControlArray.put(activeControl.getType(), activeControl); }}}boolean requestedStateStale = false;
final int[] showTypes = new int[1]; // The system Insets will update visibility based on the values in the showTypes array
final int[] hideTypes = new int[1];
// Loop through all sourceconsumers to update InsetsSourceControl passed by system_server
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
final InsetsSourceControl control = mTmpControlArray.get(consumer.getType());
consumer.setControl(control, showTypes, hideTypes);
}
// Ensure to create source consumers if not available yet.
// facilitate InsetsSourceControl passed by system_server
for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
final InsetsSourceControl control = mTmpControlArray.valueAt(i);
final @InternalInsetsType int type = control.getType();
final InsetsSourceConsumer consumer = getSourceConsumer(type);
// If the consumer does not exist, it will be created
consumer.setControl(control, showTypes, hideTypes); // You can see that setControl is called twice if there is an authenticated consumer. } mTmpControlArray.clear();// The values of showTypes and hideTypes are changed in setControl
int animatingTypes = invokeControllableInsetsChangedListeners();
showTypes[0] &= ~animatingTypes;
hideTypes[0] &= ~animatingTypes;
// Suppose showTypes[0]=8 represents the input method to be displayed
if (showTypes[0] != 0) {
applyAnimation(showTypes[0].true /* show */.false /* fromIme */);
}
// Assume hideTypes[0]=8 to hide the input method
if (hideTypes[0] != 0) {
applyAnimation(hideTypes[0].false /* show */.false /* fromIme */);
}
if(requestedStateStale) { updateRequestedState(); }}Copy the code
conclusion
- Every ViewRootImpl corresponds to an instance of InsetsController. It is a core class that controls The Insets in the App process. It is used to save the state of the window that generates the Insets in the pass system and to control the animation and play the animation
- InsetsSource is a state description of the window that generated the Insets, including visibility and size of the Insets
- Each InsetsController holds a member variable mState (InsetsState), which holds a list of the states of all the Windows (InsetsSource) that generate Insets in the system. State refers primarily to visibility and the size of the area of the window that generated the Insets
- Specific InsetsSource InsetsSourceConsumer is used for consumption, consumption is mainly refers to the window that is to produce Insets InsetsSource control the visibility and the animation, through the window of holdings Leash, So mSourceControl, InsetsSourceControl
- Each InsetsController holds multiple InsetsSourceConsumers. It holds a list of InsetsSourceConsumers, SparseArray mSourceConsumers
Insets has been summarized here, and the principle of Insets and its relationship with App will be further analyzed through source code in the follow-up. Due to the limited level, there will inevitably be errors. If you find improper or wrong places in reading, please comment and correct them, and make common progress.
Have a nice day!