diff options
4 files changed, 182 insertions, 3 deletions
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 473eeda57fde..13357b899729 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -154,6 +154,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ToBooleanFunction; import com.android.internal.view.IInputMethodClient; import com.android.server.policy.WindowManagerPolicy; +import com.android.server.wm.utils.RotationCache; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -215,7 +216,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo int mInitialDisplayDensity = 0; DisplayCutout mInitialDisplayCutout; - DisplayCutout mDisplayCutoutOverride; + private final RotationCache<DisplayCutout, DisplayCutout> mDisplayCutoutCache + = new RotationCache<>(this::calculateDisplayCutoutForRotationUncached); /** * Overridden display size. Initialized with {@link #mInitialDisplayWidth} @@ -1198,7 +1200,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } DisplayCutout calculateDisplayCutoutForRotation(int rotation) { - final DisplayCutout cutout = mInitialDisplayCutout; + return mDisplayCutoutCache.getOrCompute(mInitialDisplayCutout, rotation); + } + + private DisplayCutout calculateDisplayCutoutForRotationUncached( + DisplayCutout cutout, int rotation) { if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) { return cutout; } diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 423be6334fd8..5c8fadbef6e2 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -174,7 +174,7 @@ public class DockedStackDividerController { final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide, getContentWidth()); - DisplayCutout displayCutout = mDisplayContent.calculateDisplayCutoutForRotation( + final DisplayCutout displayCutout = mDisplayContent.calculateDisplayCutoutForRotation( rotation); // Since we only care about feasible states, snap to the closest snap target, like it diff --git a/services/core/java/com/android/server/wm/utils/RotationCache.java b/services/core/java/com/android/server/wm/utils/RotationCache.java new file mode 100644 index 000000000000..7a06cbcb084e --- /dev/null +++ b/services/core/java/com/android/server/wm/utils/RotationCache.java @@ -0,0 +1,70 @@ +/* + * 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 com.android.server.wm.utils; + +import android.util.SparseArray; + +import java.util.Arrays; + +/** + * Caches the result of a rotation-dependent computation. + * + * The cache is discarded once the identity of the other parameter changes. + * + * @param <T> type of the parameter to the computation + * @param <R> type of the result of the computation + */ +public class RotationCache<T,R> { + + private final RotationDependentComputation<T,R> mComputation; + private final SparseArray<R> mCache = new SparseArray<>(4); + private T mCachedFor; + + public RotationCache(RotationDependentComputation<T, R> computation) { + mComputation = computation; + } + + /** + * Looks up the result of the computation, or calculates it if needed. + * + * @param t a parameter to the rotation-dependent computation. + * @param rotation the rotation for which to perform the rotation-dependent computation. + * @return the result of the rotation-dependent computation. + */ + public R getOrCompute(T t, int rotation) { + if (t != mCachedFor) { + mCache.clear(); + mCachedFor = t; + } + final int idx = mCache.indexOfKey(rotation); + if (idx >= 0) { + return mCache.valueAt(idx); + } + final R result = mComputation.compute(t, rotation); + mCache.put(rotation, result); + return result; + } + + /** + * A computation that takes a generic input and is dependent on the rotation. The result can + * be cached by {@link RotationCache}. + */ + @FunctionalInterface + public interface RotationDependentComputation<T, R> { + R compute(T t, int rotation); + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java new file mode 100644 index 000000000000..d3cf97850c83 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java @@ -0,0 +1,103 @@ +/* + * 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 com.android.server.wm.utils; + +import static android.util.Pair.create; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.util.Pair; + +import com.android.server.wm.utils.RotationCache.RotationDependentComputation; + +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit +public class RotationCacheTest { + + private RotationCache<Object, Pair<Object, Integer>> mCache; + private boolean mComputationCalled; + + @Before + public void setUp() throws Exception { + mComputationCalled = false; + mCache = new RotationCache<>((o, rot) -> { + mComputationCalled = true; + return create(o, rot); + }); + } + + @Test + public void getOrCompute_computes() throws Exception { + assertThat(mCache.getOrCompute("hello", 0), equalTo(create("hello", 0))); + assertThat(mCache.getOrCompute("hello", 1), equalTo(create("hello", 1))); + assertThat(mCache.getOrCompute("hello", 2), equalTo(create("hello", 2))); + assertThat(mCache.getOrCompute("hello", 3), equalTo(create("hello", 3))); + } + + @Test + public void getOrCompute_sameParam_sameRot_hitsCache() throws Exception { + assertNotNull(mCache.getOrCompute("hello", 1)); + + mComputationCalled = false; + assertThat(mCache.getOrCompute("hello", 1), equalTo(create("hello", 1))); + assertThat(mComputationCalled, is(false)); + } + + @Test + public void getOrCompute_sameParam_hitsCache_forAllRots() throws Exception { + assertNotNull(mCache.getOrCompute("hello", 3)); + assertNotNull(mCache.getOrCompute("hello", 2)); + assertNotNull(mCache.getOrCompute("hello", 1)); + assertNotNull(mCache.getOrCompute("hello", 0)); + + mComputationCalled = false; + assertThat(mCache.getOrCompute("hello", 1), equalTo(create("hello", 1))); + assertThat(mCache.getOrCompute("hello", 0), equalTo(create("hello", 0))); + assertThat(mCache.getOrCompute("hello", 2), equalTo(create("hello", 2))); + assertThat(mCache.getOrCompute("hello", 3), equalTo(create("hello", 3))); + assertThat(mComputationCalled, is(false)); + } + + @Test + public void getOrCompute_changingParam_recomputes() throws Exception { + assertNotNull(mCache.getOrCompute("hello", 1)); + + assertThat(mCache.getOrCompute("world", 1), equalTo(create("world", 1))); + } + + @Test + public void getOrCompute_changingParam_clearsCacheForDifferentRots() throws Exception { + assertNotNull(mCache.getOrCompute("hello", 1)); + assertNotNull(mCache.getOrCompute("world", 2)); + + mComputationCalled = false; + assertThat(mCache.getOrCompute("hello", 1), equalTo(create("hello", 1))); + assertThat(mComputationCalled, is(true)); + } +}
\ No newline at end of file |