Loading api/current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -55583,10 +55583,12 @@ package android.view { } public interface WindowInsetsController { method public void addOnControllableInsetsChangedListener(@NonNull android.view.WindowInsetsController.OnControllableInsetsChangedListener); method @NonNull public android.os.CancellationSignal controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener); method public int getSystemBarsAppearance(); method public int getSystemBarsBehavior(); method public void hide(int); method public void removeOnControllableInsetsChangedListener(@NonNull android.view.WindowInsetsController.OnControllableInsetsChangedListener); method public void setSystemBarsAppearance(int, int); method public void setSystemBarsBehavior(int); method public void show(int); Loading @@ -55597,6 +55599,10 @@ package android.view { field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2 } public static interface WindowInsetsController.OnControllableInsetsChangedListener { method public void onControllableInsetsChanged(@NonNull android.view.WindowInsetsController, int); } public interface WindowManager extends android.view.ViewManager { method @NonNull public default android.view.WindowMetrics getCurrentWindowMetrics(); method @Deprecated public android.view.Display getDefaultDisplay(); core/java/android/inputmethodservice/SoftInputWindow.java +8 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import java.lang.annotation.Retention; Loading Loading @@ -94,6 +95,13 @@ public class SoftInputWindow extends Dialog { lp.token = token; getWindow().setAttributes(lp); updateWindowState(SoftInputWindowState.TOKEN_SET); // As soon as we have a token, make sure the window is added (but not shown) by // setting visibility to INVISIBLE and calling show() on Dialog. Note that // WindowInsetsController.OnControllableInsetsChangedListener relies on the window // being added to function. getWindow().getDecorView().setVisibility(View.INVISIBLE); show(); return; case SoftInputWindowState.TOKEN_SET: case SoftInputWindowState.SHOWN_AT_LEAST_ONCE: Loading core/java/android/view/InsetsController.java +65 −3 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.io.PrintWriter; import java.lang.annotation.Retention; Loading @@ -59,6 +60,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.function.BiFunction; /** Loading Loading @@ -306,6 +308,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private SyncRtSurfaceTransactionApplier mApplier; private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest; private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners = new ArrayList<>(); /** Set of inset types for which an animation was started since last resetting this field */ private @InsetsType int mLastStartedAnimTypes; public InsetsController(ViewRootImpl viewRoot) { this(viewRoot, (controller, type) -> { Loading Loading @@ -459,6 +466,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } mTmpControlArray.clear(); // Do not override any animations that the app started in the OnControllableInsetsChanged // listeners. int animatingTypes = invokeControllableInsetsChangedListeners(); showTypes[0] &= ~animatingTypes; hideTypes[0] &= ~animatingTypes; if (showTypes[0] != 0) { applyAnimation(showTypes[0], true /* show */, false /* fromIme */); } Loading Loading @@ -542,9 +556,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private CancellationSignal controlWindowInsetsAnimation(@InsetsType int types, WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs, @Nullable Interpolator interpolator, @AnimationType int animationType) { // If the frame of our window doesn't span the entire display, the control API makes very // little sense, as we don't deal with negative insets. So just cancel immediately. if (!mState.getDisplayFrame().equals(mFrame)) { if (!checkDisplayFramesForControlling()) { listener.onCancelled(); CancellationSignal cancellationSignal = new CancellationSignal(); cancellationSignal.cancel(); Loading @@ -554,6 +566,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation false /* fade */, animationType, getLayoutInsetsDuringAnimationMode(types)); } private boolean checkDisplayFramesForControlling() { // If the frame of our window doesn't span the entire display, the control API makes very // little sense, as we don't deal with negative insets. So just cancel immediately. return mState.getDisplayFrame().equals(mFrame); } private CancellationSignal controlAnimationUnchecked(@InsetsType int types, WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme, long durationMs, Interpolator interpolator, boolean fade, Loading @@ -567,6 +586,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return cancellationSignal; } cancelExistingControllers(types); mLastStartedAnimTypes |= types; final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types); final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); Loading Loading @@ -994,6 +1014,48 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return mViewRoot.mWindowAttributes.insetsFlags.behavior; } private @InsetsType int calculateControllableTypes() { if (!checkDisplayFramesForControlling()) { return 0; } @InsetsType int result = 0; for (int i = mSourceConsumers.size() - 1; i >= 0; i--) { InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i); if (consumer.getControl() != null) { result |= toPublicType(consumer.mType); } } return result; } /** * @return The types that are now animating due to a listener invoking control/show/hide */ private @InsetsType int invokeControllableInsetsChangedListeners() { mLastStartedAnimTypes = 0; @InsetsType int types = calculateControllableTypes(); int size = mControllableInsetsChangedListeners.size(); for (int i = 0; i < size; i++) { mControllableInsetsChangedListeners.get(i).onControllableInsetsChanged(this, types); } return mLastStartedAnimTypes; } @Override public void addOnControllableInsetsChangedListener( OnControllableInsetsChangedListener listener) { Objects.requireNonNull(listener); mControllableInsetsChangedListeners.add(listener); listener.onControllableInsetsChanged(this, calculateControllableTypes()); } @Override public void removeOnControllableInsetsChangedListener( OnControllableInsetsChangedListener listener) { Objects.requireNonNull(listener); mControllableInsetsChangedListeners.remove(listener); } /** * At the time we receive new leashes (e.g. InsetsSourceConsumer is processing * setControl) we need to release the old leash. But we may have already scheduled Loading core/java/android/view/PendingInsetsController.java +29 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ public class PendingInsetsController implements WindowInsetsController { private @Behavior int mBehavior = KEEP_BEHAVIOR; private final InsetsState mDummyState = new InsetsState(); private InsetsController mReplayedInsetsController; private ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners = new ArrayList<>(); @Override public void show(int types) { Loading Loading @@ -112,6 +114,27 @@ public class PendingInsetsController implements WindowInsetsController { return mDummyState; } @Override public void addOnControllableInsetsChangedListener( OnControllableInsetsChangedListener listener) { if (mReplayedInsetsController != null) { mReplayedInsetsController.addOnControllableInsetsChangedListener(listener); } else { mControllableInsetsChangedListeners.add(listener); listener.onControllableInsetsChanged(this, 0); } } @Override public void removeOnControllableInsetsChangedListener( OnControllableInsetsChangedListener listener) { if (mReplayedInsetsController != null) { mReplayedInsetsController.removeOnControllableInsetsChangedListener(listener); } else { mControllableInsetsChangedListeners.remove(listener); } } /** * Replays the commands on {@code controller} and attaches it to this instance such that any * calls will be forwarded to the real instance in the future. Loading @@ -128,9 +151,15 @@ public class PendingInsetsController implements WindowInsetsController { for (int i = 0; i < size; i++) { mRequests.get(i).replay(controller); } size = mControllableInsetsChangedListeners.size(); for (int i = 0; i < size; i++) { controller.addOnControllableInsetsChangedListener( mControllableInsetsChangedListeners.get(i)); } // Reset all state so it doesn't get applied twice just in case mRequests.clear(); mControllableInsetsChangedListeners.clear(); mBehavior = KEEP_BEHAVIOR; mAppearance = 0; mAppearanceMask = 0; Loading core/java/android/view/WindowInsetsController.java +53 −0 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Insets; import android.inputmethodservice.InputMethodService; import android.os.CancellationSignal; import android.view.WindowInsets.Type; import android.view.WindowInsets.Type.InsetsType; import android.view.animation.Interpolator; Loading Loading @@ -212,4 +214,55 @@ public interface WindowInsetsController { * @hide */ InsetsState getState(); /** * Adds a {@link OnControllableInsetsChangedListener} to the window insets controller. * * @param listener The listener to add. * * @see OnControllableInsetsChangedListener * @see #removeOnControllableInsetsChangedListener(OnControllableInsetsChangedListener) */ void addOnControllableInsetsChangedListener( @NonNull OnControllableInsetsChangedListener listener); /** * Removes a {@link OnControllableInsetsChangedListener} from the window insets controller. * * @param listener The listener to remove. * * @see OnControllableInsetsChangedListener * @see #addOnControllableInsetsChangedListener(OnControllableInsetsChangedListener) */ void removeOnControllableInsetsChangedListener( @NonNull OnControllableInsetsChangedListener listener); /** * Listener to be notified when the set of controllable {@link InsetsType} controlled by a * {@link WindowInsetsController} changes. * <p> * Once a {@link InsetsType} becomes controllable, the app will be able to control the window * that is causing this type of insets by calling {@link #controlWindowInsetsAnimation}. * <p> * Note: When listening to controllability of the {@link Type#ime}, * {@link #controlWindowInsetsAnimation} may still fail in case the {@link InputMethodService} * decides to cancel the show request. This could happen when there is a hardware keyboard * attached. * * @see #addOnControllableInsetsChangedListener(OnControllableInsetsChangedListener) * @see #removeOnControllableInsetsChangedListener(OnControllableInsetsChangedListener) */ interface OnControllableInsetsChangedListener { /** * Called when the set of controllable {@link InsetsType} changes. * * @param controller The controller for which the set of controllable {@link InsetsType}s * are changing. * @param typeMask Bitwise type-mask of the {@link InsetsType}s the controller is currently * able to control. */ void onControllableInsetsChanged(@NonNull WindowInsetsController controller, @InsetsType int typeMask); } } Loading
api/current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -55583,10 +55583,12 @@ package android.view { } public interface WindowInsetsController { method public void addOnControllableInsetsChangedListener(@NonNull android.view.WindowInsetsController.OnControllableInsetsChangedListener); method @NonNull public android.os.CancellationSignal controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener); method public int getSystemBarsAppearance(); method public int getSystemBarsBehavior(); method public void hide(int); method public void removeOnControllableInsetsChangedListener(@NonNull android.view.WindowInsetsController.OnControllableInsetsChangedListener); method public void setSystemBarsAppearance(int, int); method public void setSystemBarsBehavior(int); method public void show(int); Loading @@ -55597,6 +55599,10 @@ package android.view { field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2 } public static interface WindowInsetsController.OnControllableInsetsChangedListener { method public void onControllableInsetsChanged(@NonNull android.view.WindowInsetsController, int); } public interface WindowManager extends android.view.ViewManager { method @NonNull public default android.view.WindowMetrics getCurrentWindowMetrics(); method @Deprecated public android.view.Display getDefaultDisplay();
core/java/android/inputmethodservice/SoftInputWindow.java +8 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import java.lang.annotation.Retention; Loading Loading @@ -94,6 +95,13 @@ public class SoftInputWindow extends Dialog { lp.token = token; getWindow().setAttributes(lp); updateWindowState(SoftInputWindowState.TOKEN_SET); // As soon as we have a token, make sure the window is added (but not shown) by // setting visibility to INVISIBLE and calling show() on Dialog. Note that // WindowInsetsController.OnControllableInsetsChangedListener relies on the window // being added to function. getWindow().getDecorView().setVisibility(View.INVISIBLE); show(); return; case SoftInputWindowState.TOKEN_SET: case SoftInputWindowState.SHOWN_AT_LEAST_ONCE: Loading
core/java/android/view/InsetsController.java +65 −3 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.io.PrintWriter; import java.lang.annotation.Retention; Loading @@ -59,6 +60,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.function.BiFunction; /** Loading Loading @@ -306,6 +308,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private SyncRtSurfaceTransactionApplier mApplier; private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest; private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners = new ArrayList<>(); /** Set of inset types for which an animation was started since last resetting this field */ private @InsetsType int mLastStartedAnimTypes; public InsetsController(ViewRootImpl viewRoot) { this(viewRoot, (controller, type) -> { Loading Loading @@ -459,6 +466,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } mTmpControlArray.clear(); // Do not override any animations that the app started in the OnControllableInsetsChanged // listeners. int animatingTypes = invokeControllableInsetsChangedListeners(); showTypes[0] &= ~animatingTypes; hideTypes[0] &= ~animatingTypes; if (showTypes[0] != 0) { applyAnimation(showTypes[0], true /* show */, false /* fromIme */); } Loading Loading @@ -542,9 +556,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private CancellationSignal controlWindowInsetsAnimation(@InsetsType int types, WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs, @Nullable Interpolator interpolator, @AnimationType int animationType) { // If the frame of our window doesn't span the entire display, the control API makes very // little sense, as we don't deal with negative insets. So just cancel immediately. if (!mState.getDisplayFrame().equals(mFrame)) { if (!checkDisplayFramesForControlling()) { listener.onCancelled(); CancellationSignal cancellationSignal = new CancellationSignal(); cancellationSignal.cancel(); Loading @@ -554,6 +566,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation false /* fade */, animationType, getLayoutInsetsDuringAnimationMode(types)); } private boolean checkDisplayFramesForControlling() { // If the frame of our window doesn't span the entire display, the control API makes very // little sense, as we don't deal with negative insets. So just cancel immediately. return mState.getDisplayFrame().equals(mFrame); } private CancellationSignal controlAnimationUnchecked(@InsetsType int types, WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme, long durationMs, Interpolator interpolator, boolean fade, Loading @@ -567,6 +586,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return cancellationSignal; } cancelExistingControllers(types); mLastStartedAnimTypes |= types; final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types); final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); Loading Loading @@ -994,6 +1014,48 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return mViewRoot.mWindowAttributes.insetsFlags.behavior; } private @InsetsType int calculateControllableTypes() { if (!checkDisplayFramesForControlling()) { return 0; } @InsetsType int result = 0; for (int i = mSourceConsumers.size() - 1; i >= 0; i--) { InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i); if (consumer.getControl() != null) { result |= toPublicType(consumer.mType); } } return result; } /** * @return The types that are now animating due to a listener invoking control/show/hide */ private @InsetsType int invokeControllableInsetsChangedListeners() { mLastStartedAnimTypes = 0; @InsetsType int types = calculateControllableTypes(); int size = mControllableInsetsChangedListeners.size(); for (int i = 0; i < size; i++) { mControllableInsetsChangedListeners.get(i).onControllableInsetsChanged(this, types); } return mLastStartedAnimTypes; } @Override public void addOnControllableInsetsChangedListener( OnControllableInsetsChangedListener listener) { Objects.requireNonNull(listener); mControllableInsetsChangedListeners.add(listener); listener.onControllableInsetsChanged(this, calculateControllableTypes()); } @Override public void removeOnControllableInsetsChangedListener( OnControllableInsetsChangedListener listener) { Objects.requireNonNull(listener); mControllableInsetsChangedListeners.remove(listener); } /** * At the time we receive new leashes (e.g. InsetsSourceConsumer is processing * setControl) we need to release the old leash. But we may have already scheduled Loading
core/java/android/view/PendingInsetsController.java +29 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ public class PendingInsetsController implements WindowInsetsController { private @Behavior int mBehavior = KEEP_BEHAVIOR; private final InsetsState mDummyState = new InsetsState(); private InsetsController mReplayedInsetsController; private ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners = new ArrayList<>(); @Override public void show(int types) { Loading Loading @@ -112,6 +114,27 @@ public class PendingInsetsController implements WindowInsetsController { return mDummyState; } @Override public void addOnControllableInsetsChangedListener( OnControllableInsetsChangedListener listener) { if (mReplayedInsetsController != null) { mReplayedInsetsController.addOnControllableInsetsChangedListener(listener); } else { mControllableInsetsChangedListeners.add(listener); listener.onControllableInsetsChanged(this, 0); } } @Override public void removeOnControllableInsetsChangedListener( OnControllableInsetsChangedListener listener) { if (mReplayedInsetsController != null) { mReplayedInsetsController.removeOnControllableInsetsChangedListener(listener); } else { mControllableInsetsChangedListeners.remove(listener); } } /** * Replays the commands on {@code controller} and attaches it to this instance such that any * calls will be forwarded to the real instance in the future. Loading @@ -128,9 +151,15 @@ public class PendingInsetsController implements WindowInsetsController { for (int i = 0; i < size; i++) { mRequests.get(i).replay(controller); } size = mControllableInsetsChangedListeners.size(); for (int i = 0; i < size; i++) { controller.addOnControllableInsetsChangedListener( mControllableInsetsChangedListeners.get(i)); } // Reset all state so it doesn't get applied twice just in case mRequests.clear(); mControllableInsetsChangedListeners.clear(); mBehavior = KEEP_BEHAVIOR; mAppearance = 0; mAppearanceMask = 0; Loading
core/java/android/view/WindowInsetsController.java +53 −0 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Insets; import android.inputmethodservice.InputMethodService; import android.os.CancellationSignal; import android.view.WindowInsets.Type; import android.view.WindowInsets.Type.InsetsType; import android.view.animation.Interpolator; Loading Loading @@ -212,4 +214,55 @@ public interface WindowInsetsController { * @hide */ InsetsState getState(); /** * Adds a {@link OnControllableInsetsChangedListener} to the window insets controller. * * @param listener The listener to add. * * @see OnControllableInsetsChangedListener * @see #removeOnControllableInsetsChangedListener(OnControllableInsetsChangedListener) */ void addOnControllableInsetsChangedListener( @NonNull OnControllableInsetsChangedListener listener); /** * Removes a {@link OnControllableInsetsChangedListener} from the window insets controller. * * @param listener The listener to remove. * * @see OnControllableInsetsChangedListener * @see #addOnControllableInsetsChangedListener(OnControllableInsetsChangedListener) */ void removeOnControllableInsetsChangedListener( @NonNull OnControllableInsetsChangedListener listener); /** * Listener to be notified when the set of controllable {@link InsetsType} controlled by a * {@link WindowInsetsController} changes. * <p> * Once a {@link InsetsType} becomes controllable, the app will be able to control the window * that is causing this type of insets by calling {@link #controlWindowInsetsAnimation}. * <p> * Note: When listening to controllability of the {@link Type#ime}, * {@link #controlWindowInsetsAnimation} may still fail in case the {@link InputMethodService} * decides to cancel the show request. This could happen when there is a hardware keyboard * attached. * * @see #addOnControllableInsetsChangedListener(OnControllableInsetsChangedListener) * @see #removeOnControllableInsetsChangedListener(OnControllableInsetsChangedListener) */ interface OnControllableInsetsChangedListener { /** * Called when the set of controllable {@link InsetsType} changes. * * @param controller The controller for which the set of controllable {@link InsetsType}s * are changing. * @param typeMask Bitwise type-mask of the {@link InsetsType}s the controller is currently * able to control. */ void onControllableInsetsChanged(@NonNull WindowInsetsController controller, @InsetsType int typeMask); } }