Loading api/current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -14134,8 +14134,11 @@ package android.graphics { public final class Insets { method public static android.graphics.Insets add(android.graphics.Insets, android.graphics.Insets); method public static android.graphics.Insets max(android.graphics.Insets, android.graphics.Insets); method public static android.graphics.Insets min(android.graphics.Insets, android.graphics.Insets); method public static android.graphics.Insets of(int, int, int, int); method public static android.graphics.Insets of(android.graphics.Rect); method public static android.graphics.Insets subtract(android.graphics.Insets, android.graphics.Insets); field public static final android.graphics.Insets NONE; field public final int bottom; field public final int left; core/java/android/util/SparseSetArray.java +7 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,13 @@ public class SparseSetArray<T> { return set.contains(value); } /** * @return the set of items at index n */ public ArraySet<T> get(int n) { return mData.get(n); } /** * Remove a value from index n. * @return TRUE when the value existed at the given index and removed, FALSE otherwise. Loading core/java/android/view/InsetsAnimationControlImpl.java 0 → 100644 +197 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package android.view; import static android.view.InsetsState.INSET_SIDE_BOTTOM; import static android.view.InsetsState.INSET_SIDE_LEFT; import static android.view.InsetsState.INSET_SIDE_RIGHT; import static android.view.InsetsState.INSET_SIDE_TOP; import android.annotation.Nullable; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Rect; import android.os.UidProto.Sync; import android.util.ArraySet; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.SparseSetArray; import android.view.InsetsState.InsetSide; import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; import android.view.WindowInsets.Type.InsetType; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.function.Function; import java.util.function.Supplier; /** * Implements {@link WindowInsetsAnimationController} * @hide */ @VisibleForTesting public class InsetsAnimationControlImpl implements WindowInsetsAnimationController { private final WindowInsetsAnimationControlListener mListener; private final SparseArray<InsetsSourceConsumer> mConsumers; private final SparseIntArray mTypeSideMap = new SparseIntArray(); private final SparseSetArray<InsetsSourceConsumer> mSideSourceMap = new SparseSetArray<>(); /** @see WindowInsetsAnimationController#getHiddenStateInsets */ private final Insets mHiddenInsets; /** @see WindowInsetsAnimationController#getShownStateInsets */ private final Insets mShownInsets; private final Matrix mTmpMatrix = new Matrix(); private final InsetsState mInitialInsetsState; private final @InsetType int mTypes; private final Supplier<SyncRtSurfaceTransactionApplier> mTransactionApplierSupplier; private Insets mCurrentInsets; @VisibleForTesting public InsetsAnimationControlImpl(SparseArray<InsetsSourceConsumer> consumers, Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener, @InsetType int types, Supplier<SyncRtSurfaceTransactionApplier> transactionApplierSupplier) { mConsumers = consumers; mListener = listener; mTypes = types; mTransactionApplierSupplier = transactionApplierSupplier; mInitialInsetsState = new InsetsState(state); mCurrentInsets = getInsetsFromState(mInitialInsetsState, frame, null /* typeSideMap */); mHiddenInsets = calculateInsets(mInitialInsetsState, frame, consumers, false /* shown */, null /* typeSideMap */); mShownInsets = calculateInsets(mInitialInsetsState, frame, consumers, true /* shown */, mTypeSideMap); buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mConsumers); // TODO: Check for controllability first and wait for IME if needed. listener.onReady(this, types); } @Override public Insets getHiddenStateInsets() { return mHiddenInsets; } @Override public Insets getShownStateInsets() { return mShownInsets; } @Override public Insets getCurrentInsets() { return mCurrentInsets; } @Override @InsetType public int getTypes() { return mTypes; } @Override public void changeInsets(Insets insets) { insets = sanitize(insets); final Insets offset = Insets.subtract(mShownInsets, insets); ArrayList<SurfaceParams> params = new ArrayList<>(); if (offset.left != 0) { updateLeashesForSide(INSET_SIDE_LEFT, offset.left, params); } if (offset.top != 0) { updateLeashesForSide(INSET_SIDE_TOP, offset.top, params); } if (offset.right != 0) { updateLeashesForSide(INSET_SIDE_RIGHT, offset.right, params); } if (offset.bottom != 0) { updateLeashesForSide(INSET_SIDE_BOTTOM, offset.bottom, params); } SyncRtSurfaceTransactionApplier applier = mTransactionApplierSupplier.get(); applier.scheduleApply(params.toArray(new SurfaceParams[params.size()])); mCurrentInsets = insets; } @Override public void finish(int shownTypes) { // TODO } private Insets calculateInsets(InsetsState state, Rect frame, SparseArray<InsetsSourceConsumer> consumers, boolean shown, @Nullable @InsetSide SparseIntArray typeSideMap) { for (int i = consumers.size() - 1; i >= 0; i--) { state.getSource(consumers.valueAt(i).getType()).setVisible(shown); } return getInsetsFromState(state, frame, typeSideMap); } private Insets getInsetsFromState(InsetsState state, Rect frame, @Nullable @InsetSide SparseIntArray typeSideMap) { return state.calculateInsets(frame, false /* isScreenRound */, false /* alwaysConsumerNavBar */, null /* displayCutout */, typeSideMap) .getSystemWindowInsets(); } private Insets sanitize(Insets insets) { return Insets.max(Insets.min(insets, mShownInsets), mHiddenInsets); } private void updateLeashesForSide(@InsetSide int side, int inset, ArrayList<SurfaceParams> surfaceParams) { ArraySet<InsetsSourceConsumer> items = mSideSourceMap.get(side); // TODO: Implement behavior when inset spans over multiple types for (int i = items.size() - 1; i >= 0; i--) { final InsetsSourceConsumer consumer = items.valueAt(i); final InsetsSource source = mInitialInsetsState.getSource(consumer.getType()); final SurfaceControl leash = consumer.getControl().getLeash(); mTmpMatrix.setTranslate(source.getFrame().left, source.getFrame().top); addTranslationToMatrix(side, inset, mTmpMatrix); surfaceParams.add(new SurfaceParams(leash, 1f, mTmpMatrix, null, 0, 0f)); } } private void addTranslationToMatrix(@InsetSide int side, int inset, Matrix m) { switch (side) { case INSET_SIDE_LEFT: m.postTranslate(-inset, 0); break; case INSET_SIDE_TOP: m.postTranslate(0, -inset); break; case INSET_SIDE_RIGHT: m.postTranslate(inset, 0); break; case INSET_SIDE_BOTTOM: m.postTranslate(0, inset); break; } } private static void buildTypeSourcesMap(SparseIntArray typeSideMap, SparseSetArray<InsetsSourceConsumer> sideSourcesMap, SparseArray<InsetsSourceConsumer> consumers) { for (int i = typeSideMap.size() - 1; i >= 0; i--) { int type = typeSideMap.keyAt(i); int side = typeSideMap.valueAt(i); sideSourcesMap.add(side, consumers.get(type)); } } } core/java/android/view/InsetsController.java +30 −3 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.view.InsetsState.InternalInsetType; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; import java.util.ArrayList; /** * Implements {@link WindowInsetsController} on the client. Loading @@ -41,6 +42,7 @@ public class InsetsController implements WindowInsetsController { private final ViewRootImpl mViewRoot; private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>(); private final ArrayList<InsetsAnimationControlImpl> mAnimationControls = new ArrayList<>(); public InsetsController(ViewRootImpl viewRoot) { mViewRoot = viewRoot; Loading @@ -67,9 +69,11 @@ public class InsetsController implements WindowInsetsController { /** * @see InsetsState#calculateInsets */ WindowInsets calculateInsets(boolean isScreenRound, @VisibleForTesting public WindowInsets calculateInsets(boolean isScreenRound, boolean alwaysConsumeNavBar, DisplayCutout cutout) { return mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout); return mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout, null /* typeSideMap */); } /** Loading Loading @@ -116,6 +120,28 @@ public class InsetsController implements WindowInsetsController { } } @Override public void controlWindowInsetsAnimation(@InsetType int types, WindowInsetsAnimationControlListener listener) { // TODO: Check whether we already have a controller. final ArraySet<Integer> internalTypes = mState.toInternalType(types); final SparseArray<InsetsSourceConsumer> consumers = new SparseArray<>(); for (int i = internalTypes.size() - 1; i >= 0; i--) { InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i)); if (consumer.getControl() != null) { consumers.put(consumer.getType(), consumer); } else { // TODO: Let calling app know it's not possible, or wait // TODO: Remove it from types } } final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(consumers, mFrame, mState, listener, types, () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView)); mAnimationControls.add(controller); } private void applyLocalVisibilityOverride() { for (int i = mSourceConsumers.size() - 1; i >= 0; i--) { final InsetsSourceConsumer controller = mSourceConsumers.valueAt(i); Loading @@ -134,7 +160,8 @@ public class InsetsController implements WindowInsetsController { return controller; } void notifyVisibilityChanged() { @VisibleForTesting public void notifyVisibilityChanged() { mViewRoot.notifyInsetsChanged(); } Loading core/java/android/view/InsetsSource.java +2 −1 Original line number Diff line number Diff line Loading @@ -70,7 +70,8 @@ public class InsetsSource implements Parcelable { * * @param relativeFrame The frame to calculate the insets relative to. * @param ignoreVisibility If true, always reports back insets even if source isn't visible. * @return The resulting insets. * @return The resulting insets. The contract is that only one side will be occupied by a * source. */ public Insets calculateInsets(Rect relativeFrame, boolean ignoreVisibility) { if (!ignoreVisibility && !mVisible) { Loading Loading
api/current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -14134,8 +14134,11 @@ package android.graphics { public final class Insets { method public static android.graphics.Insets add(android.graphics.Insets, android.graphics.Insets); method public static android.graphics.Insets max(android.graphics.Insets, android.graphics.Insets); method public static android.graphics.Insets min(android.graphics.Insets, android.graphics.Insets); method public static android.graphics.Insets of(int, int, int, int); method public static android.graphics.Insets of(android.graphics.Rect); method public static android.graphics.Insets subtract(android.graphics.Insets, android.graphics.Insets); field public static final android.graphics.Insets NONE; field public final int bottom; field public final int left;
core/java/android/util/SparseSetArray.java +7 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,13 @@ public class SparseSetArray<T> { return set.contains(value); } /** * @return the set of items at index n */ public ArraySet<T> get(int n) { return mData.get(n); } /** * Remove a value from index n. * @return TRUE when the value existed at the given index and removed, FALSE otherwise. Loading
core/java/android/view/InsetsAnimationControlImpl.java 0 → 100644 +197 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package android.view; import static android.view.InsetsState.INSET_SIDE_BOTTOM; import static android.view.InsetsState.INSET_SIDE_LEFT; import static android.view.InsetsState.INSET_SIDE_RIGHT; import static android.view.InsetsState.INSET_SIDE_TOP; import android.annotation.Nullable; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Rect; import android.os.UidProto.Sync; import android.util.ArraySet; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.SparseSetArray; import android.view.InsetsState.InsetSide; import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; import android.view.WindowInsets.Type.InsetType; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.function.Function; import java.util.function.Supplier; /** * Implements {@link WindowInsetsAnimationController} * @hide */ @VisibleForTesting public class InsetsAnimationControlImpl implements WindowInsetsAnimationController { private final WindowInsetsAnimationControlListener mListener; private final SparseArray<InsetsSourceConsumer> mConsumers; private final SparseIntArray mTypeSideMap = new SparseIntArray(); private final SparseSetArray<InsetsSourceConsumer> mSideSourceMap = new SparseSetArray<>(); /** @see WindowInsetsAnimationController#getHiddenStateInsets */ private final Insets mHiddenInsets; /** @see WindowInsetsAnimationController#getShownStateInsets */ private final Insets mShownInsets; private final Matrix mTmpMatrix = new Matrix(); private final InsetsState mInitialInsetsState; private final @InsetType int mTypes; private final Supplier<SyncRtSurfaceTransactionApplier> mTransactionApplierSupplier; private Insets mCurrentInsets; @VisibleForTesting public InsetsAnimationControlImpl(SparseArray<InsetsSourceConsumer> consumers, Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener, @InsetType int types, Supplier<SyncRtSurfaceTransactionApplier> transactionApplierSupplier) { mConsumers = consumers; mListener = listener; mTypes = types; mTransactionApplierSupplier = transactionApplierSupplier; mInitialInsetsState = new InsetsState(state); mCurrentInsets = getInsetsFromState(mInitialInsetsState, frame, null /* typeSideMap */); mHiddenInsets = calculateInsets(mInitialInsetsState, frame, consumers, false /* shown */, null /* typeSideMap */); mShownInsets = calculateInsets(mInitialInsetsState, frame, consumers, true /* shown */, mTypeSideMap); buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mConsumers); // TODO: Check for controllability first and wait for IME if needed. listener.onReady(this, types); } @Override public Insets getHiddenStateInsets() { return mHiddenInsets; } @Override public Insets getShownStateInsets() { return mShownInsets; } @Override public Insets getCurrentInsets() { return mCurrentInsets; } @Override @InsetType public int getTypes() { return mTypes; } @Override public void changeInsets(Insets insets) { insets = sanitize(insets); final Insets offset = Insets.subtract(mShownInsets, insets); ArrayList<SurfaceParams> params = new ArrayList<>(); if (offset.left != 0) { updateLeashesForSide(INSET_SIDE_LEFT, offset.left, params); } if (offset.top != 0) { updateLeashesForSide(INSET_SIDE_TOP, offset.top, params); } if (offset.right != 0) { updateLeashesForSide(INSET_SIDE_RIGHT, offset.right, params); } if (offset.bottom != 0) { updateLeashesForSide(INSET_SIDE_BOTTOM, offset.bottom, params); } SyncRtSurfaceTransactionApplier applier = mTransactionApplierSupplier.get(); applier.scheduleApply(params.toArray(new SurfaceParams[params.size()])); mCurrentInsets = insets; } @Override public void finish(int shownTypes) { // TODO } private Insets calculateInsets(InsetsState state, Rect frame, SparseArray<InsetsSourceConsumer> consumers, boolean shown, @Nullable @InsetSide SparseIntArray typeSideMap) { for (int i = consumers.size() - 1; i >= 0; i--) { state.getSource(consumers.valueAt(i).getType()).setVisible(shown); } return getInsetsFromState(state, frame, typeSideMap); } private Insets getInsetsFromState(InsetsState state, Rect frame, @Nullable @InsetSide SparseIntArray typeSideMap) { return state.calculateInsets(frame, false /* isScreenRound */, false /* alwaysConsumerNavBar */, null /* displayCutout */, typeSideMap) .getSystemWindowInsets(); } private Insets sanitize(Insets insets) { return Insets.max(Insets.min(insets, mShownInsets), mHiddenInsets); } private void updateLeashesForSide(@InsetSide int side, int inset, ArrayList<SurfaceParams> surfaceParams) { ArraySet<InsetsSourceConsumer> items = mSideSourceMap.get(side); // TODO: Implement behavior when inset spans over multiple types for (int i = items.size() - 1; i >= 0; i--) { final InsetsSourceConsumer consumer = items.valueAt(i); final InsetsSource source = mInitialInsetsState.getSource(consumer.getType()); final SurfaceControl leash = consumer.getControl().getLeash(); mTmpMatrix.setTranslate(source.getFrame().left, source.getFrame().top); addTranslationToMatrix(side, inset, mTmpMatrix); surfaceParams.add(new SurfaceParams(leash, 1f, mTmpMatrix, null, 0, 0f)); } } private void addTranslationToMatrix(@InsetSide int side, int inset, Matrix m) { switch (side) { case INSET_SIDE_LEFT: m.postTranslate(-inset, 0); break; case INSET_SIDE_TOP: m.postTranslate(0, -inset); break; case INSET_SIDE_RIGHT: m.postTranslate(inset, 0); break; case INSET_SIDE_BOTTOM: m.postTranslate(0, inset); break; } } private static void buildTypeSourcesMap(SparseIntArray typeSideMap, SparseSetArray<InsetsSourceConsumer> sideSourcesMap, SparseArray<InsetsSourceConsumer> consumers) { for (int i = typeSideMap.size() - 1; i >= 0; i--) { int type = typeSideMap.keyAt(i); int side = typeSideMap.valueAt(i); sideSourcesMap.add(side, consumers.get(type)); } } }
core/java/android/view/InsetsController.java +30 −3 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.view.InsetsState.InternalInsetType; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; import java.util.ArrayList; /** * Implements {@link WindowInsetsController} on the client. Loading @@ -41,6 +42,7 @@ public class InsetsController implements WindowInsetsController { private final ViewRootImpl mViewRoot; private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>(); private final ArrayList<InsetsAnimationControlImpl> mAnimationControls = new ArrayList<>(); public InsetsController(ViewRootImpl viewRoot) { mViewRoot = viewRoot; Loading @@ -67,9 +69,11 @@ public class InsetsController implements WindowInsetsController { /** * @see InsetsState#calculateInsets */ WindowInsets calculateInsets(boolean isScreenRound, @VisibleForTesting public WindowInsets calculateInsets(boolean isScreenRound, boolean alwaysConsumeNavBar, DisplayCutout cutout) { return mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout); return mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout, null /* typeSideMap */); } /** Loading Loading @@ -116,6 +120,28 @@ public class InsetsController implements WindowInsetsController { } } @Override public void controlWindowInsetsAnimation(@InsetType int types, WindowInsetsAnimationControlListener listener) { // TODO: Check whether we already have a controller. final ArraySet<Integer> internalTypes = mState.toInternalType(types); final SparseArray<InsetsSourceConsumer> consumers = new SparseArray<>(); for (int i = internalTypes.size() - 1; i >= 0; i--) { InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i)); if (consumer.getControl() != null) { consumers.put(consumer.getType(), consumer); } else { // TODO: Let calling app know it's not possible, or wait // TODO: Remove it from types } } final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(consumers, mFrame, mState, listener, types, () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView)); mAnimationControls.add(controller); } private void applyLocalVisibilityOverride() { for (int i = mSourceConsumers.size() - 1; i >= 0; i--) { final InsetsSourceConsumer controller = mSourceConsumers.valueAt(i); Loading @@ -134,7 +160,8 @@ public class InsetsController implements WindowInsetsController { return controller; } void notifyVisibilityChanged() { @VisibleForTesting public void notifyVisibilityChanged() { mViewRoot.notifyInsetsChanged(); } Loading
core/java/android/view/InsetsSource.java +2 −1 Original line number Diff line number Diff line Loading @@ -70,7 +70,8 @@ public class InsetsSource implements Parcelable { * * @param relativeFrame The frame to calculate the insets relative to. * @param ignoreVisibility If true, always reports back insets even if source isn't visible. * @return The resulting insets. * @return The resulting insets. The contract is that only one side will be occupied by a * source. */ public Insets calculateInsets(Rect relativeFrame, boolean ignoreVisibility) { if (!ignoreVisibility && !mVisible) { Loading