summaryrefslogtreecommitdiff
path: root/core/java/android/view/ViewRootImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/view/ViewRootImpl.java')
-rw-r--r--core/java/android/view/ViewRootImpl.java1685
1 files changed, 1174 insertions, 511 deletions
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1ab3d3ab4974..7453f21d379b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -18,13 +18,45 @@ package android.view;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.InputDevice.SOURCE_CLASS_NONE;
+import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
+import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.SIZE;
import static android.view.View.PFLAG_DRAW_ANIMATION;
+import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE;
+import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import android.Manifest;
@@ -45,10 +77,12 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.BLASTBufferQueue;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.FrameInfo;
import android.graphics.HardwareRenderer.FrameDrawingCallback;
+import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Point;
@@ -68,6 +102,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -76,6 +111,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
+import android.os.UserHandle;
import android.sysprop.DisplayProperties;
import android.util.AndroidRuntimeException;
import android.util.DisplayMetrics;
@@ -86,11 +122,17 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.TypedValue;
+import android.view.InputDevice.InputSourceClass;
+import android.view.InsetsState.InternalInsetsType;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl.Transaction;
import android.view.View.AttachInfo;
import android.view.View.FocusDirection;
import android.view.View.MeasureSpec;
+import android.view.Window.OnContentApplyWindowInsetsListener;
+import android.view.WindowInsets.Type;
+import android.view.WindowInsets.Type.InsetsType;
+import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -101,6 +143,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.accessibility.IAccessibilityEmbeddedConnection;
import android.view.accessibility.IAccessibilityInteractionConnection;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import android.view.animation.AccelerateDecelerateInterpolator;
@@ -115,8 +158,10 @@ import android.widget.Scroller;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.SomeArgs;
+import com.android.internal.policy.DecorView;
import com.android.internal.policy.PhoneFallbackEventHandler;
import com.android.internal.util.Preconditions;
import com.android.internal.view.BaseSurfaceHolder;
@@ -161,6 +206,7 @@ public final class ViewRootImpl implements ViewParent,
private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
private static final boolean DEBUG_CONTENT_CAPTURE = false || LOCAL_LOGV;
+ private static final boolean DEBUG_SCROLL_CAPTURE = false || LOCAL_LOGV;
/**
* Set to false if we do not want to use the multi threaded renderer even though
@@ -181,32 +227,32 @@ public final class ViewRootImpl implements ViewParent,
* If set to 1, this will switch to a mode where we only use the new approach for IME, but not
* for the status/navigation bar.
*/
- private static final String USE_NEW_INSETS_PROPERTY = "persist.wm.new_insets";
+ private static final String USE_NEW_INSETS_PROPERTY = "persist.debug.new_insets";
/**
* @see #USE_NEW_INSETS_PROPERTY
* @hide
*/
- public static int sNewInsetsMode =
- SystemProperties.getInt(USE_NEW_INSETS_PROPERTY, 0);
+ public static final int NEW_INSETS_MODE_NONE = 0;
/**
* @see #USE_NEW_INSETS_PROPERTY
* @hide
*/
- public static final int NEW_INSETS_MODE_NONE = 0;
+ public static final int NEW_INSETS_MODE_IME = 1;
/**
* @see #USE_NEW_INSETS_PROPERTY
* @hide
*/
- public static final int NEW_INSETS_MODE_IME = 1;
+ public static final int NEW_INSETS_MODE_FULL = 2;
/**
* @see #USE_NEW_INSETS_PROPERTY
* @hide
*/
- public static final int NEW_INSETS_MODE_FULL = 2;
+ public static int sNewInsetsMode =
+ SystemProperties.getInt(USE_NEW_INSETS_PROPERTY, NEW_INSETS_MODE_FULL);
/**
* Set this system property to true to force the view hierarchy to render
@@ -214,10 +260,6 @@ public final class ViewRootImpl implements ViewParent,
*/
private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
- // properties used by emulator to determine display shape
- public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
- "ro.emu.win_outset_bottom_px";
-
/**
* Maximum time we allow the user to roll the trackball enough to generate
* a key event, before resetting the counters.
@@ -284,6 +326,10 @@ public final class ViewRootImpl implements ViewParent,
*/
private boolean mForceNextConfigUpdate;
+ private boolean mUseBLASTAdapter;
+ private boolean mForceDisableBLAST;
+ private boolean mEnableTripleBuffering;
+
/**
* Signals that compatibility booleans have been initialized according to
* target SDK versions.
@@ -322,6 +368,8 @@ public final class ViewRootImpl implements ViewParent,
final W mWindow;
+ final IBinder mLeashToken;
+
final int mTargetSdkVersion;
int mSeq;
@@ -399,12 +447,18 @@ public final class ViewRootImpl implements ViewParent,
@UnsupportedAppUsage
final View.AttachInfo mAttachInfo;
- InputChannel mInputChannel;
+ final SystemUiVisibilityInfo mCompatibleVisibilityInfo;
+ int mDispatchedSystemUiVisibility =
+ ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL ? 0 : -1;
InputQueue.Callback mInputQueueCallback;
InputQueue mInputQueue;
@UnsupportedAppUsage
FallbackEventHandler mFallbackEventHandler;
- Choreographer mChoreographer;
+ final Choreographer mChoreographer;
+
+ // used in relayout to get SurfaceControl size
+ // for BLAST adapter surface setup
+ private final Point mSurfaceSize = new Point();
final Rect mTempRect; // used in the transaction to not thrash the heap.
final Rect mVisRect; // used to retrieve visible rect of focused view.
@@ -436,15 +490,12 @@ public final class ViewRootImpl implements ViewParent,
boolean mReportNextDraw;
boolean mFullRedrawNeeded;
boolean mNewSurfaceNeeded;
- boolean mHasHadWindowFocus;
- boolean mLastWasImTarget;
boolean mForceNextWindowRelayout;
CountDownLatch mWindowDrawCountDown;
boolean mIsDrawing;
int mLastSystemUiVisibility;
int mClientWindowLayoutFlags;
- boolean mLastOverscanRequested;
// Pool of queued input events.
private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
@@ -460,6 +511,9 @@ public final class ViewRootImpl implements ViewParent,
int mPendingInputEventCount;
boolean mProcessInputEventsScheduled;
boolean mUnbufferedInputDispatch;
+ @InputSourceClass
+ int mUnbufferedInputSource = SOURCE_CLASS_NONE;
+
String mPendingInputEventQueueLengthCounterName = "pq";
InputStage mFirstInputStage;
@@ -469,24 +523,30 @@ public final class ViewRootImpl implements ViewParent,
private final UnhandledKeyManager mUnhandledKeyManager = new UnhandledKeyManager();
boolean mWindowAttributesChanged = false;
- int mWindowAttributesChangesFlag = 0;
// These can be accessed by any thread, must be protected with a lock.
// Surface can never be reassigned or cleared (use Surface.clear()).
@UnsupportedAppUsage
public final Surface mSurface = new Surface();
private final SurfaceControl mSurfaceControl = new SurfaceControl();
+ private SurfaceControl mBlastSurfaceControl = new SurfaceControl();
+
+ private BLASTBufferQueue mBlastBufferQueue;
/**
- * Child surface of {@code mSurface} with the same bounds as its parent, and crop bounds
- * are set to the parent's bounds adjusted for surface insets. This surface is created when
- * {@link ViewRootImpl#createBoundsSurface(int)} is called.
- * By parenting to this bounds surface, child surfaces can ensure they do not draw into the
- * surface inset regions set by the parent window.
+ * Transaction object that can be used to synchronize child SurfaceControl changes with
+ * ViewRootImpl SurfaceControl changes by the server. The object is passed along with
+ * the SurfaceChangedCallback.
+ */
+ private final Transaction mSurfaceChangedTransaction = new Transaction();
+ /**
+ * Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to
+ * the surface insets. This surface is created only if a client requests it via {@link
+ * #getBoundsLayer()}. By parenting to this bounds surface, child surfaces can ensure they do
+ * not draw into the surface inset region set by the parent window.
*/
- public final Surface mBoundsSurface = new Surface();
- private SurfaceSession mSurfaceSession;
- private SurfaceControl mBoundsSurfaceControl;
+ private SurfaceControl mBoundsLayer;
+ private final SurfaceSession mSurfaceSession = new SurfaceSession();
private final Transaction mTransaction = new Transaction();
@UnsupportedAppUsage
@@ -494,29 +554,25 @@ public final class ViewRootImpl implements ViewParent,
boolean mAddedTouchMode;
final Rect mTmpFrame = new Rect();
+ final Rect mTmpRect = new Rect();
// These are accessed by multiple threads.
final Rect mWinFrame; // frame given by window manager.
- final Rect mPendingOverscanInsets = new Rect();
- final Rect mPendingVisibleInsets = new Rect();
- final Rect mPendingStableInsets = new Rect();
- final Rect mPendingContentInsets = new Rect();
- final Rect mPendingOutsets = new Rect();
final Rect mPendingBackDropFrame = new Rect();
final DisplayCutout.ParcelableWrapper mPendingDisplayCutout =
new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
boolean mPendingAlwaysConsumeSystemBars;
- private InsetsState mTempInsets = new InsetsState();
+ private final InsetsState mTempInsets = new InsetsState();
+ private final InsetsSourceControl[] mTempControls = new InsetsSourceControl[SIZE];
final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
= new ViewTreeObserver.InternalInsetsInfo();
- final Rect mDispatchContentInsets = new Rect();
- final Rect mDispatchStableInsets = new Rect();
- DisplayCutout mDispatchDisplayCutout = DisplayCutout.NO_CUTOUT;
-
private WindowInsets mLastWindowInsets;
+ // Insets types hidden by legacy window flags or system UI flags.
+ private @InsetsType int mTypesHiddenByFlags = 0;
+
/** Last applied configuration obtained from resources. */
private final Configuration mLastConfigurationFromResources = new Configuration();
/** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */
@@ -597,10 +653,29 @@ public final class ViewRootImpl implements ViewParent,
InputEventConsistencyVerifier.isInstrumentationEnabled() ?
new InputEventConsistencyVerifier(this, 0) : null;
- private final InsetsController mInsetsController = new InsetsController(this);
+ private final InsetsController mInsetsController;
+ private final ImeFocusController mImeFocusController;
+
+ private ScrollCaptureClient mScrollCaptureClient;
+
+ /**
+ * @return {@link ImeFocusController} for this instance.
+ */
+ @NonNull
+ public ImeFocusController getImeFocusController() {
+ return mImeFocusController;
+ }
+
+ /** @return The current {@link ScrollCaptureClient} for this instance, if any is active. */
+ @Nullable
+ public ScrollCaptureClient getScrollCaptureClient() {
+ return mScrollCaptureClient;
+ }
private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker();
+ private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
+
static final class SystemUiVisibilityInfo {
int seq;
int globalVisibility;
@@ -608,11 +683,49 @@ public final class ViewRootImpl implements ViewParent,
int localChanges;
}
+ // If set, ViewRootImpl will call BLASTBufferQueue::setNextTransaction with
+ // mRtBLASTSyncTransaction, prior to invoking draw. This provides a way
+ // to redirect the buffers in to transactions.
+ private boolean mNextDrawUseBLASTSyncTransaction;
+ // Set when calling setNextTransaction, we can't just reuse mNextDrawUseBLASTSyncTransaction
+ // because, imagine this scenario:
+ // 1. First draw is using BLAST, mNextDrawUseBLAST = true
+ // 2. We call perform draw and are waiting on the callback
+ // 3. After the first perform draw but before the first callback and the
+ // second perform draw, a second draw sets mNextDrawUseBLAST = true (it already was)
+ // 4. At this point the callback fires and we set mNextDrawUseBLAST = false;
+ // 5. We get to performDraw and fail to sync as we intended because mNextDrawUseBLAST
+ // is now false.
+ // This is why we use a two-step latch with the two booleans, one consumed from
+ // performDraw and one consumed from finishBLASTSync()
+ private boolean mNextReportConsumeBLAST;
+ // Be very careful with the threading here. This is used from the render thread while
+ // the UI thread is paused and then applied and cleared from the UI thread right after
+ // draw returns.
+ private SurfaceControl.Transaction mRtBLASTSyncTransaction = new SurfaceControl.Transaction();
+
+ // Keeps track of whether the WM requested us to use BLAST Sync when calling relayout.
+ // We use this to make sure we don't send the WM transactions from an internal BLAST sync
+ // (e.g. SurfaceView)
+ private boolean mSendNextFrameToWm = false;
+
+ private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
+
private String mTag = TAG;
public ViewRootImpl(Context context, Display display) {
+ this(context, display, WindowManagerGlobal.getWindowSession(),
+ false /* useSfChoreographer */);
+ }
+
+ public ViewRootImpl(Context context, Display display, IWindowSession session) {
+ this(context, display, session, false /* useSfChoreographer */);
+ }
+
+ public ViewRootImpl(Context context, Display display, IWindowSession session,
+ boolean useSfChoreographer) {
mContext = context;
- mWindowSession = WindowManagerGlobal.getWindowSession();
+ mWindowSession = session;
mDisplay = display;
mBasePackageName = context.getBasePackageName();
mThread = Thread.currentThread();
@@ -625,6 +738,7 @@ public final class ViewRootImpl implements ViewParent,
mVisRect = new Rect();
mWinFrame = new Rect();
mWindow = new W(this);
+ mLeashToken = new Binder();
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
mViewVisibility = View.GONE;
mTransparentRegion = new Region();
@@ -634,6 +748,7 @@ public final class ViewRootImpl implements ViewParent,
mAdded = false;
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
context);
+ mCompatibleVisibilityInfo = new SystemUiVisibilityInfo();
mAccessibilityManager = AccessibilityManager.getInstance(context);
mAccessibilityManager.addAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager, mHandler);
@@ -644,8 +759,10 @@ public final class ViewRootImpl implements ViewParent,
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
mFallbackEventHandler = new PhoneFallbackEventHandler(context);
- mChoreographer = Choreographer.getInstance();
+ mChoreographer = useSfChoreographer
+ ? Choreographer.getSfInstance() : Choreographer.getInstance();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
+ mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this));
String processorOverrideName = context.getResources().getString(
R.string.config_inputEventCompatProcessorOverrideClassName);
@@ -673,6 +790,7 @@ public final class ViewRootImpl implements ViewParent,
}
loadSystemProperties();
+ mImeFocusController = new ImeFocusController(this);
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -696,6 +814,16 @@ public final class ViewRootImpl implements ViewParent,
mActivityConfigCallback = callback;
}
+ public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) {
+ mAttachInfo.mContentOnApplyWindowInsetsListener = listener;
+
+ // System windows will be fitted on first traversal, so no reason to request additional
+ // (possibly getting executed after the first traversal).
+ if (!mFirst) {
+ requestFitSystemWindows();
+ }
+ }
+
public void addWindowCallbacks(WindowCallbacks callback) {
synchronized (mWindowCallbacks) {
mWindowCallbacks.add(callback);
@@ -782,6 +910,14 @@ public final class ViewRootImpl implements ViewParent,
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
+ setView(view, attrs, panelParentView, UserHandle.myUserId());
+ }
+
+ /**
+ * We have one child
+ */
+ public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
+ int userId) {
synchronized (this) {
if (mView == null) {
mView = view;
@@ -795,6 +931,9 @@ public final class ViewRootImpl implements ViewParent,
if (mWindowAttributes.packageName == null) {
mWindowAttributes.packageName = mBasePackageName;
}
+ mWindowAttributes.privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
+
attrs = mWindowAttributes;
setTag();
@@ -859,7 +998,6 @@ public final class ViewRootImpl implements ViewParent,
mSoftInputMode = attrs.softInputMode;
mWindowAttributesChanged = true;
- mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
mAttachInfo.mRootView = view;
mAttachInfo.mScalingRequired = mTranslator != null;
mAttachInfo.mApplicationScale =
@@ -875,9 +1013,10 @@ public final class ViewRootImpl implements ViewParent,
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
+ InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
- mInputChannel = new InputChannel();
+ inputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
@@ -885,17 +1024,18 @@ public final class ViewRootImpl implements ViewParent,
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
- res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
- getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
+ adjustLayoutParamsForCompatibility(mWindowAttributes);
+ res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
+ getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
- mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
- mTempInsets);
+ mAttachInfo.mDisplayCutout, inputChannel,
+ mTempInsets, mTempControls);
setFrame(mTmpFrame);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
- mInputChannel = null;
+ inputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
@@ -909,15 +1049,12 @@ public final class ViewRootImpl implements ViewParent,
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
}
- mPendingOverscanInsets.set(0, 0, 0, 0);
- mPendingContentInsets.set(mAttachInfo.mContentInsets);
- mPendingStableInsets.set(mAttachInfo.mStableInsets);
mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
- mPendingVisibleInsets.set(0, 0, 0, 0);
mAttachInfo.mAlwaysConsumeSystemBars =
(res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) != 0;
mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars;
mInsetsController.onStateChanged(mTempInsets);
+ mInsetsController.onControlsChanged(mTempControls);
if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
if (res < WindowManagerGlobal.ADD_OKAY) {
mAttachInfo.mRootView = null;
@@ -962,21 +1099,31 @@ public final class ViewRootImpl implements ViewParent,
throw new WindowManager.InvalidDisplayException("Unable to add window "
+ mWindow + " -- the specified window type "
+ mWindowAttributes.type + " is not valid");
+ case WindowManagerGlobal.ADD_INVALID_USER:
+ throw new WindowManager.BadTokenException("Unable to add Window "
+ + mWindow + " -- requested userId is not valid");
}
throw new RuntimeException(
"Unable to add window -- unknown error code " + res);
}
+ if ((res & WindowManagerGlobal.ADD_FLAG_USE_BLAST) != 0) {
+ mUseBLASTAdapter = true;
+ }
+ if ((res & WindowManagerGlobal.ADD_FLAG_USE_TRIPLE_BUFFERING) != 0) {
+ mEnableTripleBuffering = true;
+ }
+
if (view instanceof RootViewSurfaceTaker) {
mInputQueueCallback =
((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
}
- if (mInputChannel != null) {
+ if (inputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
- mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
+ mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
Looper.myLooper());
}
@@ -1008,6 +1155,14 @@ public final class ViewRootImpl implements ViewParent,
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
+
+ if (mView instanceof RootViewSurfaceTaker) {
+ PendingInsetsController pendingInsetsController =
+ ((RootViewSurfaceTaker) mView).providePendingInsetsController();
+ if (pendingInsetsController != null) {
+ pendingInsetsController.replayAndAttach(mInsetsController);
+ }
+ }
}
}
}
@@ -1019,11 +1174,6 @@ public final class ViewRootImpl implements ViewParent,
}
}
- /** Whether the window is in local focus mode or not */
- private boolean isInLocalFocusMode() {
- return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
- }
-
@UnsupportedAppUsage
public int getWindowFlags() {
return mWindowAttributes.flags;
@@ -1262,14 +1412,12 @@ public final class ViewRootImpl implements ViewParent,
attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
- mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
- if ((mWindowAttributesChangesFlag
- & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
+ final int changes = mWindowAttributes.copyFrom(attrs);
+ if ((changes & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
// Recompute system ui visibility.
mAttachInfo.mRecomputeGlobalAttributes = true;
}
- if ((mWindowAttributesChangesFlag
- & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
+ if ((changes & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
// Request to update light center.
mAttachInfo.mNeedsUpdateLightCenter = true;
}
@@ -1278,6 +1426,9 @@ public final class ViewRootImpl implements ViewParent,
}
mWindowAttributes.privateFlags |= compatibleWindowFlag;
+ mWindowAttributes.privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
+
if (mWindowAttributes.preservePreviousSurfaceInsets) {
// Restore old surface insets.
mWindowAttributes.surfaceInsets.set(
@@ -1305,6 +1456,10 @@ public final class ViewRootImpl implements ViewParent,
| (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
}
+ if ((changes & LayoutParams.SOFT_INPUT_MODE_CHANGED) != 0) {
+ requestFitSystemWindows();
+ }
+
mWindowAttributesChanged = true;
scheduleTraversals();
}
@@ -1381,6 +1536,7 @@ public final class ViewRootImpl implements ViewParent,
// Get new instance of display based on current display adjustments. It may be updated later
// if moving between the displays also involved a configuration change.
updateInternalDisplay(displayId, mView.getResources());
+ mImeFocusController.onMovedToDisplay();
mAttachInfo.mDisplayState = mDisplay.getState();
// Internal state updated, now notify the view hierarchy.
mView.dispatchMovedToDisplay(mDisplay, config);
@@ -1430,6 +1586,12 @@ public final class ViewRootImpl implements ViewParent,
return;
}
mApplyInsetsRequested = true;
+ requestLayout();
+
+ // See comment for View.sForceLayoutWhenInsetsChanged
+ if (View.sForceLayoutWhenInsetsChanged && mView != null) {
+ forceLayout(mView);
+ }
// If this changes during traversal, no need to schedule another one as it will dispatch it
// during the current traversal.
@@ -1538,19 +1700,6 @@ public final class ViewRootImpl implements ViewParent,
mIsAmbientMode = ambient;
}
- interface WindowStoppedCallback {
- public void windowStopped(boolean stopped);
- }
- private final ArrayList<WindowStoppedCallback> mWindowStoppedCallbacks = new ArrayList<>();
-
- void addWindowStoppedCallback(WindowStoppedCallback c) {
- mWindowStoppedCallbacks.add(c);
- }
-
- void removeWindowStoppedCallback(WindowStoppedCallback c) {
- mWindowStoppedCallbacks.remove(c);
- }
-
void setWindowStopped(boolean stopped) {
checkThread();
if (mStopped != stopped) {
@@ -1567,80 +1716,141 @@ public final class ViewRootImpl implements ViewParent,
if (renderer != null) {
renderer.destroyHardwareResources(mView);
}
- }
- for (int i = 0; i < mWindowStoppedCallbacks.size(); i++) {
- mWindowStoppedCallbacks.get(i).windowStopped(stopped);
- }
-
- if (mStopped) {
- if (mSurfaceHolder != null && mSurface.isValid()) {
+ if (mSurface.isValid()) {
+ if (mSurfaceHolder != null) {
+ notifyHolderSurfaceDestroyed();
+ }
notifySurfaceDestroyed();
}
destroySurface();
}
}
+ scheduleConsumeBatchedInputImmediately();
+ }
+
+
+ /** Register callbacks to be notified when the ViewRootImpl surface changes. */
+ interface SurfaceChangedCallback {
+ void surfaceCreated(Transaction t);
+ void surfaceReplaced(Transaction t);
+ void surfaceDestroyed();
+ }
+
+ private final ArrayList<SurfaceChangedCallback> mSurfaceChangedCallbacks = new ArrayList<>();
+ void addSurfaceChangedCallback(SurfaceChangedCallback c) {
+ mSurfaceChangedCallbacks.add(c);
+ }
+
+ void removeSurfaceChangedCallback(SurfaceChangedCallback c) {
+ mSurfaceChangedCallbacks.remove(c);
+ }
+
+ private void notifySurfaceCreated() {
+ for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
+ mSurfaceChangedCallbacks.get(i).surfaceCreated(mSurfaceChangedTransaction);
+ }
}
/**
- * Creates a surface as a child of {@code mSurface} with the same bounds as its parent and
- * crop bounds set to the parent's bounds adjusted for surface insets.
- *
- * @param zOrderLayer Z order relative to the parent surface.
+ * Notify listeners when the ViewRootImpl surface has been replaced. This callback will not be
+ * called if a new surface is created, only if the valid surface has been replaced with another
+ * valid surface.
*/
- public void createBoundsSurface(int zOrderLayer) {
- if (mSurfaceSession == null) {
- mSurfaceSession = new SurfaceSession();
+ private void notifySurfaceReplaced() {
+ for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
+ mSurfaceChangedCallbacks.get(i).surfaceReplaced(mSurfaceChangedTransaction);
}
- if (mBoundsSurfaceControl != null && mBoundsSurface.isValid()) {
- return; // surface control for bounds surface already exists.
+ }
+
+ private void notifySurfaceDestroyed() {
+ for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
+ mSurfaceChangedCallbacks.get(i).surfaceDestroyed();
}
+ }
- mBoundsSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
- .setName("Bounds for - " + getTitle().toString())
- .setParent(mSurfaceControl)
- .build();
+ /**
+ * @return child layer with the same bounds as its parent {@code mSurface} and cropped to the
+ * surface insets. If the layer does not exist, it is created.
+ *
+ * <p>Parenting to this layer will ensure that its children are cropped by the view's surface
+ * insets.
+ */
+ public SurfaceControl getBoundsLayer() {
+ if (mBoundsLayer == null) {
+ mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession)
+ .setContainerLayer()
+ .setName("Bounds for - " + getTitle().toString())
+ .setParent(getRenderSurfaceControl())
+ .setCallsite("ViewRootImpl.getBoundsLayer")
+ .build();
+ setBoundsLayerCrop();
+ mTransaction.show(mBoundsLayer).apply();
+ }
+ return mBoundsLayer;
+ }
+
+ Surface getOrCreateBLASTSurface(int width, int height) {
+ if (mSurfaceControl == null
+ || !mSurfaceControl.isValid()
+ || mBlastSurfaceControl == null
+ || !mBlastSurfaceControl.isValid()) {
+ return null;
+ }
- setBoundsSurfaceCrop();
- mTransaction.setLayer(mBoundsSurfaceControl, zOrderLayer)
- .show(mBoundsSurfaceControl)
- .apply();
- mBoundsSurface.copyFrom(mBoundsSurfaceControl);
+ Surface ret = null;
+ if (mBlastBufferQueue == null) {
+ mBlastBufferQueue = new BLASTBufferQueue(
+ mBlastSurfaceControl, width, height, mEnableTripleBuffering);
+ // We only return the Surface the first time, as otherwise
+ // it hasn't changed and there is no need to update.
+ ret = mBlastBufferQueue.getSurface();
+ } else {
+ mBlastBufferQueue.update(mBlastSurfaceControl, width, height);
+ }
+
+ return ret;
}
- private void setBoundsSurfaceCrop() {
+ private void setBoundsLayerCrop() {
// mWinFrame is already adjusted for surface insets. So offset it and use it as
// the cropping bounds.
mTempBoundsRect.set(mWinFrame);
mTempBoundsRect.offsetTo(mWindowAttributes.surfaceInsets.left,
mWindowAttributes.surfaceInsets.top);
- mTransaction.setWindowCrop(mBoundsSurfaceControl, mTempBoundsRect);
+ mTransaction.setWindowCrop(mBoundsLayer, mTempBoundsRect);
}
/**
- * Called after window layout to update the bounds surface. If the surface insets have
- * changed or the surface has resized, update the bounds surface.
+ * Called after window layout to update the bounds surface. If the surface insets have changed
+ * or the surface has resized, update the bounds surface.
+ *
+ * @param shouldReparent Whether it should reparent the bounds layer to the main SurfaceControl.
*/
- private void updateBoundsSurface() {
- if (mBoundsSurfaceControl != null && mSurface.isValid()) {
- setBoundsSurfaceCrop();
- mTransaction.deferTransactionUntilSurface(mBoundsSurfaceControl,
- mSurface, mSurface.getNextFrameNumber())
- .apply();
+ private void updateBoundsLayer(boolean shouldReparent) {
+ if (mBoundsLayer != null) {
+ setBoundsLayerCrop();
+ mTransaction.deferTransactionUntil(mBoundsLayer, getRenderSurfaceControl(),
+ mSurface.getNextFrameNumber());
+
+ if (shouldReparent) {
+ mTransaction.reparent(mBoundsLayer, getRenderSurfaceControl());
+ }
+ mTransaction.apply();
}
}
private void destroySurface() {
+ if (mBoundsLayer != null) {
+ mBoundsLayer.release();
+ mBoundsLayer = null;
+ }
mSurface.release();
mSurfaceControl.release();
- mSurfaceSession = null;
-
- if (mBoundsSurfaceControl != null) {
- mTransaction.remove(mBoundsSurfaceControl).apply();
- mBoundsSurface.release();
- mBoundsSurfaceControl = null;
- }
+ mBlastSurfaceControl.release();
+ // We should probably add an explicit dispose.
+ mBlastBufferQueue = null;
}
/**
@@ -1716,9 +1926,6 @@ public final class ViewRootImpl implements ViewParent,
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
- if (!mUnbufferedInputDispatch) {
- scheduleConsumeBatchedInput();
- }
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
@@ -1775,6 +1982,14 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
WindowManager.LayoutParams params = mWindowAttributes;
mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
+ mCompatibleVisibilityInfo.globalVisibility =
+ (mCompatibleVisibilityInfo.globalVisibility & ~View.SYSTEM_UI_FLAG_LOW_PROFILE)
+ | (mAttachInfo.mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ if (mDispatchedSystemUiVisibility != mCompatibleVisibilityInfo.globalVisibility) {
+ mHandler.removeMessages(MSG_DISPATCH_SYSTEM_UI_VISIBILITY);
+ mHandler.sendMessage(mHandler.obtainMessage(
+ MSG_DISPATCH_SYSTEM_UI_VISIBILITY, mCompatibleVisibilityInfo));
+ }
if (mAttachInfo.mKeepScreenOn != oldScreenOn
|| mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
|| mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
@@ -1791,15 +2006,171 @@ public final class ViewRootImpl implements ViewParent,
private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
int vis = 0;
// Translucent decor window flags imply stable system ui visibility.
- if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
+ if ((params.flags & FLAG_TRANSLUCENT_STATUS) != 0) {
vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
}
- if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
+ if ((params.flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) {
vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
}
return vis;
}
+ /**
+ * Update the compatible system UI visibility for dispatching it to the legacy app.
+ *
+ * @param type Indicates which type of the insets source we are handling.
+ * @param visible True if the insets source is visible.
+ * @param hasControl True if we can control the insets source.
+ */
+ void updateCompatSysUiVisibility(@InternalInsetsType int type, boolean visible,
+ boolean hasControl) {
+ if ((type != ITYPE_STATUS_BAR && type != ITYPE_NAVIGATION_BAR)
+ || ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) {
+ return;
+ }
+ final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo;
+ final int systemUiFlag = type == ITYPE_STATUS_BAR
+ ? View.SYSTEM_UI_FLAG_FULLSCREEN
+ : View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+ final boolean wasVisible = (info.globalVisibility & systemUiFlag) == 0;
+ if (visible) {
+ info.globalVisibility &= ~systemUiFlag;
+ if (!wasVisible && hasControl) {
+ // The local system UI visibility can only be cleared while we have the control.
+ info.localChanges |= systemUiFlag;
+ }
+ } else {
+ info.globalVisibility |= systemUiFlag;
+ info.localChanges &= ~systemUiFlag;
+ }
+ if (mDispatchedSystemUiVisibility != info.globalVisibility) {
+ mHandler.removeMessages(MSG_DISPATCH_SYSTEM_UI_VISIBILITY);
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, info));
+ }
+ }
+
+ private void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
+ if (mSeq != args.seq && sNewInsetsMode != NEW_INSETS_MODE_FULL) {
+ // The sequence has changed, so we need to update our value and make
+ // sure to do a traversal afterward so the window manager is given our
+ // most recent data.
+ mSeq = args.seq;
+ mAttachInfo.mForceReportNewAttributes = true;
+ scheduleTraversals();
+ }
+ if (mView == null) return;
+ if (args.localChanges != 0) {
+ mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
+ args.localChanges = 0;
+ }
+
+ final int visibility = args.globalVisibility & View.SYSTEM_UI_CLEARABLE_FLAGS;
+ if (mDispatchedSystemUiVisibility != visibility) {
+ mDispatchedSystemUiVisibility = visibility;
+ mView.dispatchSystemUiVisibilityChanged(visibility);
+ }
+ }
+
+ @VisibleForTesting
+ public static void adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams) {
+ if (sNewInsetsMode != NEW_INSETS_MODE_FULL) {
+ return;
+ }
+ final int sysUiVis = inOutParams.systemUiVisibility | inOutParams.subtreeSystemUiVisibility;
+ final int flags = inOutParams.flags;
+ final int type = inOutParams.type;
+
+ if ((inOutParams.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) {
+ inOutParams.insetsFlags.appearance = 0;
+ if ((sysUiVis & SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
+ inOutParams.insetsFlags.appearance |= APPEARANCE_LOW_PROFILE_BARS;
+ }
+ if ((sysUiVis & SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0) {
+ inOutParams.insetsFlags.appearance |= APPEARANCE_LIGHT_STATUS_BARS;
+ }
+ if ((sysUiVis & SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0) {
+ inOutParams.insetsFlags.appearance |= APPEARANCE_LIGHT_NAVIGATION_BARS;
+ }
+ }
+
+ if ((inOutParams.privateFlags & PRIVATE_FLAG_BEHAVIOR_CONTROLLED) == 0) {
+ if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0
+ || (flags & FLAG_FULLSCREEN) != 0) {
+ inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+ } else if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE) != 0) {
+ inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_BARS_BY_SWIPE;
+ } else {
+ inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_BARS_BY_TOUCH;
+ }
+ }
+
+ if ((inOutParams.privateFlags & PRIVATE_FLAG_FIT_INSETS_CONTROLLED) != 0) {
+ return;
+ }
+
+ int types = inOutParams.getFitInsetsTypes();
+ int sides = inOutParams.getFitInsetsSides();
+ boolean ignoreVis = inOutParams.isFitInsetsIgnoringVisibility();
+
+ if (((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0
+ || (flags & FLAG_LAYOUT_IN_SCREEN) != 0)
+ || (flags & FLAG_TRANSLUCENT_STATUS) != 0) {
+ types &= ~Type.statusBars();
+ }
+ if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+ || (flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) {
+ types &= ~Type.systemBars();
+ }
+ if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
+ ignoreVis = true;
+ } else if ((types & Type.systemBars()) == Type.systemBars()) {
+ types |= Type.ime();
+ }
+ inOutParams.setFitInsetsTypes(types);
+ inOutParams.setFitInsetsSides(sides);
+ inOutParams.setFitInsetsIgnoringVisibility(ignoreVis);
+
+ // The fitting of insets are not really controlled by the clients, so we remove the flag.
+ inOutParams.privateFlags &= ~PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
+ }
+
+ private void controlInsetsForCompatibility(WindowManager.LayoutParams params) {
+ if (sNewInsetsMode != NEW_INSETS_MODE_FULL) {
+ return;
+ }
+ final int sysUiVis = params.systemUiVisibility | params.subtreeSystemUiVisibility;
+ final int flags = params.flags;
+ final boolean matchParent = params.width == MATCH_PARENT && params.height == MATCH_PARENT;
+ final boolean nonAttachedAppWindow = params.type >= FIRST_APPLICATION_WINDOW
+ && params.type <= LAST_APPLICATION_WINDOW;
+ final boolean statusWasHiddenByFlags = (mTypesHiddenByFlags & Type.statusBars()) != 0;
+ final boolean statusIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0
+ || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow);
+ final boolean navWasHiddenByFlags = (mTypesHiddenByFlags & Type.navigationBars()) != 0;
+ final boolean navIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
+
+ @InsetsType int typesToHide = 0;
+ @InsetsType int typesToShow = 0;
+ if (statusIsHiddenByFlags && !statusWasHiddenByFlags) {
+ typesToHide |= Type.statusBars();
+ } else if (!statusIsHiddenByFlags && statusWasHiddenByFlags) {
+ typesToShow |= Type.statusBars();
+ }
+ if (navIsHiddenByFlags && !navWasHiddenByFlags) {
+ typesToHide |= Type.navigationBars();
+ } else if (!navIsHiddenByFlags && navWasHiddenByFlags) {
+ typesToShow |= Type.navigationBars();
+ }
+ if (typesToHide != 0) {
+ getInsetsController().hide(typesToHide);
+ }
+ if (typesToShow != 0) {
+ getInsetsController().show(typesToShow);
+ }
+ mTypesHiddenByFlags |= typesToHide;
+ mTypesHiddenByFlags &= ~typesToShow;
+ }
+
private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
int childWidthMeasureSpec;
@@ -1891,76 +2262,69 @@ public final class ViewRootImpl implements ViewParent,
/* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
if (mLastWindowInsets == null || forceConstruct) {
- mDispatchContentInsets.set(mAttachInfo.mContentInsets);
- mDispatchStableInsets.set(mAttachInfo.mStableInsets);
- mDispatchDisplayCutout = mAttachInfo.mDisplayCutout.get();
-
- Rect contentInsets = mDispatchContentInsets;
- Rect stableInsets = mDispatchStableInsets;
- DisplayCutout displayCutout = mDispatchDisplayCutout;
- // For dispatch we preserve old logic, but for direct requests from Views we allow to
- // immediately use pending insets. This is such that getRootWindowInsets returns the
- // result from the layout hint before we ran a traversal shortly after adding a window.
- if (!forceConstruct
- && (!mPendingContentInsets.equals(contentInsets) ||
- !mPendingStableInsets.equals(stableInsets) ||
- !mPendingDisplayCutout.get().equals(displayCutout))) {
- contentInsets = mPendingContentInsets;
- stableInsets = mPendingStableInsets;
- displayCutout = mPendingDisplayCutout.get();
- }
- Rect outsets = mAttachInfo.mOutsets;
- if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
- contentInsets = new Rect(contentInsets.left + outsets.left,
- contentInsets.top + outsets.top, contentInsets.right + outsets.right,
- contentInsets.bottom + outsets.bottom);
- }
- contentInsets = ensureInsetsNonNegative(contentInsets, "content");
- stableInsets = ensureInsetsNonNegative(stableInsets, "stable");
mLastWindowInsets = mInsetsController.calculateInsets(
mContext.getResources().getConfiguration().isScreenRound(),
- mAttachInfo.mAlwaysConsumeSystemBars, displayCutout,
- contentInsets, stableInsets, mWindowAttributes.softInputMode);
- }
- return mLastWindowInsets;
- }
+ mAttachInfo.mAlwaysConsumeSystemBars, mPendingDisplayCutout.get(),
+ mWindowAttributes.softInputMode, mWindowAttributes.flags,
+ (mWindowAttributes.systemUiVisibility
+ | mWindowAttributes.subtreeSystemUiVisibility));
- private Rect ensureInsetsNonNegative(Rect insets, String kind) {
- if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) {
- Log.wtf(mTag, "Negative " + kind + "Insets: " + insets + ", mFirst=" + mFirst);
- return new Rect(Math.max(0, insets.left),
- Math.max(0, insets.top),
- Math.max(0, insets.right),
- Math.max(0, insets.bottom));
+ Rect visibleInsets = mInsetsController.calculateVisibleInsets(
+ mWindowAttributes.softInputMode);
+
+ mAttachInfo.mVisibleInsets.set(visibleInsets);
+ mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect());
+ mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect());
}
- return insets;
+ return mLastWindowInsets;
}
- void dispatchApplyInsets(View host) {
+ public void dispatchApplyInsets(View host) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchApplyInsets");
+ mApplyInsetsRequested = false;
WindowInsets insets = getWindowInsets(true /* forceConstruct */);
- final boolean dispatchCutout = (mWindowAttributes.layoutInDisplayCutoutMode
- == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS);
- if (!dispatchCutout) {
+ if (!shouldDispatchCutout()) {
// Window is either not laid out in cutout or the status bar inset takes care of
// clearing the cutout, so we don't need to dispatch the cutout to the hierarchy.
insets = insets.consumeDisplayCutout();
}
host.dispatchApplyWindowInsets(insets);
+ mAttachInfo.delayNotifyContentCaptureInsetsEvent(insets.getInsets(Type.all()));
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
- InsetsController getInsetsController() {
+ private boolean updateCaptionInsets() {
+ if (!(mView instanceof DecorView)) return false;
+ final int captionInsetsHeight = ((DecorView) mView).getCaptionInsetsHeight();
+ final Rect captionFrame = new Rect();
+ if (captionInsetsHeight != 0) {
+ captionFrame.set(mWinFrame.left, mWinFrame.top, mWinFrame.right,
+ mWinFrame.top + captionInsetsHeight);
+ }
+ if (mAttachInfo.mCaptionInsets.equals(captionFrame)) return false;
+ mAttachInfo.mCaptionInsets.set(captionFrame);
+ return true;
+ }
+
+ private boolean shouldDispatchCutout() {
+ return mWindowAttributes.layoutInDisplayCutoutMode
+ == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ || mWindowAttributes.layoutInDisplayCutoutMode
+ == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ }
+
+ @VisibleForTesting
+ public InsetsController getInsetsController() {
return mInsetsController;
}
private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
- return lp.type == TYPE_STATUS_BAR_PANEL
+ return lp.type == TYPE_STATUS_BAR_ADDITIONAL
|| lp.type == TYPE_INPUT_METHOD
|| lp.type == TYPE_VOLUME_OVERLAY;
}
- private int dipToPx(int dip) {
+ int dipToPx(int dip) {
final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
return (int) (displayMetrics.density * dip + 0.5f);
}
@@ -1981,7 +2345,6 @@ public final class ViewRootImpl implements ViewParent,
mIsInTraversal = true;
mWillDrawSoon = true;
boolean windowSizeMayChange = false;
- boolean surfaceChanged = false;
WindowManager.LayoutParams lp = mWindowAttributes;
int desiredWindowWidth;
@@ -1998,11 +2361,6 @@ public final class ViewRootImpl implements ViewParent,
((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
WindowManager.LayoutParams params = null;
- if (mWindowAttributesChanged) {
- mWindowAttributesChanged = false;
- surfaceChanged = true;
- params = lp;
- }
CompatibilityInfo compatibilityInfo =
mDisplay.getDisplayAdjustments().getCompatibilityInfo();
if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
@@ -2018,8 +2376,6 @@ public final class ViewRootImpl implements ViewParent,
}
}
- mWindowAttributesChangesFlag = 0;
-
Rect frame = mWinFrame;
if (mFirst) {
mFullRedrawNeeded = true;
@@ -2032,9 +2388,18 @@ public final class ViewRootImpl implements ViewParent,
mDisplay.getRealSize(size);
desiredWindowWidth = size.x;
desiredWindowHeight = size.y;
+ } else if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
+ || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
+ // For wrap content, we have to remeasure later on anyways. Use size consistent with
+ // below so we get best use of the measure cache.
+ desiredWindowWidth = dipToPx(config.screenWidthDp);
+ desiredWindowHeight = dipToPx(config.screenHeightDp);
} else {
- desiredWindowWidth = mWinFrame.width();
- desiredWindowHeight = mWinFrame.height();
+ // After addToDisplay, the frame contains the frameHint from window manager, which
+ // for most windows is going to be the same size as the result of relayoutWindow.
+ // Using this here allows us to avoid remeasuring after relayoutWindow
+ desiredWindowWidth = frame.width();
+ desiredWindowHeight = frame.height();
}
// We used to use the following condition to choose 32 bits drawing caches:
@@ -2073,11 +2438,6 @@ public final class ViewRootImpl implements ViewParent,
endDragResizing();
destroyHardwareResources();
}
- if (viewVisibility == View.GONE) {
- // After making a window gone, we will count it as being
- // shown for the first time the next time it gets focus.
- mHasHadWindowFocus = false;
- }
}
// Non-visible windows can't hold accessibility focus.
@@ -2088,7 +2448,7 @@ public final class ViewRootImpl implements ViewParent,
// Execute enqueued actions on every traversal in case a detached view enqueued an action
getRunQueue().executeActions(mAttachInfo.mHandler);
- boolean insetsChanged = false;
+ boolean cutoutChanged = false;
boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
if (layoutRequested) {
@@ -2101,28 +2461,8 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mInTouchMode = !mAddedTouchMode;
ensureTouchModeLocally(mAddedTouchMode);
} else {
- if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
- insetsChanged = true;
- }
- if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
- insetsChanged = true;
- }
- if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
- insetsChanged = true;
- }
if (!mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout)) {
- insetsChanged = true;
- }
- if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
- mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
- if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
- + mAttachInfo.mVisibleInsets);
- }
- if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
- insetsChanged = true;
- }
- if (mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars) {
- insetsChanged = true;
+ cutoutChanged = true;
}
if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
|| lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
@@ -2181,19 +2521,7 @@ public final class ViewRootImpl implements ViewParent,
}
}
- if (params != null) {
- if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
- if (!PixelFormat.formatHasAlpha(params.format)) {
- params.format = PixelFormat.TRANSLUCENT;
- }
- }
- mAttachInfo.mOverscanRequested = (params.flags
- & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
- }
-
if (mApplyInsetsRequested) {
- mApplyInsetsRequested = false;
- mLastOverscanRequested = mAttachInfo.mOverscanRequested;
dispatchApplyInsets(host);
if (mLayoutRequested) {
// Short-circuit catching a new layout request here, so
@@ -2241,9 +2569,28 @@ public final class ViewRootImpl implements ViewParent,
final boolean isViewVisible = viewVisibility == View.VISIBLE;
final boolean windowRelayoutWasForced = mForceNextWindowRelayout;
boolean surfaceSizeChanged = false;
+ boolean surfaceCreated = false;
+ boolean surfaceDestroyed = false;
+ /* True if surface generation id changes. */
+ boolean surfaceReplaced = false;
- if (mFirst || windowShouldResize || insetsChanged ||
- viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
+ final boolean windowAttributesChanged = mWindowAttributesChanged;
+ if (windowAttributesChanged) {
+ mWindowAttributesChanged = false;
+ params = lp;
+ }
+
+ if (params != null) {
+ if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0
+ && !PixelFormat.formatHasAlpha(params.format)) {
+ params.format = PixelFormat.TRANSLUCENT;
+ }
+ adjustLayoutParamsForCompatibility(params);
+ controlInsetsForCompatibility(params);
+ }
+
+ if (mFirst || windowShouldResize || viewVisibilityChanged || cutoutChanged || params != null
+ || mForceNextWindowRelayout) {
mForceNextWindowRelayout = false;
if (isViewVisible) {
@@ -2265,7 +2612,7 @@ public final class ViewRootImpl implements ViewParent,
}
boolean hwInitialized = false;
- boolean contentInsetsChanged = false;
+ boolean dispatchApplyInsets = false;
boolean hadSurface = mSurface.isValid();
try {
@@ -2288,12 +2635,7 @@ public final class ViewRootImpl implements ViewParent,
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
- + " overscan=" + mPendingOverscanInsets.toShortString()
- + " content=" + mPendingContentInsets.toShortString()
- + " visible=" + mPendingVisibleInsets.toShortString()
- + " stable=" + mPendingStableInsets.toShortString()
+ " cutout=" + mPendingDisplayCutout.get().toString()
- + " outsets=" + mPendingOutsets.toShortString()
+ " surface=" + mSurface);
// If the pending {@link MergedConfiguration} handed back from
@@ -2309,104 +2651,70 @@ public final class ViewRootImpl implements ViewParent,
updatedConfiguration = true;
}
- final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
- mAttachInfo.mOverscanInsets);
- contentInsetsChanged = !mPendingContentInsets.equals(
- mAttachInfo.mContentInsets);
- final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
- mAttachInfo.mVisibleInsets);
- final boolean stableInsetsChanged = !mPendingStableInsets.equals(
- mAttachInfo.mStableInsets);
- final boolean cutoutChanged = !mPendingDisplayCutout.equals(
- mAttachInfo.mDisplayCutout);
- final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
+ cutoutChanged = !mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout);
surfaceSizeChanged = (relayoutResult
& WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
- surfaceChanged |= surfaceSizeChanged;
final boolean alwaysConsumeSystemBarsChanged =
mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
final boolean colorModeChanged = hasColorModeChanged(lp.getColorMode());
- if (contentInsetsChanged) {
- mAttachInfo.mContentInsets.set(mPendingContentInsets);
- if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
- + mAttachInfo.mContentInsets);
- }
- if (overscanInsetsChanged) {
- mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
- if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: "
- + mAttachInfo.mOverscanInsets);
- // Need to relayout with content insets.
- contentInsetsChanged = true;
- }
- if (stableInsetsChanged) {
- mAttachInfo.mStableInsets.set(mPendingStableInsets);
- if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: "
- + mAttachInfo.mStableInsets);
- // Need to relayout with content insets.
- contentInsetsChanged = true;
- }
+ surfaceCreated = !hadSurface && mSurface.isValid();
+ surfaceDestroyed = hadSurface && !mSurface.isValid();
+ surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId())
+ && mSurface.isValid();
+
if (cutoutChanged) {
mAttachInfo.mDisplayCutout.set(mPendingDisplayCutout);
if (DEBUG_LAYOUT) {
Log.v(mTag, "DisplayCutout changing to: " + mAttachInfo.mDisplayCutout);
}
// Need to relayout with content insets.
- contentInsetsChanged = true;
+ dispatchApplyInsets = true;
}
if (alwaysConsumeSystemBarsChanged) {
mAttachInfo.mAlwaysConsumeSystemBars = mPendingAlwaysConsumeSystemBars;
- contentInsetsChanged = true;
+ dispatchApplyInsets = true;
+ }
+ if (updateCaptionInsets()) {
+ dispatchApplyInsets = true;
}
- if (contentInsetsChanged || mLastSystemUiVisibility !=
- mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
- || mLastOverscanRequested != mAttachInfo.mOverscanRequested
- || outsetsChanged) {
+ if (dispatchApplyInsets || mLastSystemUiVisibility !=
+ mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested) {
mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
- mLastOverscanRequested = mAttachInfo.mOverscanRequested;
- mAttachInfo.mOutsets.set(mPendingOutsets);
- mApplyInsetsRequested = false;
dispatchApplyInsets(host);
// We applied insets so force contentInsetsChanged to ensure the
// hierarchy is measured below.
- contentInsetsChanged = true;
- }
- if (visibleInsetsChanged) {
- mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
- if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
- + mAttachInfo.mVisibleInsets);
+ dispatchApplyInsets = true;
}
if (colorModeChanged && mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mThreadedRenderer.setWideGamut(
lp.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
}
- if (!hadSurface) {
- if (mSurface.isValid()) {
- // If we are creating a new surface, then we need to
- // completely redraw it.
- mFullRedrawNeeded = true;
- mPreviousTransparentRegion.setEmpty();
+ if (surfaceCreated) {
+ // If we are creating a new surface, then we need to
+ // completely redraw it.
+ mFullRedrawNeeded = true;
+ mPreviousTransparentRegion.setEmpty();
- // Only initialize up-front if transparent regions are not
- // requested, otherwise defer to see if the entire window
- // will be transparent
- if (mAttachInfo.mThreadedRenderer != null) {
- try {
- hwInitialized = mAttachInfo.mThreadedRenderer.initialize(
- mSurface);
- if (hwInitialized && (host.mPrivateFlags
- & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
- // Don't pre-allocate if transparent regions
- // are requested as they may not be needed
- mAttachInfo.mThreadedRenderer.allocateBuffers();
- }
- } catch (OutOfResourcesException e) {
- handleOutOfResourcesException(e);
- return;
+ // Only initialize up-front if transparent regions are not
+ // requested, otherwise defer to see if the entire window
+ // will be transparent
+ if (mAttachInfo.mThreadedRenderer != null) {
+ try {
+ hwInitialized = mAttachInfo.mThreadedRenderer.initialize(mSurface);
+ if (hwInitialized && (host.mPrivateFlags
+ & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
+ // Don't pre-allocate if transparent regions
+ // are requested as they may not be needed
+ mAttachInfo.mThreadedRenderer.allocateBuffers();
}
+ } catch (OutOfResourcesException e) {
+ handleOutOfResourcesException(e);
+ return;
}
}
- } else if (!mSurface.isValid()) {
+ notifySurfaceCreated();
+ } else if (surfaceDestroyed) {
// If the surface has been removed, then reset the scroll
// positions.
if (mLastScrolledFocus != null) {
@@ -2424,10 +2732,11 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mThreadedRenderer.isEnabled()) {
mAttachInfo.mThreadedRenderer.destroy();
}
- } else if ((surfaceGenerationId != mSurface.getGenerationId()
+ } else if ((surfaceReplaced
|| surfaceSizeChanged || windowRelayoutWasForced || colorModeChanged)
&& mSurfaceHolder == null
- && mAttachInfo.mThreadedRenderer != null) {
+ && mAttachInfo.mThreadedRenderer != null
+ && mSurface.isValid()) {
mFullRedrawNeeded = true;
try {
// Need to do updateSurface (which leads to CanvasContext::setSurface and
@@ -2445,6 +2754,10 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ if (!surfaceCreated && surfaceReplaced) {
+ notifySurfaceReplaced();
+ }
+
final boolean freeformResizing = (relayoutResult
& WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0;
final boolean dockedResizing = (relayoutResult
@@ -2460,7 +2773,8 @@ public final class ViewRootImpl implements ViewParent,
&& mWinFrame.height() == mPendingBackDropFrame.height();
// TODO: Need cutout?
startDragResizing(mPendingBackDropFrame, !backdropSizeMatchesFrame,
- mPendingVisibleInsets, mPendingStableInsets, mResizeMode);
+ mLastWindowInsets.getSystemWindowInsets().toRect(),
+ mLastWindowInsets.getStableInsets().toRect(), mResizeMode);
} else {
// We shouldn't come here, but if we come we should end the resize.
endDragResizing();
@@ -2500,31 +2814,32 @@ public final class ViewRootImpl implements ViewParent,
}
mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
mSurfaceHolder.mSurfaceLock.unlock();
- if (mSurface.isValid()) {
- if (!hadSurface) {
- mSurfaceHolder.ungetCallbacks();
-
- mIsCreating = true;
- SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
- if (callbacks != null) {
- for (SurfaceHolder.Callback c : callbacks) {
- c.surfaceCreated(mSurfaceHolder);
- }
+ if (surfaceCreated) {
+ mSurfaceHolder.ungetCallbacks();
+
+ mIsCreating = true;
+ SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
+ if (callbacks != null) {
+ for (SurfaceHolder.Callback c : callbacks) {
+ c.surfaceCreated(mSurfaceHolder);
}
- surfaceChanged = true;
}
- if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) {
- SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
- if (callbacks != null) {
- for (SurfaceHolder.Callback c : callbacks) {
- c.surfaceChanged(mSurfaceHolder, lp.format,
- mWidth, mHeight);
- }
+ }
+
+ if ((surfaceCreated || surfaceReplaced || surfaceSizeChanged
+ || windowAttributesChanged) && mSurface.isValid()) {
+ SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
+ if (callbacks != null) {
+ for (SurfaceHolder.Callback c : callbacks) {
+ c.surfaceChanged(mSurfaceHolder, lp.format,
+ mWidth, mHeight);
}
}
mIsCreating = false;
- } else if (hadSurface) {
- notifySurfaceDestroyed();
+ }
+
+ if (surfaceDestroyed) {
+ notifyHolderSurfaceDestroyed();
mSurfaceHolder.mSurfaceLock.lock();
try {
mSurfaceHolder.mSurface = new Surface();
@@ -2550,7 +2865,7 @@ public final class ViewRootImpl implements ViewParent,
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
(relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
- || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
+ || mHeight != host.getMeasuredHeight() || dispatchApplyInsets ||
updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
@@ -2559,7 +2874,7 @@ public final class ViewRootImpl implements ViewParent,
+ mWidth + " measuredWidth=" + host.getMeasuredWidth()
+ " mHeight=" + mHeight
+ " measuredHeight=" + host.getMeasuredHeight()
- + " coveredInsetsChanged=" + contentInsetsChanged);
+ + " dispatchApplyInsets=" + dispatchApplyInsets);
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
@@ -2603,8 +2918,17 @@ public final class ViewRootImpl implements ViewParent,
maybeHandleWindowMove(frame);
}
- if (surfaceSizeChanged) {
- updateBoundsSurface();
+ if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) {
+ // If the surface has been replaced, there's a chance the bounds layer is not parented
+ // to the new layer. When updating bounds layer, also reparent to the main VRI
+ // SurfaceControl to ensure it's correctly placed in the hierarchy.
+ //
+ // This needs to be done on the client side since WMS won't reparent the children to the
+ // new surface if it thinks the app is closing. WMS gets the signal that the app is
+ // stopping, but on the client side it doesn't get stopped since it's restarted quick
+ // enough. WMS doesn't want to keep around old children since they will leak when the
+ // client creates new children.
+ updateBoundsLayer(surfaceReplaced);
}
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
@@ -2647,6 +2971,10 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ if (surfaceDestroyed) {
+ notifySurfaceDestroyed();
+ }
+
if (triggerGlobalLayoutListener) {
mAttachInfo.mRecomputeGlobalAttributes = false;
mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
@@ -2733,7 +3061,7 @@ public final class ViewRootImpl implements ViewParent,
if (changedVisibility || regainedFocus) {
// Toasts are presented as notifications - don't present them as windows as well
boolean isToast = (mWindowAttributes == null) ? false
- : (mWindowAttributes.type == WindowManager.LayoutParams.TYPE_TOAST);
+ : (mWindowAttributes.type == TYPE_TOAST);
if (!isToast) {
host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
}
@@ -2746,25 +3074,17 @@ public final class ViewRootImpl implements ViewParent,
mViewVisibility = viewVisibility;
mHadWindowFocus = hasWindowFocus;
- if (hasWindowFocus && !isInLocalFocusMode()) {
- final boolean imTarget = WindowManager.LayoutParams
- .mayUseInputMethod(mWindowAttributes.flags);
- if (imTarget != mLastWasImTarget) {
- mLastWasImTarget = imTarget;
- InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
- if (imm != null && imTarget) {
- imm.onPreWindowFocus(mView, hasWindowFocus);
- imm.onPostWindowFocus(mView, mView.findFocus(),
- mWindowAttributes.softInputMode,
- !mHasHadWindowFocus, mWindowAttributes.flags);
- }
- }
- }
+ mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
// Remember if we must report the next draw.
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
reportNextDraw();
}
+ if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC) != 0) {
+ reportNextDraw();
+ setUseBLASTSyncTransaction();
+ mSendNextFrameToWm = true;
+ }
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
@@ -2826,6 +3146,8 @@ public final class ViewRootImpl implements ViewParent,
ViewStructure structure = session.newViewStructure(view);
view.onProvideContentCaptureStructure(structure, /* flags= */ 0);
session.notifyViewAppeared(structure);
+ } else if (event instanceof Insets) {
+ mainSession.notifyViewInsetsChanged(sessionId, (Insets) event);
} else {
Log.w(mTag, "invalid content capture event: " + event);
}
@@ -2838,7 +3160,7 @@ public final class ViewRootImpl implements ViewParent,
}
}
- private void notifySurfaceDestroyed() {
+ private void notifyHolderSurfaceDestroyed() {
mSurfaceHolder.ungetCallbacks();
SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
if (callbacks != null) {
@@ -2927,14 +3249,9 @@ public final class ViewRootImpl implements ViewParent,
}
mAttachInfo.mHasWindowFocus = hasWindowFocus;
+ mImeFocusController.updateImeFocusable(mWindowAttributes, true /* force */);
+ mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes);
- mLastWasImTarget = WindowManager.LayoutParams
- .mayUseInputMethod(mWindowAttributes.flags);
-
- InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
- if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
- imm.onPreWindowFocus(mView, hasWindowFocus);
- }
if (mView != null) {
mAttachInfo.mKeyDispatchState.reset();
mView.dispatchWindowFocusChanged(hasWindowFocus);
@@ -2946,12 +3263,10 @@ public final class ViewRootImpl implements ViewParent,
// Note: must be done after the focus change callbacks,
// so all of the view state is set up correctly.
+ mImeFocusController.onPostWindowFocus(mView.findFocus(), hasWindowFocus,
+ mWindowAttributes);
+
if (hasWindowFocus) {
- if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
- imm.onPostWindowFocus(mView, mView.findFocus(),
- mWindowAttributes.softInputMode,
- !mHasHadWindowFocus, mWindowAttributes.flags);
- }
// Clear the forward bit. We can just do this directly, since
// the window manager doesn't care about it.
mWindowAttributes.softInputMode &=
@@ -2960,7 +3275,6 @@ public final class ViewRootImpl implements ViewParent,
.softInputMode &=
~WindowManager.LayoutParams
.SOFT_INPUT_IS_FORWARD_NAVIGATION;
- mHasHadWindowFocus = true;
// Refocusing a window that has a focused view should fire a
// focus event for the view since the global focused view changed.
@@ -3139,7 +3453,6 @@ public final class ViewRootImpl implements ViewParent,
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
int desiredWindowHeight) {
- mLayoutRequested = false;
mScrollMayChange = true;
mInLayout = true;
@@ -3280,14 +3593,19 @@ public final class ViewRootImpl implements ViewParent,
public void requestTransparentRegion(View child) {
// the test below should not fail unless someone is messing with us
checkThread();
- if (mView == child) {
+ if (mView != child) {
+ return;
+ }
+
+ if ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
// Need to make sure we re-evaluate the window attributes next
// time around, to ensure the window has the correct format.
mWindowAttributesChanged = true;
- mWindowAttributesChangesFlag = 0;
- requestLayout();
}
+
+ // Always request layout to apply the latest transparent region.
+ requestLayout();
}
/**
@@ -3444,7 +3762,7 @@ public final class ViewRootImpl implements ViewParent,
private void reportDrawFinished() {
try {
mDrawsNeededToReport = 0;
- mWindowSession.finishDrawing(mWindow);
+ mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction);
} catch (RemoteException e) {
// Have fun!
}
@@ -3464,38 +3782,54 @@ public final class ViewRootImpl implements ViewParent,
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
boolean usingAsyncReport = false;
+ boolean reportNextDraw = mReportNextDraw; // Capture the original value
if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver
.captureFrameCommitCallbacks();
- if (mReportNextDraw) {
- usingAsyncReport = true;
+ final boolean needFrameCompleteCallback = mNextDrawUseBLASTSyncTransaction ||
+ (commitCallbacks != null && commitCallbacks.size() > 0) ||
+ mReportNextDraw;
+ usingAsyncReport = mReportNextDraw;
+ if (needFrameCompleteCallback) {
final Handler handler = mAttachInfo.mHandler;
- mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) ->
+ mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> {
+ finishBLASTSync(!mSendNextFrameToWm);
handler.postAtFrontOfQueue(() -> {
- // TODO: Use the frame number
- pendingDrawFinished();
+ if (reportNextDraw) {
+ // TODO: Use the frame number
+ pendingDrawFinished();
+ }
if (commitCallbacks != null) {
for (int i = 0; i < commitCallbacks.size(); i++) {
commitCallbacks.get(i).run();
}
}
- }));
- } else if (commitCallbacks != null && commitCallbacks.size() > 0) {
- final Handler handler = mAttachInfo.mHandler;
- mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) ->
- handler.postAtFrontOfQueue(() -> {
- for (int i = 0; i < commitCallbacks.size(); i++) {
- commitCallbacks.get(i).run();
- }
- }));
+ });});
}
}
try {
+ if (mNextDrawUseBLASTSyncTransaction) {
+ // TODO(b/149747443)
+ // We aren't prepared to handle overlapping use of mRtBLASTSyncTransaction
+ // so if we are BLAST syncing we make sure the previous draw has
+ // totally finished.
+ if (mAttachInfo.mThreadedRenderer != null) {
+ mAttachInfo.mThreadedRenderer.pause();
+ }
+
+ mNextReportConsumeBLAST = true;
+ mNextDrawUseBLASTSyncTransaction = false;
+
+ if (mBlastBufferQueue != null) {
+ mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction);
+ }
+ }
boolean canUseAsync = draw(fullRedrawNeeded);
if (usingAsyncReport && !canUseAsync) {
mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null);
usingAsyncReport = false;
+ finishBLASTSync(true /* apply */);
}
} finally {
mIsDrawing = false;
@@ -4025,7 +4359,7 @@ public final class ViewRootImpl implements ViewParent,
}
boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
- final Rect ci = mAttachInfo.mContentInsets;
+ final Rect ci = getWindowInsets(false).getSystemWindowInsetsAsRect();
final Rect vi = mAttachInfo.mVisibleInsets;
int scrollY = 0;
boolean handled = false;
@@ -4304,6 +4638,9 @@ public final class ViewRootImpl implements ViewParent,
}
void dispatchDetachedFromWindow() {
+ // Make sure we free-up insets resources if view never received onWindowFocusLost()
+ // because of a die-signal
+ mInsetsController.onWindowFocusLost();
mFirstInputStage.onDetachedFromWindow();
if (mView != null && mView.mAttachInfo != null) {
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
@@ -4321,6 +4658,8 @@ public final class ViewRootImpl implements ViewParent,
setAccessibilityFocus(null, null);
+ mInsetsController.cancelExistingAnimations();
+
mView.assignParent(null);
mView = null;
mAttachInfo.mRootView = null;
@@ -4333,20 +4672,16 @@ public final class ViewRootImpl implements ViewParent,
mInputQueueCallback = null;
mInputQueue = null;
}
- if (mInputEventReceiver != null) {
- mInputEventReceiver.dispose();
- mInputEventReceiver = null;
- }
try {
mWindowSession.remove(mWindow);
} catch (RemoteException e) {
}
-
- // Dispose the input channel after removing the window so the Window Manager
- // doesn't interpret the input channel being closed as an abnormal termination.
- if (mInputChannel != null) {
- mInputChannel.dispose();
- mInputChannel = null;
+ // Dispose receiver would dispose client InputChannel, too. That could send out a socket
+ // broken event, so we need to unregister the server InputChannel when removing window to
+ // prevent server side receive the event and prompt error.
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.dispose();
+ mInputEventReceiver = null;
}
mDisplayManager.unregisterDisplayListener(mDisplayListener);
@@ -4503,6 +4838,10 @@ public final class ViewRootImpl implements ViewParent,
private static final int MSG_INSETS_CONTROL_CHANGED = 31;
private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 32;
private static final int MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED = 33;
+ private static final int MSG_SHOW_INSETS = 34;
+ private static final int MSG_HIDE_INSETS = 35;
+ private static final int MSG_REQUEST_SCROLL_CAPTURE = 36;
+
final class ViewRootHandler extends Handler {
@Override
@@ -4566,6 +4905,10 @@ public final class ViewRootImpl implements ViewParent,
return "MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED";
case MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED:
return "MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED";
+ case MSG_SHOW_INSETS:
+ return "MSG_SHOW_INSETS";
+ case MSG_HIDE_INSETS:
+ return "MSG_HIDE_INSETS";
}
return super.getMessageName(message);
}
@@ -4606,14 +4949,9 @@ public final class ViewRootImpl implements ViewParent,
// Recycled in the fall through...
SomeArgs args = (SomeArgs) msg.obj;
if (mWinFrame.equals(args.arg1)
- && mPendingOverscanInsets.equals(args.arg5)
- && mPendingContentInsets.equals(args.arg2)
- && mPendingStableInsets.equals(args.arg6)
&& mPendingDisplayCutout.get().equals(args.arg9)
- && mPendingVisibleInsets.equals(args.arg3)
- && mPendingOutsets.equals(args.arg7)
&& mPendingBackDropFrame.equals(args.arg8)
- && args.arg4 == null
+ && mLastReportedMergedConfiguration.equals(args.arg4)
&& args.argi1 == 0
&& mDisplay.getDisplayId() == args.argi3) {
break;
@@ -4641,20 +4979,10 @@ public final class ViewRootImpl implements ViewParent,
}
final boolean framesChanged = !mWinFrame.equals(args.arg1)
- || !mPendingOverscanInsets.equals(args.arg5)
- || !mPendingContentInsets.equals(args.arg2)
- || !mPendingStableInsets.equals(args.arg6)
- || !mPendingDisplayCutout.get().equals(args.arg9)
- || !mPendingVisibleInsets.equals(args.arg3)
- || !mPendingOutsets.equals(args.arg7);
+ || !mPendingDisplayCutout.get().equals(args.arg9);
setFrame((Rect) args.arg1);
- mPendingOverscanInsets.set((Rect) args.arg5);
- mPendingContentInsets.set((Rect) args.arg2);
- mPendingStableInsets.set((Rect) args.arg6);
mPendingDisplayCutout.set((DisplayCutout) args.arg9);
- mPendingVisibleInsets.set((Rect) args.arg3);
- mPendingOutsets.set((Rect) args.arg7);
mPendingBackDropFrame.set((Rect) args.arg8);
mForceNextWindowRelayout = args.argi1 != 0;
mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
@@ -4676,8 +5004,27 @@ public final class ViewRootImpl implements ViewParent,
break;
case MSG_INSETS_CONTROL_CHANGED: {
SomeArgs args = (SomeArgs) msg.obj;
- mInsetsController.onControlsChanged((InsetsSourceControl[]) args.arg2);
+
+ // Deliver state change before control change, such that:
+ // a) When gaining control, controller can compare with server state to evaluate
+ // whether it needs to run animation.
+ // b) When loosing control, controller can restore server state by taking last
+ // dispatched state as truth.
mInsetsController.onStateChanged((InsetsState) args.arg1);
+ mInsetsController.onControlsChanged((InsetsSourceControl[]) args.arg2);
+ break;
+ }
+ case MSG_SHOW_INSETS: {
+ if (mView == null) {
+ Log.e(TAG,
+ String.format("Calling showInsets(%d,%b) on window that no longer"
+ + " has views.", msg.arg1, msg.arg2 == 1));
+ }
+ mInsetsController.show(msg.arg1, msg.arg2 == 1);
+ break;
+ }
+ case MSG_HIDE_INSETS: {
+ mInsetsController.hide(msg.arg1, msg.arg2 == 1);
break;
}
case MSG_WINDOW_MOVED:
@@ -4735,10 +5082,7 @@ public final class ViewRootImpl implements ViewParent,
enqueueInputEvent(event, null, 0, true);
} break;
case MSG_CHECK_FOCUS: {
- InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
- if (imm != null) {
- imm.checkFocus();
- }
+ getImeFocusController().checkFocus(false, true);
} break;
case MSG_CLOSE_SYSTEM_DIALOGS: {
if (mView != null) {
@@ -4804,6 +5148,9 @@ public final class ViewRootImpl implements ViewParent,
case MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED: {
updateLocationInParentDisplay(msg.arg1, msg.arg2);
} break;
+ case MSG_REQUEST_SCROLL_CAPTURE:
+ handleScrollCaptureRequest((IScrollCaptureController) msg.obj);
+ break;
}
}
}
@@ -4938,6 +5285,8 @@ public final class ViewRootImpl implements ViewParent,
protected static final int FINISH_HANDLED = 1;
protected static final int FINISH_NOT_HANDLED = 2;
+ private String mTracePrefix;
+
/**
* Creates an input stage.
* @param next The next stage to which events should be forwarded.
@@ -4955,7 +5304,14 @@ public final class ViewRootImpl implements ViewParent,
} else if (shouldDropInputEvent(q)) {
finish(q, false);
} else {
- apply(q, onProcess(q));
+ traceEvent(q, Trace.TRACE_TAG_VIEW);
+ final int result;
+ try {
+ result = onProcess(q);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ apply(q, result);
}
}
@@ -5065,6 +5421,18 @@ public final class ViewRootImpl implements ViewParent,
return false;
}
}
+
+ private void traceEvent(QueuedInputEvent q, long traceTag) {
+ if (!Trace.isTagEnabled(traceTag)) {
+ return;
+ }
+
+ if (mTracePrefix == null) {
+ mTracePrefix = getClass().getSimpleName();
+ }
+ Trace.traceBegin(traceTag, mTracePrefix + " id=0x"
+ + Integer.toHexString(q.mEvent.getId()));
+ }
}
/**
@@ -5282,23 +5650,20 @@ public final class ViewRootImpl implements ViewParent,
@Override
protected int onProcess(QueuedInputEvent q) {
- if (mLastWasImTarget && !isInLocalFocusMode()) {
- InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
- if (imm != null) {
- final InputEvent event = q.mEvent;
- if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
- int result = imm.dispatchInputEvent(event, q, this, mHandler);
- if (result == InputMethodManager.DISPATCH_HANDLED) {
- return FINISH_HANDLED;
- } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
- // The IME could not handle it, so skip along to the next InputStage
- return FORWARD;
- } else {
- return DEFER; // callback will be invoked later
- }
- }
+ final int result = mImeFocusController.onProcessImeInputStage(
+ q, q.mEvent, mWindowAttributes, this);
+ switch (result) {
+ case InputMethodManager.DISPATCH_IN_PROGRESS:
+ // callback will be invoked later
+ return DEFER;
+ case InputMethodManager.DISPATCH_NOT_HANDLED:
+ // The IME could not handle it, so skip along to the next InputStage
+ return FORWARD;
+ case InputMethodManager.DISPATCH_HANDLED:
+ return FINISH_HANDLED;
+ default:
+ throw new IllegalStateException("Unexpected result=" + result);
}
- return FORWARD;
}
@Override
@@ -5374,11 +5739,10 @@ public final class ViewRootImpl implements ViewParent,
mTranslator.translateEventInScreenToAppWindow(event);
}
- // Enter touch mode on down or scroll, if it is coming from a touch screen device,
- // exit otherwise.
+ // Enter touch mode on down or scroll from any type of a device.
final int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
- ensureTouchMode(event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN));
+ ensureTouchMode(true);
}
if (action == MotionEvent.ACTION_DOWN) {
@@ -6938,27 +7302,6 @@ public final class ViewRootImpl implements ViewParent,
event.recycle();
}
- public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
- if (mSeq != args.seq) {
- // The sequence has changed, so we need to update our value and make
- // sure to do a traversal afterward so the window manager is given our
- // most recent data.
- mSeq = args.seq;
- mAttachInfo.mForceReportNewAttributes = true;
- scheduleTraversals();
- }
- if (mView == null) return;
- if (args.localChanges != 0) {
- mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
- }
-
- int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
- if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
- mAttachInfo.mGlobalSystemUiVisibility = visibility;
- mView.dispatchSystemUiVisibilityChanged(visibility);
- }
- }
-
/**
* Notify that the window title changed
*/
@@ -7101,11 +7444,22 @@ public final class ViewRootImpl implements ViewParent,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
- mTmpFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
- mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
- mPendingMergedConfiguration, mSurfaceControl, mTempInsets);
+ mTmpFrame, mTmpRect, mTmpRect, mTmpRect, mPendingBackDropFrame,
+ mPendingDisplayCutout, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
+ mTempControls, mSurfaceSize, mBlastSurfaceControl);
if (mSurfaceControl.isValid()) {
- mSurface.copyFrom(mSurfaceControl);
+ if (!useBLAST()) {
+ mSurface.copyFrom(mSurfaceControl);
+ } else {
+ final Surface blastSurface = getOrCreateBLASTSurface(mSurfaceSize.x,
+ mSurfaceSize.y);
+ // If blastSurface == null that means it hasn't changed since the last time we
+ // called. In this situation, avoid calling transferFrom as we would then
+ // inc the generation ID and cause EGL resources to be recreated.
+ if (blastSurface != null) {
+ mSurface.transferFrom(blastSurface);
+ }
+ }
} else {
destroySurface();
}
@@ -7119,13 +7473,10 @@ public final class ViewRootImpl implements ViewParent,
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWinFrame(mTmpFrame);
- mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
- mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
- mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
- mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
}
setFrame(mTmpFrame);
mInsetsController.onStateChanged(mTempInsets);
+ mInsetsController.onControlsChanged(mTempControls);
return relayoutResult;
}
@@ -7227,6 +7578,9 @@ public final class ViewRootImpl implements ViewParent,
writer.print(mTraversalScheduled);
writer.print(innerPrefix); writer.print("mIsAmbientMode=");
writer.print(mIsAmbientMode);
+ writer.print(innerPrefix); writer.print("mUnbufferedInputSource=");
+ writer.print(Integer.toHexString(mUnbufferedInputSource));
+
if (mTraversalScheduled) {
writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
} else {
@@ -7263,26 +7617,42 @@ public final class ViewRootImpl implements ViewParent,
}
}
- public void dumpGfxInfo(int[] info) {
- info[0] = info[1] = 0;
- if (mView != null) {
- getGfxInfo(mView, info);
+ static final class GfxInfo {
+ public int viewCount;
+ public long renderNodeMemoryUsage;
+ public long renderNodeMemoryAllocated;
+
+ void add(GfxInfo other) {
+ viewCount += other.viewCount;
+ renderNodeMemoryUsage += other.renderNodeMemoryUsage;
+ renderNodeMemoryAllocated += other.renderNodeMemoryAllocated;
}
}
- private static void getGfxInfo(View view, int[] info) {
- RenderNode renderNode = view.mRenderNode;
- info[0]++;
- if (renderNode != null) {
- info[1] += (int) renderNode.computeApproximateMemoryUsage();
+ GfxInfo getGfxInfo() {
+ GfxInfo info = new GfxInfo();
+ if (mView != null) {
+ appendGfxInfo(mView, info);
}
+ return info;
+ }
+ private static void computeRenderNodeUsage(RenderNode node, GfxInfo info) {
+ if (node == null) return;
+ info.renderNodeMemoryUsage += node.computeApproximateMemoryUsage();
+ info.renderNodeMemoryAllocated += node.computeApproximateMemoryAllocated();
+ }
+
+ private static void appendGfxInfo(View view, GfxInfo info) {
+ info.viewCount++;
+ computeRenderNodeUsage(view.mRenderNode, info);
+ computeRenderNodeUsage(view.mBackgroundRenderNode, info);
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
int count = group.getChildCount();
for (int i = 0; i < count; i++) {
- getGfxInfo(group.getChildAt(i), info);
+ appendGfxInfo(group.getChildAt(i), info);
}
}
}
@@ -7334,7 +7704,8 @@ public final class ViewRootImpl implements ViewParent,
try {
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
- mWindowSession.finishDrawing(mWindow);
+ mWindowSession.finishDrawing(
+ mWindow, null /* postDrawTransaction */);
}
} catch (RemoteException e) {
}
@@ -7397,8 +7768,8 @@ public final class ViewRootImpl implements ViewParent,
}
@UnsupportedAppUsage
- private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+ private void dispatchResized(Rect frame, Rect contentInsets,
+ Rect visibleInsets, Rect stableInsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId,
DisplayCutout.ParcelableWrapper displayCutout) {
@@ -7423,7 +7794,6 @@ public final class ViewRootImpl implements ViewParent,
Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWindow(frame);
- mTranslator.translateRectInScreenToAppWindow(overscanInsets);
mTranslator.translateRectInScreenToAppWindow(contentInsets);
mTranslator.translateRectInScreenToAppWindow(visibleInsets);
}
@@ -7434,9 +7804,7 @@ public final class ViewRootImpl implements ViewParent,
args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
args.arg4 = sameProcessCall && mergedConfiguration != null
? new MergedConfiguration(mergedConfiguration) : mergedConfiguration;
- args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
- args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
args.arg9 = displayCutout.get(); // DisplayCutout is immutable.
args.argi1 = forceLayout ? 1 : 0;
@@ -7447,17 +7815,36 @@ public final class ViewRootImpl implements ViewParent,
}
private void dispatchInsetsChanged(InsetsState insetsState) {
+ if (Binder.getCallingPid() == android.os.Process.myPid()) {
+ insetsState = new InsetsState(insetsState, true /* copySource */);
+ }
mHandler.obtainMessage(MSG_INSETS_CHANGED, insetsState).sendToTarget();
}
private void dispatchInsetsControlChanged(InsetsState insetsState,
InsetsSourceControl[] activeControls) {
+ if (Binder.getCallingPid() == android.os.Process.myPid()) {
+ insetsState = new InsetsState(insetsState, true /* copySource */);
+ if (activeControls != null) {
+ for (int i = activeControls.length - 1; i >= 0; i--) {
+ activeControls[i] = new InsetsSourceControl(activeControls[i]);
+ }
+ }
+ }
SomeArgs args = SomeArgs.obtain();
args.arg1 = insetsState;
args.arg2 = activeControls;
mHandler.obtainMessage(MSG_INSETS_CONTROL_CHANGED, args).sendToTarget();
}
+ private void showInsets(@InsetsType int types, boolean fromIme) {
+ mHandler.obtainMessage(MSG_SHOW_INSETS, types, fromIme ? 1 : 0).sendToTarget();
+ }
+
+ private void hideInsets(@InsetsType int types, boolean fromIme) {
+ mHandler.obtainMessage(MSG_HIDE_INSETS, types, fromIme ? 1 : 0).sendToTarget();
+ }
+
public void dispatchMoved(int newX, int newY) {
if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
if (mTranslator != null) {
@@ -7654,33 +8041,54 @@ public final class ViewRootImpl implements ViewParent,
private void deliverInputEvent(QueuedInputEvent q) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
- q.mEvent.getSequenceNumber());
- if (mInputEventConsistencyVerifier != null) {
- mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
- }
+ q.mEvent.getId());
- InputStage stage;
- if (q.shouldSendToSynthesizer()) {
- stage = mSyntheticInputStage;
- } else {
- stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x"
+ + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano="
+ + q.mEvent.getEventTimeNano() + " id=0x"
+ + Integer.toHexString(q.mEvent.getId()));
}
+ try {
+ if (mInputEventConsistencyVerifier != null) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "verifyEventConsistency");
+ try {
+ mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ }
- if (q.mEvent instanceof KeyEvent) {
- mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
- }
+ InputStage stage;
+ if (q.shouldSendToSynthesizer()) {
+ stage = mSyntheticInputStage;
+ } else {
+ stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
+ }
- if (stage != null) {
- handleWindowFocusChanged();
- stage.deliver(q);
- } else {
- finishInputEvent(q);
+ if (q.mEvent instanceof KeyEvent) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "preDispatchToUnhandledKeyManager");
+ try {
+ mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ }
+
+ if (stage != null) {
+ handleWindowFocusChanged();
+ stage.deliver(q);
+ } else {
+ finishInputEvent(q);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
private void finishInputEvent(QueuedInputEvent q) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
- q.mEvent.getSequenceNumber());
+ q.mEvent.getId());
if (q.mReceiver != null) {
boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
@@ -7721,7 +8129,9 @@ public final class ViewRootImpl implements ViewParent,
}
void scheduleConsumeBatchedInput() {
- if (!mConsumeBatchedInputScheduled) {
+ // If anything is currently scheduled to consume batched input then there's no point in
+ // scheduling it again.
+ if (!mConsumeBatchedInputScheduled && !mConsumeBatchedInputImmediatelyScheduled) {
mConsumeBatchedInputScheduled = true;
mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
mConsumedBatchedInputRunnable, null);
@@ -7744,22 +8154,15 @@ public final class ViewRootImpl implements ViewParent,
}
}
- void doConsumeBatchedInput(long frameTimeNanos) {
- if (mConsumeBatchedInputScheduled) {
- mConsumeBatchedInputScheduled = false;
- if (mInputEventReceiver != null) {
- if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
- && frameTimeNanos != -1) {
- // If we consumed a batch here, we want to go ahead and schedule the
- // consumption of batched input events on the next frame. Otherwise, we would
- // wait until we have more input events pending and might get starved by other
- // things occurring in the process. If the frame time is -1, however, then
- // we're in a non-batching mode, so there's no need to schedule this.
- scheduleConsumeBatchedInput();
- }
- }
- doProcessInputEvents();
+ boolean doConsumeBatchedInput(long frameTimeNanos) {
+ final boolean consumedBatches;
+ if (mInputEventReceiver != null) {
+ consumedBatches = mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos);
+ } else {
+ consumedBatches = false;
}
+ doProcessInputEvents();
+ return consumedBatches;
}
final class TraversalRunnable implements Runnable {
@@ -7802,12 +8205,26 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
- public void onBatchedInputEventPending() {
- if (mUnbufferedInputDispatch) {
- super.onBatchedInputEventPending();
- } else {
- scheduleConsumeBatchedInput();
+ public void onBatchedInputEventPending(int source) {
+ // mStopped: There will be no more choreographer callbacks if we are stopped,
+ // so we must consume all input immediately to prevent ANR
+ final boolean unbuffered = mUnbufferedInputDispatch
+ || (source & mUnbufferedInputSource) != SOURCE_CLASS_NONE
+ || mStopped;
+ if (unbuffered) {
+ if (mConsumeBatchedInputScheduled) {
+ unscheduleConsumeBatchedInput();
+ }
+ // Consume event immediately if unbuffered input dispatch has been requested.
+ consumeBatchedInputEvents(-1);
+ return;
}
+ scheduleConsumeBatchedInput();
+ }
+
+ @Override
+ public void onFocusEvent(boolean hasFocus, boolean inTouchMode) {
+ windowFocusChanged(hasFocus, inTouchMode);
}
@Override
@@ -7821,7 +8238,14 @@ public final class ViewRootImpl implements ViewParent,
final class ConsumeBatchedInputRunnable implements Runnable {
@Override
public void run() {
- doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
+ mConsumeBatchedInputScheduled = false;
+ if (doConsumeBatchedInput(mChoreographer.getFrameTimeNanos())) {
+ // If we consumed a batch here, we want to go ahead and schedule the
+ // consumption of batched input events on the next frame. Otherwise, we would
+ // wait until we have more input events pending and might get starved by other
+ // things occurring in the process.
+ scheduleConsumeBatchedInput();
+ }
}
}
final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
@@ -7831,6 +8255,7 @@ public final class ViewRootImpl implements ViewParent,
final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
@Override
public void run() {
+ mConsumeBatchedInputImmediatelyScheduled = false;
doConsumeBatchedInput(-1);
}
}
@@ -8065,6 +8490,7 @@ public final class ViewRootImpl implements ViewParent,
mHandler.sendMessage(msg);
}
+ // TODO(118118435): Remove this after migration
public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
int localValue, int localChanges) {
SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
@@ -8440,6 +8866,131 @@ public final class ViewRootImpl implements ViewParent,
return false;
}
+ /**
+ * Adds a scroll capture callback to this window.
+ *
+ * @param callback the callback to add
+ */
+ public void addScrollCaptureCallback(ScrollCaptureCallback callback) {
+ if (mRootScrollCaptureCallbacks == null) {
+ mRootScrollCaptureCallbacks = new HashSet<>();
+ }
+ mRootScrollCaptureCallbacks.add(callback);
+ }
+
+ /**
+ * Removes a scroll capture callback from this window.
+ *
+ * @param callback the callback to remove
+ */
+ public void removeScrollCaptureCallback(ScrollCaptureCallback callback) {
+ if (mRootScrollCaptureCallbacks != null) {
+ mRootScrollCaptureCallbacks.remove(callback);
+ if (mRootScrollCaptureCallbacks.isEmpty()) {
+ mRootScrollCaptureCallbacks = null;
+ }
+ }
+ }
+
+ /**
+ * Dispatches a scroll capture request to the view hierarchy on the ui thread.
+ *
+ * @param controller the controller to receive replies
+ */
+ public void dispatchScrollCaptureRequest(@NonNull IScrollCaptureController controller) {
+ mHandler.obtainMessage(MSG_REQUEST_SCROLL_CAPTURE, controller).sendToTarget();
+ }
+
+ /**
+ * Collect and include any ScrollCaptureCallback instances registered with the window.
+ *
+ * @see #addScrollCaptureCallback(ScrollCaptureCallback)
+ * @param targets the search queue for targets
+ */
+ private void collectRootScrollCaptureTargets(Queue<ScrollCaptureTarget> targets) {
+ for (ScrollCaptureCallback cb : mRootScrollCaptureCallbacks) {
+ // Add to the list for consideration
+ Point offset = new Point(mView.getLeft(), mView.getTop());
+ Rect rect = new Rect(0, 0, mView.getWidth(), mView.getHeight());
+ targets.add(new ScrollCaptureTarget(mView, rect, offset, cb));
+ }
+ }
+
+ /**
+ * Handles an inbound request for scroll capture from the system. If a client is not already
+ * active, a search will be dispatched through the view tree to locate scrolling content.
+ * <p>
+ * Either {@link IScrollCaptureController#onClientConnected(IScrollCaptureClient, Rect,
+ * Point)} or {@link IScrollCaptureController#onClientUnavailable()} will be returned
+ * depending on the results of the search.
+ *
+ * @param controller the interface to the system controller
+ * @see ScrollCaptureTargetResolver
+ */
+ private void handleScrollCaptureRequest(@NonNull IScrollCaptureController controller) {
+ LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+
+ // Window (root) level callbacks
+ collectRootScrollCaptureTargets(targetList);
+
+ // Search through View-tree
+ View rootView = getView();
+ Point point = new Point();
+ Rect rect = new Rect(0, 0, rootView.getWidth(), rootView.getHeight());
+ getChildVisibleRect(rootView, rect, point);
+ rootView.dispatchScrollCaptureSearch(rect, point, targetList);
+
+ // No-op path. Scroll capture not offered for this window.
+ if (targetList.isEmpty()) {
+ dispatchScrollCaptureSearchResult(controller, null);
+ return;
+ }
+
+ // Request scrollBounds from each of the targets.
+ // Continues with the consumer once all responses are consumed, or the timeout expires.
+ ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetList);
+ resolver.start(mHandler, 1000,
+ (selected) -> dispatchScrollCaptureSearchResult(controller, selected));
+ }
+
+ /** Called by {@link #handleScrollCaptureRequest} when a result is returned */
+ private void dispatchScrollCaptureSearchResult(
+ @NonNull IScrollCaptureController controller,
+ @Nullable ScrollCaptureTarget selectedTarget) {
+
+ // If timeout or no eligible targets found.
+ if (selectedTarget == null) {
+ try {
+ if (DEBUG_SCROLL_CAPTURE) {
+ Log.d(TAG, "scrollCaptureSearch returned no targets available.");
+ }
+ controller.onClientUnavailable();
+ } catch (RemoteException e) {
+ if (DEBUG_SCROLL_CAPTURE) {
+ Log.w(TAG, "Failed to notify controller of scroll capture search result.", e);
+ }
+ }
+ return;
+ }
+
+ // Create a client instance and return it to the caller
+ mScrollCaptureClient = new ScrollCaptureClient(selectedTarget, controller);
+ try {
+ if (DEBUG_SCROLL_CAPTURE) {
+ Log.d(TAG, "scrollCaptureSearch returning client: " + getScrollCaptureClient());
+ }
+ controller.onClientConnected(
+ mScrollCaptureClient,
+ selectedTarget.getScrollBounds(),
+ selectedTarget.getPositionInWindow());
+ } catch (RemoteException e) {
+ if (DEBUG_SCROLL_CAPTURE) {
+ Log.w(TAG, "Failed to notify controller of scroll capture search result.", e);
+ }
+ mScrollCaptureClient.disconnect();
+ mScrollCaptureClient = null;
+ }
+ }
private void reportNextDraw() {
if (mReportNextDraw == false) {
@@ -8533,15 +9084,15 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
- public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+ public void resized(Rect frame, Rect contentInsets,
+ Rect visibleInsets, Rect stableInsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId,
DisplayCutout.ParcelableWrapper displayCutout) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
- viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
- visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
+ viewAncestor.dispatchResized(frame, contentInsets,
+ visibleInsets, stableInsets, reportDraw, mergedConfiguration,
backDropFrame, forceLayout, alwaysConsumeSystemBars, displayId,
displayCutout);
}
@@ -8573,6 +9124,22 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
+ public void showInsets(@InsetsType int types, boolean fromIme) {
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.showInsets(types, fromIme);
+ }
+ }
+
+ @Override
+ public void hideInsets(@InsetsType int types, boolean fromIme) {
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.hideInsets(types, fromIme);
+ }
+ }
+
+ @Override
public void moved(int newX, int newY) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
@@ -8655,7 +9222,7 @@ public final class ViewRootImpl implements ViewParent,
@Override
public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
- boolean sync) {
+ float zoom, boolean sync) {
if (sync) {
try {
mWindowSession.wallpaperOffsetsComplete(asBinder());
@@ -8726,6 +9293,13 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ @Override
+ public void requestScrollCapture(IScrollCaptureController controller) {
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchScrollCaptureRequest(controller);
+ }
+ }
}
public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
@@ -8813,6 +9387,21 @@ public final class ViewRootImpl implements ViewParent,
}
/**
+ * @return Returns a token used to identify the windows input channel.
+ */
+ public IBinder getInputToken() {
+ if (mInputEventReceiver == null) {
+ return null;
+ }
+ return mInputEventReceiver.getToken();
+ }
+
+ @NonNull
+ public IBinder getWindowToken() {
+ return mAttachInfo.mWindowToken;
+ }
+
+ /**
* Class for managing the accessibility interaction connection
* based on the global accessibility state.
*/
@@ -8829,6 +9418,10 @@ public final class ViewRootImpl implements ViewParent,
focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
}
}
+ if (mAttachInfo.mLeashedParentToken != null) {
+ mAccessibilityManager.associateEmbeddedHierarchy(
+ mAttachInfo.mLeashedParentToken, mLeashToken);
+ }
} else {
ensureNoConnection();
mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
@@ -8841,6 +9434,7 @@ public final class ViewRootImpl implements ViewParent,
if (!registered) {
mAttachInfo.mAccessibilityWindowId =
mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
+ mLeashToken,
mContext.getPackageName(),
new AccessibilityInteractionConnection(ViewRootImpl.this));
}
@@ -9027,6 +9621,18 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ /**
+ * Gets an accessibility embedded connection interface for this ViewRootImpl.
+ * @hide
+ */
+ public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() {
+ if (mAccessibilityEmbeddedConnection == null) {
+ mAccessibilityEmbeddedConnection = new AccessibilityEmbeddedConnection(
+ ViewRootImpl.this);
+ }
+ return mAccessibilityEmbeddedConnection;
+ }
+
private class SendWindowContentChangedAccessibilityEvent implements Runnable {
private int mChangeTypes = 0;
@@ -9195,4 +9801,61 @@ public final class ViewRootImpl implements ViewParent,
return false;
}
}
+
+ void setUseBLASTSyncTransaction() {
+ mNextDrawUseBLASTSyncTransaction = true;
+ }
+
+ private void finishBLASTSync(boolean apply) {
+ mSendNextFrameToWm = false;
+ if (mNextReportConsumeBLAST) {
+ mNextReportConsumeBLAST = false;
+
+ if (apply) {
+ mRtBLASTSyncTransaction.apply();
+ } else {
+ mSurfaceChangedTransaction.merge(mRtBLASTSyncTransaction);
+ }
+ }
+ }
+
+ SurfaceControl.Transaction getBLASTSyncTransaction() {
+ return mRtBLASTSyncTransaction;
+ }
+
+ /**
+ * @hide
+ */
+ public SurfaceControl getRenderSurfaceControl() {
+ if (useBLAST()) {
+ return mBlastSurfaceControl;
+ } else {
+ return mSurfaceControl;
+ }
+ }
+
+ @Override
+ public void onDescendantUnbufferedRequested() {
+ mUnbufferedInputSource = mView.mUnbufferedInputSource;
+ }
+
+ /**
+ * Force disabling use of the BLAST adapter regardless of the system
+ * flag. Needs to be called before addView.
+ */
+ void forceDisableBLAST() {
+ mForceDisableBLAST = true;
+ }
+
+ boolean useBLAST() {
+ return mUseBLASTAdapter && !mForceDisableBLAST;
+ }
+
+ /**
+ * Returns true if we are about to or currently processing a draw directed
+ * in to a BLAST transaction.
+ */
+ boolean isDrawingToBLASTTransaction() {
+ return mNextReportConsumeBLAST;
+ }
}