diff options
Diffstat (limited to 'libs')
30 files changed, 364 insertions, 76 deletions
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml index 69fc25a378cf..06aaad7d65ca 100644 --- a/libs/WindowManager/Shell/res/values-nl/strings.xml +++ b/libs/WindowManager/Shell/res/values-nl/strings.xml @@ -45,10 +45,10 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bovenste scherm 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Bovenste scherm 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Onderste scherm op volledig scherm"</string> - <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Bediening met één hand gebruiken"</string> + <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Bediening met 1 hand gebruiken"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Als je wilt afsluiten, swipe je omhoog vanaf de onderkant van het scherm of tik je ergens boven de app"</string> - <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Bediening met één hand starten"</string> - <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Bediening met één hand afsluiten"</string> + <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Bediening met 1 hand starten"</string> + <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Bediening met 1 hand afsluiten"</string> <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Instellingen voor <xliff:g id="APP_NAME">%1$s</xliff:g>-bubbels"</string> <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Overloop"</string> <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Weer toevoegen aan stack"</string> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java index cb27ad9f58f5..f565724813eb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java @@ -159,6 +159,14 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged } } + private void dispatchImeControlTargetChanged(int displayId, boolean controlling) { + synchronized (mPositionProcessors) { + for (ImePositionProcessor pp : mPositionProcessors) { + pp.onImeControlTargetChanged(displayId, controlling); + } + } + } + private void dispatchVisibilityChanged(int displayId, boolean isShowing) { synchronized (mPositionProcessors) { for (ImePositionProcessor pp : mPositionProcessors) { @@ -237,42 +245,52 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged protected void insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls) { insetsChanged(insetsState); + InsetsSourceControl imeSourceControl = null; if (activeControls != null) { for (InsetsSourceControl activeControl : activeControls) { if (activeControl == null) { continue; } if (activeControl.getType() == InsetsState.ITYPE_IME) { - final Point lastSurfacePosition = mImeSourceControl != null - ? mImeSourceControl.getSurfacePosition() : null; - final boolean positionChanged = - !activeControl.getSurfacePosition().equals(lastSurfacePosition); - final boolean leashChanged = - !haveSameLeash(mImeSourceControl, activeControl); - final InsetsSourceControl lastImeControl = mImeSourceControl; - mImeSourceControl = activeControl; - if (mAnimation != null) { - if (positionChanged) { - startAnimation(mImeShowing, true /* forceRestart */); - } - } else { - if (leashChanged) { - applyVisibilityToLeash(); - } - if (!mImeShowing) { - removeImeSurface(); - } - } - if (lastImeControl != null) { - lastImeControl.release(SurfaceControl::release); - } + imeSourceControl = activeControl; + } + } + } + + final boolean hadImeSourceControl = mImeSourceControl != null; + final boolean hasImeSourceControl = imeSourceControl != null; + if (hadImeSourceControl != hasImeSourceControl) { + dispatchImeControlTargetChanged(mDisplayId, hasImeSourceControl); + } + + if (hasImeSourceControl) { + final Point lastSurfacePosition = mImeSourceControl != null + ? mImeSourceControl.getSurfacePosition() : null; + final boolean positionChanged = + !imeSourceControl.getSurfacePosition().equals(lastSurfacePosition); + final boolean leashChanged = + !haveSameLeash(mImeSourceControl, imeSourceControl); + if (mAnimation != null) { + if (positionChanged) { + startAnimation(mImeShowing, true /* forceRestart */); + } + } else { + if (leashChanged) { + applyVisibilityToLeash(imeSourceControl); } + if (!mImeShowing) { + removeImeSurface(); + } + } + if (mImeSourceControl != null) { + mImeSourceControl.release(SurfaceControl::release); } + mImeSourceControl = imeSourceControl; } } - private void applyVisibilityToLeash() { - SurfaceControl leash = mImeSourceControl.getLeash(); + private void applyVisibilityToLeash(InsetsSourceControl imeSourceControl) { + SurfaceControl leash = imeSourceControl.getLeash(); if (leash != null) { SurfaceControl.Transaction t = mTransactionPool.acquire(); if (mImeShowing) { @@ -584,6 +602,15 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged } /** + * Called when the IME control target changed. So that the processor can restore its + * adjusted layout when the IME insets is not controlling by the current controller anymore. + * + * @param controlling indicates whether the current controller is controlling IME insets. + */ + default void onImeControlTargetChanged(int displayId, boolean controlling) { + } + + /** * Called when the IME visibility changed. * * @param isShowing {@code true} if the IME is shown. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index e42f511eb391..5b158d2063ba 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -366,6 +366,7 @@ public final class SplitLayout { private final int mDisplayId; + private boolean mImeShown; private int mYOffsetForIme; private float mDimValue1; private float mDimValue2; @@ -392,6 +393,7 @@ public final class SplitLayout { if (!mInitialized || imeTargetPosition == SPLIT_POSITION_UNDEFINED) return 0; mStartImeTop = showing ? hiddenTop : shownTop; mEndImeTop = showing ? shownTop : hiddenTop; + mImeShown = showing; // Update target dim values mLastDim1 = mDimValue1; @@ -414,7 +416,7 @@ public final class SplitLayout { mSplitWindowManager.setInteractive( !showing || imeTargetPosition == SPLIT_POSITION_UNDEFINED); - return 0; + return needOffset ? IME_ANIMATION_NO_ALPHA : 0; } @Override @@ -432,6 +434,17 @@ public final class SplitLayout { mSplitLayoutHandler.onBoundsChanging(SplitLayout.this); } + @Override + public void onImeControlTargetChanged(int displayId, boolean controlling) { + if (displayId != mDisplayId) return; + // Restore the split layout when wm-shell is not controlling IME insets anymore. + if (!controlling && mImeShown) { + reset(); + mSplitWindowManager.setInteractive(true); + mSplitLayoutHandler.onBoundsChanging(SplitLayout.this); + } + } + private int getTargetYOffset() { final int desireOffset = Math.abs(mEndImeTop - mStartImeTop); // Make sure to keep at least 30% visible for the top split. @@ -461,8 +474,10 @@ public final class SplitLayout { } private void reset() { - mYOffsetForIme = 0; - mDimValue1 = mDimValue2 = 0.0f; + mImeShown = false; + mYOffsetForIme = mLastYOffset = mTargetYOffset = 0; + mDimValue1 = mLastDim1 = mTargetDim1 = 0.0f; + mDimValue2 = mLastDim2 = mTargetDim2 = 0.0f; } /* Adjust bounds with IME offset. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java index 23171bb9575c..aced072c8c71 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java @@ -91,7 +91,6 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor private boolean mPaused = true; private boolean mPausedTargetAdjusted = false; - private boolean mAdjustedWhileHidden = false; DividerImeController(LegacySplitScreenTaskListener splits, TransactionPool pool, ShellExecutor mainExecutor, TaskOrganizer taskOrganizer) { @@ -123,7 +122,6 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor void reset() { mPaused = true; mPausedTargetAdjusted = false; - mAdjustedWhileHidden = false; mAnimation = null; mAdjusted = mTargetAdjusted = false; mImeWasShown = mTargetShown = false; @@ -140,6 +138,19 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor ? ADJUSTED_NONFOCUS_DIM : 0.f; } + + @Override + public void onImeControlTargetChanged(int displayId, boolean controlling) { + // Restore the split layout when wm-shell is not controlling IME insets anymore. + if (!controlling && mTargetShown) { + mPaused = false; + mTargetAdjusted = mTargetShown = false; + mTargetPrimaryDim = mTargetSecondaryDim = 0.f; + updateImeAdjustState(true /* force */); + startAsyncAnimation(); + } + } + @Override @ImeAnimationFlags public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop, @@ -151,8 +162,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor mShownTop = shownTop; mTargetShown = imeShouldShow; mSecondaryHasFocus = getSecondaryHasFocus(displayId); - final boolean splitIsVisible = !getView().isHidden(); - final boolean targetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus + final boolean targetAdjusted = imeShouldShow && mSecondaryHasFocus && !imeIsFloating && !getLayout().mDisplayLayout.isLandscape() && !mSplits.mSplitScreenController.isMinimized(); if (mLastAdjustTop < 0) { @@ -176,7 +186,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor } mTargetAdjusted = targetAdjusted; updateDimTargets(); - if (DEBUG) Slog.d(TAG, " ime starting. vis:" + splitIsVisible + " " + dumpState()); + if (DEBUG) Slog.d(TAG, " ime starting. " + dumpState()); if (mAnimation != null || (mImeWasShown && imeShouldShow && mTargetAdjusted != mAdjusted)) { // We need to animate adjustment independently of the IME position, so @@ -184,13 +194,8 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor // different split's editor has gained focus while the IME is still visible. startAsyncAnimation(); } - if (splitIsVisible) { - // If split is hidden, we don't want to trigger any relayouts that would cause the - // divider to show again. - updateImeAdjustState(); - } else { - mAdjustedWhileHidden = true; - } + updateImeAdjustState(); + return (mTargetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0; } @@ -256,11 +261,6 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor mSplits.mSplitScreenController.setAdjustedForIme(mTargetShown && !mPaused); } - public void updateAdjustForIme() { - updateImeAdjustState(mAdjustedWhileHidden); - mAdjustedWhileHidden = false; - } - @Override public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java index 261ff2f8de83..80ab166d0649 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java @@ -146,10 +146,8 @@ public class LegacySplitScreenController implements DisplayController.OnDisplays new LegacySplitDisplayLayout(mContext, displayLayout, mSplits); sdl.rotateTo(toRotation); mRotateSplitLayout = sdl; - final int position = isDividerVisible() - ? (mMinimized ? mView.mSnapTargetBeforeMinimized.position - : mView.getCurrentPosition()) - // snap resets to middle target when not in split-mode + // snap resets to middle target when not minimized and rotation changed. + final int position = mMinimized ? mView.mSnapTargetBeforeMinimized.position : sdl.getSnapAlgorithm().getMiddleTarget().position; DividerSnapAlgorithm snap = sdl.getSnapAlgorithm(); final DividerSnapAlgorithm.SnapTarget target = @@ -229,9 +227,6 @@ public class LegacySplitScreenController implements DisplayController.OnDisplays return; } mView.setHidden(showing); - if (!showing) { - mImePositionProcessor.updateAdjustForIme(); - } mIsKeyguardShowing = showing; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java index 046c32071358..a4b866aa3f5e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java @@ -19,6 +19,7 @@ package com.android.wm.shell.pip; import static android.util.TypedValue.COMPLEX_UNIT_DIP; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.PictureInPictureParams; import android.content.Context; import android.content.pm.ActivityInfo; @@ -454,6 +455,56 @@ public class PipBoundsAlgorithm { } /** + * @return the normal bounds adjusted so that they fit the menu actions. + */ + public Rect adjustNormalBoundsToFitMenu(@NonNull Rect normalBounds, + @Nullable Size minMenuSize) { + if (minMenuSize == null) { + return normalBounds; + } + if (normalBounds.width() >= minMenuSize.getWidth() + && normalBounds.height() >= minMenuSize.getHeight()) { + // The normal bounds can fit the menu as is, no need to adjust the bounds. + return normalBounds; + } + final Rect adjustedNormalBounds = new Rect(); + final boolean needsWidthAdj = minMenuSize.getWidth() > normalBounds.width(); + final boolean needsHeightAdj = minMenuSize.getHeight() > normalBounds.height(); + final int adjWidth; + final int adjHeight; + if (needsWidthAdj && needsHeightAdj) { + // Both the width and the height are too small - find the edge that needs the larger + // adjustment and scale that edge. The other edge will scale beyond the minMenuSize + // when the aspect ratio is applied. + final float widthScaleFactor = + ((float) (minMenuSize.getWidth())) / ((float) (normalBounds.width())); + final float heightScaleFactor = + ((float) (minMenuSize.getHeight())) / ((float) (normalBounds.height())); + if (widthScaleFactor > heightScaleFactor) { + adjWidth = minMenuSize.getWidth(); + adjHeight = Math.round(adjWidth / mPipBoundsState.getAspectRatio()); + } else { + adjHeight = minMenuSize.getHeight(); + adjWidth = Math.round(adjHeight * mPipBoundsState.getAspectRatio()); + } + } else if (needsWidthAdj) { + // Width is too small - use the min menu size width instead. + adjWidth = minMenuSize.getWidth(); + adjHeight = Math.round(adjWidth / mPipBoundsState.getAspectRatio()); + } else { + // Height is too small - use the min menu size height instead. + adjHeight = minMenuSize.getHeight(); + adjWidth = Math.round(adjHeight * mPipBoundsState.getAspectRatio()); + } + adjustedNormalBounds.set(0, 0, adjWidth, adjHeight); + // Make sure the bounds conform to the aspect ratio and min edge size. + transformBoundsToAspectRatio(adjustedNormalBounds, + mPipBoundsState.getAspectRatio(), true /* useCurrentMinEdgeSize */, + true /* useCurrentSize */); + return adjustedNormalBounds; + } + + /** * Dumps internal states. */ public void dump(PrintWriter pw, String prefix) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index 324a6e27a242..f367cd608f37 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -722,6 +722,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) { mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY); } + + final PipAnimationController.PipTransitionAnimator animator = + mPipAnimationController.getCurrentAnimator(); + if (animator != null) { + animator.removeAllUpdateListeners(); + animator.removeAllListeners(); + animator.cancel(); + } } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java index f0bd8a2846ed..c816f18c2fc2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java @@ -246,10 +246,20 @@ public class PipResizeGestureHandler { } if (ev instanceof MotionEvent) { + MotionEvent mv = (MotionEvent) ev; + int action = mv.getActionMasked(); + final Rect pipBounds = mPipBoundsState.getBounds(); + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + if (!pipBounds.contains((int) mv.getRawX(), (int) mv.getRawY()) + && mPhonePipMenuController.isMenuVisible()) { + mPhonePipMenuController.hideMenu(); + } + } + if (mEnablePinchResize && mOngoingPinchToResize) { - onPinchResize((MotionEvent) ev); + onPinchResize(mv); } else if (mEnableDragCornerResize) { - onDragCornerResize((MotionEvent) ev); + onDragCornerResize(mv); } } } @@ -450,7 +460,6 @@ public class PipResizeGestureHandler { float x = ev.getX(); float y = ev.getY() - mOhmOffset; if (action == MotionEvent.ACTION_DOWN) { - final Rect currentPipBounds = mPipBoundsState.getBounds(); mLastResizeBounds.setEmpty(); mAllowGesture = isInValidSysUiState() && isWithinDragResizeRegion((int) x, (int) y); if (mAllowGesture) { @@ -458,11 +467,6 @@ public class PipResizeGestureHandler { mDownPoint.set(x, y); mDownBounds.set(mPipBoundsState.getBounds()); } - if (!currentPipBounds.contains((int) x, (int) y) - && mPhonePipMenuController.isMenuVisible()) { - mPhonePipMenuController.hideMenu(); - } - } else if (mAllowGesture) { switch (action) { case MotionEvent.ACTION_POINTER_DOWN: diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java index b1086c575f49..0bcd1a363eb6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java @@ -726,12 +726,17 @@ public class PipTouchHandler { } private void animateToNormalSize(Runnable callback) { + // Save the current bounds as the user-resize bounds. mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds()); - final Rect normalBounds = new Rect(mPipBoundsState.getNormalBounds()); + + final Size minMenuSize = mMenuController.getEstimatedMinMenuSize(); + final Rect normalBounds = mPipBoundsState.getNormalBounds(); + final Rect destBounds = mPipBoundsAlgorithm.adjustNormalBoundsToFitMenu(normalBounds, + minMenuSize); Rect restoredMovementBounds = new Rect(); - mPipBoundsAlgorithm.getMovementBounds(normalBounds, + mPipBoundsAlgorithm.getMovementBounds(destBounds, mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0); - mSavedSnapFraction = mMotionHelper.animateToExpandedState(normalBounds, + mSavedSnapFraction = mMotionHelper.animateToExpandedState(destBounds, mPipBoundsState.getMovementBounds(), restoredMovementBounds, callback); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java index 9986154b051d..4e477ca104dd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java @@ -85,7 +85,10 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener { } View iconView = view.getIconView(); - if (iconView == null || iconView.getBackground() == null) { + + // If the icon and the background are invisible, don't animate it + if (iconView == null || iconView.getLayoutParams().width == 0 + || iconView.getLayoutParams().height == 0) { mIconFadeOutDuration = 0; mIconStartAlpha = 0; mAppRevealDelay = 0; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java index df3fee043419..b09d0d89a6b9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java @@ -77,6 +77,13 @@ public class SplashscreenContentDrawer { // For example, an icon with the foreground 108*108 opaque pixels and it's background // also 108*108 pixels, then do not enlarge this icon if only need to show foreground icon. private static final float ENLARGE_FOREGROUND_ICON_THRESHOLD = (72f * 72f) / (108f * 108f); + + /** + * If the developer doesn't specify a background for the icon, we slightly scale it up. + * + * The background is either manually specified in the theme or the Adaptive Icon + * background is used if it's different from the window background. + */ private static final float NO_BACKGROUND_SCALE = 192f / 160; private final Context mContext; private final IconProvider mIconProvider; @@ -228,7 +235,7 @@ public class SplashscreenContentDrawer { attrs.mWindowBgColor = safeReturnAttrDefault((def) -> typedArray.getColor( R.styleable.Window_windowSplashScreenBackground, def), Color.TRANSPARENT); - attrs.mReplaceIcon = safeReturnAttrDefault((def) -> typedArray.getDrawable( + attrs.mSplashScreenIcon = safeReturnAttrDefault((def) -> typedArray.getDrawable( R.styleable.Window_windowSplashScreenAnimatedIcon), null); attrs.mAnimationDuration = safeReturnAttrDefault((def) -> typedArray.getInt( R.styleable.Window_windowSplashScreenAnimationDuration, def), 0); @@ -241,7 +248,7 @@ public class SplashscreenContentDrawer { if (DEBUG) { Slog.d(TAG, "window attributes color: " + Integer.toHexString(attrs.mWindowBgColor) - + " icon " + attrs.mReplaceIcon + " duration " + attrs.mAnimationDuration + + " icon " + attrs.mSplashScreenIcon + " duration " + attrs.mAnimationDuration + " brandImage " + attrs.mBrandingImage); } } @@ -250,7 +257,7 @@ public class SplashscreenContentDrawer { public static class SplashScreenWindowAttrs { private int mWindowBgResId = 0; private int mWindowBgColor = Color.TRANSPARENT; - private Drawable mReplaceIcon = null; + private Drawable mSplashScreenIcon = null; private Drawable mBrandingImage = null; private int mIconBgColor = Color.TRANSPARENT; private int mAnimationDuration = 0; @@ -287,10 +294,15 @@ public class SplashscreenContentDrawer { // empty splash screen case animationDuration = 0; mFinalIconSize = 0; - } else if (mTmpAttrs.mReplaceIcon != null) { + } else if (mTmpAttrs.mSplashScreenIcon != null) { // replaced icon, don't process - iconDrawable = mTmpAttrs.mReplaceIcon; + iconDrawable = mTmpAttrs.mSplashScreenIcon; animationDuration = mTmpAttrs.mAnimationDuration; + + // There is no background below the icon, so scale the icon up + if (mTmpAttrs.mIconBgColor == Color.TRANSPARENT) { + mFinalIconSize *= NO_BACKGROUND_SCALE; + } createIconDrawable(iconDrawable, false); } else { final float iconScale = (float) mIconSize / (float) mDefaultIconSize; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java index dae7055ede53..211941f44c8e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java @@ -162,6 +162,7 @@ public class SplashscreenIconDrawableFactory { @Override public void draw(Canvas canvas) { + canvas.clipPath(mMaskScaleOnly); if (mMaskScaleOnly != null) { canvas.drawPath(mMaskScaleOnly, mPaint); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java index a0c6d1138698..90f898aa09da 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java @@ -402,6 +402,64 @@ public class PipBoundsAlgorithmTest extends ShellTestCase { assertBoundsInclusionWithMargin("useDefaultBounds", defaultBounds, actualBounds); } + @Test + public void adjustNormalBoundsToFitMenu_alreadyFits() { + final Rect normalBounds = new Rect(0, 0, 400, 711); + final Size minMenuSize = new Size(396, 292); + mPipBoundsState.setAspectRatio( + ((float) normalBounds.width()) / ((float) normalBounds.height())); + + final Rect bounds = + mPipBoundsAlgorithm.adjustNormalBoundsToFitMenu(normalBounds, minMenuSize); + + assertEquals(normalBounds, bounds); + } + + @Test + public void adjustNormalBoundsToFitMenu_widthTooSmall() { + final Rect normalBounds = new Rect(0, 0, 297, 528); + final Size minMenuSize = new Size(396, 292); + mPipBoundsState.setAspectRatio( + ((float) normalBounds.width()) / ((float) normalBounds.height())); + + final Rect bounds = + mPipBoundsAlgorithm.adjustNormalBoundsToFitMenu(normalBounds, minMenuSize); + + assertEquals(minMenuSize.getWidth(), bounds.width()); + assertEquals(minMenuSize.getWidth() / mPipBoundsState.getAspectRatio(), + bounds.height(), 0.3f); + } + + @Test + public void adjustNormalBoundsToFitMenu_heightTooSmall() { + final Rect normalBounds = new Rect(0, 0, 400, 280); + final Size minMenuSize = new Size(396, 292); + mPipBoundsState.setAspectRatio( + ((float) normalBounds.width()) / ((float) normalBounds.height())); + + final Rect bounds = + mPipBoundsAlgorithm.adjustNormalBoundsToFitMenu(normalBounds, minMenuSize); + + assertEquals(minMenuSize.getHeight(), bounds.height()); + assertEquals(minMenuSize.getHeight() * mPipBoundsState.getAspectRatio(), + bounds.width(), 0.3f); + } + + @Test + public void adjustNormalBoundsToFitMenu_widthAndHeightTooSmall() { + final Rect normalBounds = new Rect(0, 0, 350, 280); + final Size minMenuSize = new Size(396, 292); + mPipBoundsState.setAspectRatio( + ((float) normalBounds.width()) / ((float) normalBounds.height())); + + final Rect bounds = + mPipBoundsAlgorithm.adjustNormalBoundsToFitMenu(normalBounds, minMenuSize); + + assertEquals(minMenuSize.getWidth(), bounds.width()); + assertEquals(minMenuSize.getWidth() / mPipBoundsState.getAspectRatio(), + bounds.height(), 0.3f); + } + private void overrideDefaultAspectRatio(float aspectRatio) { final TestableResources res = mContext.getOrCreateTestableResources(); res.addOverride( diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index 894b479c11db..eb5878d95561 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -133,6 +133,12 @@ public: } } + void onRemovedFromTree() { + if (mImpl) { + mImpl->onRemovedFromTree(); + } + } + [[nodiscard]] bool hasText() const { return mImpl && mImpl->hasText(); } @@ -172,6 +178,7 @@ private: return false; } void syncContents(const WebViewSyncData& data) { } + void onRemovedFromTree() { } void applyColorTransform(ColorTransform transform) { } }; @@ -298,6 +305,10 @@ public: apply([&](auto& it) { it.syncContents(data); }); } + void onRemovedFromTree() { + apply([&](auto& it) { it.onRemovedFromTree(); }); + } + [[nodiscard]] bool hasText() const { return apply([](const auto& it) -> auto { return it.hasText(); }); } diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index f0995c4f324b..b8fa55a18dac 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -84,6 +84,8 @@ float Properties::defaultSdrWhitePoint = 200.f; bool Properties::useHintManager = true; int Properties::targetCpuTimePercentage = 70; +bool Properties::enableWebViewOverlays = false; + StretchEffectBehavior Properties::stretchEffectBehavior = StretchEffectBehavior::ShaderHWUI; bool Properties::load() { @@ -137,6 +139,8 @@ bool Properties::load() { targetCpuTimePercentage = base::GetIntProperty(PROPERTY_TARGET_CPU_TIME_PERCENTAGE, 70); if (targetCpuTimePercentage <= 0 || targetCpuTimePercentage > 100) targetCpuTimePercentage = 70; + enableWebViewOverlays = base::GetBoolProperty(PROPERTY_WEBVIEW_OVERLAYS_ENABLED, false); + return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw); } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index f5fd0036f7be..7df6e2c92247 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -182,6 +182,11 @@ enum DebugLevel { */ #define PROPERTY_REDUCE_OPS_TASK_SPLITTING "renderthread.skia.reduceopstasksplitting" +/** + * Enable WebView Overlays feature. + */ +#define PROPERTY_WEBVIEW_OVERLAYS_ENABLED "debug.hwui.webview_overlays_enabled" + /////////////////////////////////////////////////////////////////////////////// // Misc /////////////////////////////////////////////////////////////////////////////// @@ -276,6 +281,8 @@ public: static bool useHintManager; static int targetCpuTimePercentage; + static bool enableWebViewOverlays; + static StretchEffectBehavior getStretchEffectBehavior() { return stretchEffectBehavior; } diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 44c335f6adb3..0c422df65881 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -18,6 +18,7 @@ #include "DamageAccumulator.h" #include "Debug.h" +#include "Properties.h" #include "TreeInfo.h" #include "VectorDrawable.h" #include "private/hwui/WebViewFunctor.h" @@ -473,6 +474,9 @@ void RenderNode::decParentRefCount(TreeObserver& observer, TreeInfo* info) { } void RenderNode::onRemovedFromTree(TreeInfo* info) { + if (Properties::enableWebViewOverlays && mDisplayList) { + mDisplayList.onRemovedFromTree(); + } destroyHardwareResources(info); } diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp index 92e20c477669..df4101109a18 100644 --- a/libs/hwui/WebViewFunctorManager.cpp +++ b/libs/hwui/WebViewFunctorManager.cpp @@ -108,6 +108,13 @@ void WebViewFunctor::sync(const WebViewSyncData& syncData) const { mCallbacks.onSync(mFunctor, mData, syncData); } +void WebViewFunctor::onRemovedFromTree() { + ATRACE_NAME("WebViewFunctor::onRemovedFromTree"); + if (mSurfaceControl) { + removeOverlays(); + } +} + void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) { ATRACE_NAME("WebViewFunctor::drawGl"); if (!mHasContext) { @@ -121,12 +128,19 @@ void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) { .mergeTransaction = currentFunctor.mergeTransaction, }; - if (!drawInfo.isLayer) { + if (Properties::enableWebViewOverlays && !drawInfo.isLayer) { renderthread::CanvasContext* activeContext = renderthread::CanvasContext::getActiveContext(); if (activeContext != nullptr) { ASurfaceControl* rootSurfaceControl = activeContext->getSurfaceControl(); - if (rootSurfaceControl) overlayParams.overlaysMode = OverlaysMode::Enabled; + if (rootSurfaceControl) { + overlayParams.overlaysMode = OverlaysMode::Enabled; + int32_t rgid = activeContext->getSurfaceControlGenerationId(); + if (mParentSurfaceControlGenerationId != rgid) { + reparentSurfaceControl(rootSurfaceControl); + mParentSurfaceControlGenerationId = rgid; + } + } } } @@ -178,6 +192,7 @@ void WebViewFunctor::removeOverlays() { ScopedCurrentFunctor currentFunctor(this); mCallbacks.removeOverlays(mFunctor, mData, currentFunctor.mergeTransaction); if (mSurfaceControl) { + reparentSurfaceControl(nullptr); auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions(); funcs.releaseFunc(mSurfaceControl); mSurfaceControl = nullptr; @@ -195,6 +210,7 @@ ASurfaceControl* WebViewFunctor::getSurfaceControl() { LOG_ALWAYS_FATAL_IF(rootSurfaceControl == nullptr, "Null root surface control!"); auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions(); + mParentSurfaceControlGenerationId = activeContext->getSurfaceControlGenerationId(); mSurfaceControl = funcs.createFunc(rootSurfaceControl, "Webview Overlay SurfaceControl"); ASurfaceTransaction* transaction = funcs.transactionCreateFunc(); activeContext->prepareSurfaceControlForWebview(); @@ -209,15 +225,29 @@ ASurfaceControl* WebViewFunctor::getSurfaceControl() { void WebViewFunctor::mergeTransaction(ASurfaceTransaction* transaction) { ATRACE_NAME("WebViewFunctor::mergeTransaction"); if (transaction == nullptr) return; + bool done = false; renderthread::CanvasContext* activeContext = renderthread::CanvasContext::getActiveContext(); - LOG_ALWAYS_FATAL_IF(activeContext == nullptr, "Null active canvas context!"); - bool done = activeContext->mergeTransaction(transaction, mSurfaceControl); + // activeContext might be null when called from mCallbacks.removeOverlays() + if (activeContext != nullptr) { + done = activeContext->mergeTransaction(transaction, mSurfaceControl); + } if (!done) { auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions(); funcs.transactionApplyFunc(transaction); } } +void WebViewFunctor::reparentSurfaceControl(ASurfaceControl* parent) { + ATRACE_NAME("WebViewFunctor::reparentSurfaceControl"); + if (mSurfaceControl == nullptr) return; + + auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions(); + ASurfaceTransaction* transaction = funcs.transactionCreateFunc(); + funcs.transactionReparentFunc(transaction, mSurfaceControl, parent); + mergeTransaction(transaction); + funcs.transactionDeleteFunc(transaction); +} + WebViewFunctorManager& WebViewFunctorManager::instance() { static WebViewFunctorManager sInstance; return sInstance; diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h index a84cda550567..f28f310993ec 100644 --- a/libs/hwui/WebViewFunctorManager.h +++ b/libs/hwui/WebViewFunctorManager.h @@ -58,6 +58,8 @@ public: void removeOverlays() { mReference.removeOverlays(); } + void onRemovedFromTree() { mReference.onRemovedFromTree(); } + private: friend class WebViewFunctor; @@ -74,6 +76,7 @@ public: void postDrawVk(); void destroyContext(); void removeOverlays(); + void onRemovedFromTree(); ASurfaceControl* getSurfaceControl(); void mergeTransaction(ASurfaceTransaction* transaction); @@ -85,12 +88,16 @@ public: } private: + void reparentSurfaceControl(ASurfaceControl* parent); + +private: WebViewFunctorCallbacks mCallbacks; void* const mData; int mFunctor; RenderMode mMode; bool mHasContext = false; bool mCreatedHandle = false; + int32_t mParentSurfaceControlGenerationId = 0; ASurfaceControl* mSurfaceControl = nullptr; }; diff --git a/libs/hwui/canvas/CanvasOpBuffer.cpp b/libs/hwui/canvas/CanvasOpBuffer.cpp index 6089c572b0d5..336c5d8dab35 100644 --- a/libs/hwui/canvas/CanvasOpBuffer.cpp +++ b/libs/hwui/canvas/CanvasOpBuffer.cpp @@ -46,6 +46,10 @@ void CanvasOpBuffer::syncContents(const WebViewSyncData& data) { LOG_ALWAYS_FATAL("TODO"); } +void CanvasOpBuffer::onRemovedFromTree() { + LOG_ALWAYS_FATAL("TODO"); +} + void CanvasOpBuffer::applyColorTransform(ColorTransform transform) { LOG_ALWAYS_FATAL("TODO"); } diff --git a/libs/hwui/canvas/CanvasOpBuffer.h b/libs/hwui/canvas/CanvasOpBuffer.h index af797ca8288b..529546d5c49c 100644 --- a/libs/hwui/canvas/CanvasOpBuffer.h +++ b/libs/hwui/canvas/CanvasOpBuffer.h @@ -100,6 +100,7 @@ public: TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn); void syncContents(const WebViewSyncData& data); + void onRemovedFromTree(); void applyColorTransform(ColorTransform transform); [[nodiscard]] bool isEmpty() const { return !mHas.content; } diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp index 4d31cd90d40f..ef3a11c13469 100644 --- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp @@ -933,6 +933,11 @@ static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, job env->ReleaseStringUTFChars(skiaDiskCachePath, skiaCacheArray); } +static jboolean android_view_ThreadedRenderer_isWebViewOverlaysEnabled(JNIEnv* env, jobject clazz) { + // this value is valid only after loadSystemProperties() is called + return Properties::enableWebViewOverlays; +} + // ---------------------------------------------------------------------------- // JNI Glue // ---------------------------------------------------------------------------- @@ -1025,6 +1030,8 @@ static const JNINativeMethod gMethods[] = { (void*)android_view_ThreadedRenderer_setDisplayDensityDpi}, {"nInitDisplayInfo", "(IIFIJJ)V", (void*)android_view_ThreadedRenderer_initDisplayInfo}, {"preload", "()V", (void*)android_view_ThreadedRenderer_preload}, + {"isWebViewOverlaysEnabled", "()Z", + (void*)android_view_ThreadedRenderer_isWebViewOverlaysEnabled}, }; static JavaVM* mJvm = nullptr; diff --git a/libs/hwui/pipeline/skia/FunctorDrawable.h b/libs/hwui/pipeline/skia/FunctorDrawable.h index 988a896b6267..9bbd0a92600b 100644 --- a/libs/hwui/pipeline/skia/FunctorDrawable.h +++ b/libs/hwui/pipeline/skia/FunctorDrawable.h @@ -44,6 +44,10 @@ public: mWebViewHandle->sync(data); } + virtual void onRemovedFromTree() { + mWebViewHandle->onRemovedFromTree(); + } + protected: virtual SkRect onGetBounds() override { return mBounds; } diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index 3498f715b455..fcfc4f82abed 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -47,6 +47,12 @@ void SkiaDisplayList::syncContents(const WebViewSyncData& data) { } } +void SkiaDisplayList::onRemovedFromTree() { + for (auto& functor : mChildFunctors) { + functor->onRemovedFromTree(); + } +} + bool SkiaDisplayList::reuseDisplayList(RenderNode* node) { reset(); node->attachAvailableList(this); diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 90e9bc6a1a28..2a677344b7b2 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -111,6 +111,13 @@ public: */ void syncContents(const WebViewSyncData& data); + /** + * ONLY to be called by RenderNode::onRemovedFromTree so that we can notify any + * contained VectorDrawables or GLFunctors. + * + */ + void onRemovedFromTree(); + void applyColorTransform(ColorTransform transform) { mDisplayList.applyColorTransform(transform); } diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 5462623e75ff..44a6e4354608 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -59,6 +59,10 @@ void SkiaPipeline::onDestroyHardwareResources() { } bool SkiaPipeline::pinImages(std::vector<SkImage*>& mutableImages) { + if (!mRenderThread.getGrContext()) { + ALOGD("Trying to pin an image with an invalid GrContext"); + return false; + } for (SkImage* image : mutableImages) { if (SkImage_pinAsTexture(image, mRenderThread.getGrContext())) { mPinnedImages.emplace_back(sk_ref_sp(image)); diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 0c9711ba8025..81cee6103d22 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -201,6 +201,7 @@ void CanvasContext::setSurfaceControl(ASurfaceControl* surfaceControl) { funcs.releaseFunc(mSurfaceControl); } mSurfaceControl = surfaceControl; + mSurfaceControlGenerationId++; mExpectSurfaceStats = surfaceControl != nullptr; if (mSurfaceControl != nullptr) { funcs.acquireFunc(mSurfaceControl); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 3279ccb8e597..85af3e4fb0b6 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -110,6 +110,7 @@ public: GrDirectContext* getGrContext() const { return mRenderThread.getGrContext(); } ASurfaceControl* getSurfaceControl() const { return mSurfaceControl; } + int32_t getSurfaceControlGenerationId() const { return mSurfaceControlGenerationId; } // Won't take effect until next EGLSurface creation void setSwapBehavior(SwapBehavior swapBehavior); @@ -253,6 +254,9 @@ private: // The SurfaceControl reference is passed from ViewRootImpl, can be set to // NULL to remove the reference ASurfaceControl* mSurfaceControl = nullptr; + // id to track surface control changes and WebViewFunctor uses it to determine + // whether reparenting is needed + int32_t mSurfaceControlGenerationId = 0; // stopped indicates the CanvasContext will reject actual redraw operations, // and defer repaint until it is un-stopped bool mStopped = false; diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 524407d2b9b0..f83c0a4926f9 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -98,6 +98,10 @@ ASurfaceControlFunctions::ASurfaceControlFunctions() { LOG_ALWAYS_FATAL_IF(transactionApplyFunc == nullptr, "Failed to find required symbol ASurfaceTransaction_apply!"); + transactionReparentFunc = (AST_reparent)dlsym(handle_, "ASurfaceTransaction_reparent"); + LOG_ALWAYS_FATAL_IF(transactionReparentFunc == nullptr, + "Failed to find required symbol transactionReparentFunc!"); + transactionSetVisibilityFunc = (AST_setVisibility)dlsym(handle_, "ASurfaceTransaction_setVisibility"); LOG_ALWAYS_FATAL_IF(transactionSetVisibilityFunc == nullptr, diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index c5e3746587b8..05d225b856db 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -94,6 +94,9 @@ typedef uint64_t (*ASCStats_getFrameNumber)(ASurfaceControlStats* stats); typedef ASurfaceTransaction* (*AST_create)(); typedef void (*AST_delete)(ASurfaceTransaction* transaction); typedef void (*AST_apply)(ASurfaceTransaction* transaction); +typedef void (*AST_reparent)(ASurfaceTransaction* aSurfaceTransaction, + ASurfaceControl* aSurfaceControl, + ASurfaceControl* newParentASurfaceControl); typedef void (*AST_setVisibility)(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, int8_t visibility); typedef void (*AST_setZOrder)(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, @@ -113,6 +116,7 @@ struct ASurfaceControlFunctions { AST_create transactionCreateFunc; AST_delete transactionDeleteFunc; AST_apply transactionApplyFunc; + AST_reparent transactionReparentFunc; AST_setVisibility transactionSetVisibilityFunc; AST_setZOrder transactionSetZOrderFunc; }; |