summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vishnu Nair <vishnun@google.com> 2023-12-05 19:11:29 +0000
committer Vishnu Nair <vishnun@google.com> 2023-12-08 04:14:55 +0000
commit99249ffe60473ed6ecedb5b9b74053d34bf723b3 (patch)
tree98afb112bab05192f7600b38473c61d4c72b534a
parent06ebddace6ffe6c21bb3ee11121d7bfd507e540d (diff)
Expose TrustedPresentationListener for Window
Bug: 278027319 Test: TrustedPresentationCallbackTest Change-Id: I87d4a0b786daa9255ba150ff2409028b874c7b7b
-rw-r--r--core/api/current.txt12
-rw-r--r--core/java/android/view/WindowManager.java19
-rw-r--r--core/java/android/view/WindowManagerGlobal.java3
-rw-r--r--core/java/android/window/TrustedPresentationThresholds.java57
-rw-r--r--core/java/android/window/flags/window_surfaces.aconfig8
-rw-r--r--services/core/java/com/android/server/wm/TrustedPresentationListenerController.java16
-rw-r--r--services/tests/wmtests/AndroidManifest.xml5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TrustedPresentationListenerTest.java267
8 files changed, 77 insertions, 310 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index e8894a81e65b..123c7d703610 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -53795,9 +53795,11 @@ package android.view {
method @Deprecated public android.view.Display getDefaultDisplay();
method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
method public default boolean isCrossWindowBlurEnabled();
+ method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void registerTrustedPresentationListener(@NonNull android.os.IBinder, @NonNull android.window.TrustedPresentationThresholds, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method public default void removeCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public default void removeProposedRotationListener(@NonNull java.util.function.IntConsumer);
method public void removeViewImmediate(android.view.View);
+ method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void unregisterTrustedPresentationListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
field public static final String PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION = "android.window.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION";
@@ -60775,6 +60777,16 @@ package android.window {
method public void markSyncReady();
}
+ @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public final class TrustedPresentationThresholds implements android.os.Parcelable {
+ ctor @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public TrustedPresentationThresholds(@FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @IntRange(from=1) int);
+ method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public int describeContents();
+ method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @NonNull public static final android.os.Parcelable.Creator<android.window.TrustedPresentationThresholds> CREATOR;
+ field @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) public final float minAlpha;
+ field @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) public final float minFractionRendered;
+ field @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @IntRange(from=1) public final int stabilityRequirementMs;
+ }
+
}
package javax.microedition.khronos.egl {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f668088e6b44..3459e0b14b21 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -126,6 +126,8 @@ import android.window.ITrustedPresentationListener;
import android.window.TaskFpsCallback;
import android.window.TrustedPresentationThresholds;
+import com.android.window.flags.Flags;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -5888,18 +5890,18 @@ public interface WindowManager extends ViewManager {
}
/**
- * Add a trusted presentation listener associated with a window. If the listener has already
- * been registered, an AndroidRuntimeException will be thrown.
+ * Add a trusted presentation listener associated with a window.
+ *
+ * <p> If this listener is already registered then the window and thresholds will be updated.
*
- * @param window The Window to add the trusted presentation listener for
+ * @param window The Window to add the trusted presentation listener for
* @param thresholds The {@link TrustedPresentationThresholds} that will specify
* when the to invoke the callback.
* @param executor The {@link Executor} where the callback will be invoked on.
- * @param listener The {@link ITrustedPresentationListener} that will receive the callbacks
+ * @param listener The {@link Consumer} that will receive the callbacks
* when entered or exited trusted presentation per the thresholds.
- *
- * @hide b/287076178 un-hide with API bump
*/
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
default void registerTrustedPresentationListener(@NonNull IBinder window,
@NonNull TrustedPresentationThresholds thresholds, @NonNull Executor executor,
@NonNull Consumer<Boolean> listener) {
@@ -5910,10 +5912,9 @@ public interface WindowManager extends ViewManager {
* Removes a presentation listener associated with a window. If the listener was not previously
* registered, the call will be a noop.
*
- * @hide
- * @see #registerTrustedPresentationListener(IBinder,
- * TrustedPresentationThresholds, Executor, Consumer)
+ * @see WindowManager#registerTrustedPresentationListener(IBinder, TrustedPresentationThresholds, Executor, Consumer)
*/
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
default void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) {
throw new UnsupportedOperationException();
}
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index a7d814e9ab8c..f1e406196abf 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -820,7 +820,8 @@ public final class WindowManagerGlobal {
Consumer<Boolean> listener, Executor executor) {
synchronized (mTplLock) {
if (mListeners.containsKey(listener)) {
- throw new AndroidRuntimeException("Trying to add duplicate listener");
+ Log.i(TAG, "Updating listener " + listener + " thresholds to " + thresholds);
+ removeListener(listener);
}
int id = sId++;
mListeners.put(listener, new Pair<>(id, executor));
diff --git a/core/java/android/window/TrustedPresentationThresholds.java b/core/java/android/window/TrustedPresentationThresholds.java
index 801d35c49228..90f8834b37d1 100644
--- a/core/java/android/window/TrustedPresentationThresholds.java
+++ b/core/java/android/window/TrustedPresentationThresholds.java
@@ -16,40 +16,53 @@
package android.window;
+import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntRange;
+import android.annotation.SuppressLint;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.SurfaceControl;
import androidx.annotation.NonNull;
+import com.android.window.flags.Flags;
+
/**
- * @hide
+ * Threshold values that are sent with
+ * {@link android.view.WindowManager#registerTrustedPresentationListener(IBinder,
+ * TrustedPresentationThresholds, Executor, Consumer)}
*/
+@FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
public final class TrustedPresentationThresholds implements Parcelable {
/**
* The min alpha the {@link SurfaceControl} is required to have to be considered inside the
* threshold.
*/
@FloatRange(from = 0f, fromInclusive = false, to = 1f)
- public final float mMinAlpha;
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
+ @SuppressLint("InternalField") // simple data class
+ public final float minAlpha;
/**
* The min fraction of the SurfaceControl that was presented to the user to be considered
* inside the threshold.
*/
@FloatRange(from = 0f, fromInclusive = false, to = 1f)
- public final float mMinFractionRendered;
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
+ @SuppressLint("InternalField") // simple data class
+ public final float minFractionRendered;
/**
* The time in milliseconds required for the {@link SurfaceControl} to be in the threshold.
*/
@IntRange(from = 1)
- public final int mStabilityRequirementMs;
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
+ @SuppressLint("InternalField") // simple data class
+ public final int stabilityRequirementMs;
private void checkValid() {
- if (mMinAlpha <= 0 || mMinFractionRendered <= 0 || mStabilityRequirementMs < 1) {
+ if (minAlpha <= 0 || minFractionRendered <= 0 || stabilityRequirementMs < 1) {
throw new IllegalArgumentException(
"TrustedPresentationThresholds values are invalid");
}
@@ -67,33 +80,37 @@ public final class TrustedPresentationThresholds implements Parcelable {
* @param stabilityRequirementMs The time in milliseconds required for the
* {@link SurfaceControl} to be in the threshold.
*/
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
public TrustedPresentationThresholds(
@FloatRange(from = 0f, fromInclusive = false, to = 1f) float minAlpha,
@FloatRange(from = 0f, fromInclusive = false, to = 1f) float minFractionRendered,
@IntRange(from = 1) int stabilityRequirementMs) {
- this.mMinAlpha = minAlpha;
- this.mMinFractionRendered = minFractionRendered;
- this.mStabilityRequirementMs = stabilityRequirementMs;
+ this.minAlpha = minAlpha;
+ this.minFractionRendered = minFractionRendered;
+ this.stabilityRequirementMs = stabilityRequirementMs;
checkValid();
}
@Override
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
public String toString() {
return "TrustedPresentationThresholds { "
- + "minAlpha = " + mMinAlpha + ", "
- + "minFractionRendered = " + mMinFractionRendered + ", "
- + "stabilityRequirementMs = " + mStabilityRequirementMs
+ + "minAlpha = " + minAlpha + ", "
+ + "minFractionRendered = " + minFractionRendered + ", "
+ + "stabilityRequirementMs = " + stabilityRequirementMs
+ " }";
}
@Override
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeFloat(mMinAlpha);
- dest.writeFloat(mMinFractionRendered);
- dest.writeInt(mStabilityRequirementMs);
+ dest.writeFloat(minAlpha);
+ dest.writeFloat(minFractionRendered);
+ dest.writeInt(stabilityRequirementMs);
}
@Override
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
public int describeContents() {
return 0;
}
@@ -102,24 +119,24 @@ public final class TrustedPresentationThresholds implements Parcelable {
* @hide
*/
TrustedPresentationThresholds(@NonNull Parcel in) {
- mMinAlpha = in.readFloat();
- mMinFractionRendered = in.readFloat();
- mStabilityRequirementMs = in.readInt();
+ minAlpha = in.readFloat();
+ minFractionRendered = in.readFloat();
+ stabilityRequirementMs = in.readInt();
checkValid();
}
- /**
- * @hide
- */
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
public static final @NonNull Creator<TrustedPresentationThresholds> CREATOR =
new Creator<TrustedPresentationThresholds>() {
@Override
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
public TrustedPresentationThresholds[] newArray(int size) {
return new TrustedPresentationThresholds[size];
}
@Override
+ @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
public TrustedPresentationThresholds createFromParcel(@NonNull Parcel in) {
return new TrustedPresentationThresholds(in);
}
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 29932f342b74..56df49370379 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -56,3 +56,11 @@ flag {
is_fixed_read_only: true
bug: "308662081"
}
+
+flag {
+ namespace: "window_surfaces"
+ name: "trusted_presentation_listener_for_window"
+ description: "Enable trustedPresentationListener on windows public API"
+ is_fixed_read_only: true
+ bug: "278027319"
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
index e82dc37c2b6a..1688a1a91114 100644
--- a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
+++ b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
@@ -343,15 +343,15 @@ public class TrustedPresentationListenerController {
var listener = trustedPresentationInfo.mListener;
boolean lastState = trustedPresentationInfo.mLastComputedTrustedPresentationState;
boolean newState =
- (alpha >= trustedPresentationInfo.mThresholds.mMinAlpha) && (fractionRendered
- >= trustedPresentationInfo.mThresholds.mMinFractionRendered);
+ (alpha >= trustedPresentationInfo.mThresholds.minAlpha) && (fractionRendered
+ >= trustedPresentationInfo.mThresholds.minFractionRendered);
trustedPresentationInfo.mLastComputedTrustedPresentationState = newState;
ProtoLog.v(WM_DEBUG_TPL,
"lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f "
+ "minFractionRendered=%f",
- lastState, newState, alpha, trustedPresentationInfo.mThresholds.mMinAlpha,
- fractionRendered, trustedPresentationInfo.mThresholds.mMinFractionRendered);
+ lastState, newState, alpha, trustedPresentationInfo.mThresholds.minAlpha,
+ fractionRendered, trustedPresentationInfo.mThresholds.minFractionRendered);
if (lastState && !newState) {
// We were in the trusted presentation state, but now we left it,
@@ -371,13 +371,13 @@ public class TrustedPresentationListenerController {
trustedPresentationInfo.mEnteredTrustedPresentationStateTime = currTimeMs;
mHandler.postDelayed(() -> {
computeTpl(mLastWindowHandles);
- }, (long) (trustedPresentationInfo.mThresholds.mStabilityRequirementMs * 1.5));
+ }, (long) (trustedPresentationInfo.mThresholds.stabilityRequirementMs * 1.5));
}
// Has the timer elapsed, but we are still in the state? Emit a callback if needed
if (!trustedPresentationInfo.mLastReportedTrustedPresentationState && newState && (
currTimeMs - trustedPresentationInfo.mEnteredTrustedPresentationStateTime
- > trustedPresentationInfo.mThresholds.mStabilityRequirementMs)) {
+ > trustedPresentationInfo.mThresholds.stabilityRequirementMs)) {
trustedPresentationInfo.mLastReportedTrustedPresentationState = true;
addListenerUpdate(listenerUpdates, listener,
trustedPresentationInfo.mId, /*presentationState*/ true);
@@ -438,8 +438,8 @@ public class TrustedPresentationListenerController {
}
private void checkValid(TrustedPresentationThresholds thresholds) {
- if (thresholds.mMinAlpha <= 0 || thresholds.mMinFractionRendered <= 0
- || thresholds.mStabilityRequirementMs < 1) {
+ if (thresholds.minAlpha <= 0 || thresholds.minFractionRendered <= 0
+ || thresholds.stabilityRequirementMs < 1) {
throw new IllegalArgumentException(
"TrustedPresentationThresholds values are invalid");
}
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index a8d3fa110844..ef197918deff 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -99,11 +99,6 @@
android:theme="@style/WhiteBackgroundTheme"
android:exported="true"/>
- <activity android:name="com.android.server.wm.TrustedPresentationListenerTest$TestActivity"
- android:exported="true"
- android:showWhenLocked="true"
- android:turnScreenOn="true" />
-
<activity android:name="android.app.Activity"
android:exported="true"
android:showWhenLocked="true"
diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationListenerTest.java
deleted file mode 100644
index 96b66bfd3bc0..000000000000
--- a/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationListenerTest.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2023 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;
-
-import static android.server.wm.ActivityManagerTestBase.createFullscreenActivityScenarioRule;
-import static android.server.wm.BuildUtils.HW_TIMEOUT_MULTIPLIER;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.fail;
-
-import android.app.Activity;
-import android.os.SystemClock;
-import android.platform.test.annotations.Presubmit;
-import android.server.wm.CtsWindowInfoUtils;
-import android.util.AndroidRuntimeException;
-import android.util.Log;
-import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.View;
-import android.view.WindowManager;
-import android.window.TrustedPresentationThresholds;
-
-import androidx.annotation.GuardedBy;
-import androidx.annotation.NonNull;
-import androidx.test.ext.junit.rules.ActivityScenarioRule;
-
-import com.android.server.wm.utils.CommonUtils;
-
-import junit.framework.Assert;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-
-/**
- * TODO (b/287076178): Move these tests to
- * {@link android.view.surfacecontrol.cts.TrustedPresentationListenerTest} when API is made public
- */
-@Presubmit
-public class TrustedPresentationListenerTest {
- private static final String TAG = "TrustedPresentationListenerTest";
- private static final int STABILITY_REQUIREMENT_MS = 500;
- private static final long WAIT_TIME_MS = HW_TIMEOUT_MULTIPLIER * 2000L;
-
- private static final float FRACTION_VISIBLE = 0.1f;
-
- private final List<Boolean> mResults = Collections.synchronizedList(new ArrayList<>());
- private CountDownLatch mReceivedResults = new CountDownLatch(1);
-
- private TrustedPresentationThresholds mThresholds = new TrustedPresentationThresholds(
- 1 /* minAlpha */, FRACTION_VISIBLE, STABILITY_REQUIREMENT_MS);
-
- @Rule
- public TestName mName = new TestName();
-
- @Rule
- public ActivityScenarioRule<TestActivity> mActivityRule = createFullscreenActivityScenarioRule(
- TestActivity.class);
-
- private TestActivity mActivity;
-
- private SurfaceControlViewHost.SurfacePackage mSurfacePackage = null;
-
- @Before
- public void setup() {
- mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
- mDefaultListener = new Listener(mReceivedResults);
- }
-
- @After
- public void tearDown() {
- if (mSurfacePackage != null) {
- new SurfaceControl.Transaction().remove(mSurfacePackage.getSurfaceControl()).apply(
- true);
- mSurfacePackage.release();
- }
- CommonUtils.waitUntilActivityRemoved(mActivity);
-
- }
-
- private class Listener implements Consumer<Boolean> {
- final CountDownLatch mLatch;
-
- Listener(CountDownLatch latch) {
- mLatch = latch;
- }
-
- @Override
- public void accept(Boolean inTrustedPresentationState) {
- Log.d(TAG, "onTrustedPresentationChanged " + inTrustedPresentationState);
- mResults.add(inTrustedPresentationState);
- mLatch.countDown();
- }
- }
-
- private Consumer<Boolean> mDefaultListener;
-
- @Test
- public void testAddTrustedPresentationListenerOnWindow() {
- WindowManager windowManager = mActivity.getSystemService(WindowManager.class);
- windowManager.registerTrustedPresentationListener(
- mActivity.getWindow().getDecorView().getWindowToken(), mThresholds, Runnable::run,
- mDefaultListener);
- assertResults(List.of(true));
- }
-
- @Test
- public void testRemoveTrustedPresentationListenerOnWindow() throws InterruptedException {
- WindowManager windowManager = mActivity.getSystemService(WindowManager.class);
- windowManager.registerTrustedPresentationListener(
- mActivity.getWindow().getDecorView().getWindowToken(), mThresholds, Runnable::run,
- mDefaultListener);
- assertResults(List.of(true));
- // reset the latch
- mReceivedResults = new CountDownLatch(1);
-
- windowManager.unregisterTrustedPresentationListener(mDefaultListener);
- mReceivedResults.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
- // Ensure we waited the full time and never received a notify on the result from the
- // callback.
- assertEquals("Should never have received a callback", mReceivedResults.getCount(), 1);
- // results shouldn't have changed.
- assertEquals(mResults, List.of(true));
- }
-
- @Test
- public void testRemovingUnknownListenerIsANoop() {
- WindowManager windowManager = mActivity.getSystemService(WindowManager.class);
- assertNotNull(windowManager);
- windowManager.unregisterTrustedPresentationListener(mDefaultListener);
- }
-
- @Test
- public void testAddDuplicateListenerThrowsException() {
- WindowManager windowManager = mActivity.getSystemService(WindowManager.class);
- assertNotNull(windowManager);
- windowManager.registerTrustedPresentationListener(
- mActivity.getWindow().getDecorView().getWindowToken(), mThresholds,
- Runnable::run, mDefaultListener);
- assertThrows(AndroidRuntimeException.class,
- () -> windowManager.registerTrustedPresentationListener(
- mActivity.getWindow().getDecorView().getWindowToken(), mThresholds,
- Runnable::run, mDefaultListener));
- }
-
- @Test
- public void testAddDuplicateThresholds() {
- mReceivedResults = new CountDownLatch(2);
- mDefaultListener = new Listener(mReceivedResults);
- WindowManager windowManager = mActivity.getSystemService(WindowManager.class);
- windowManager.registerTrustedPresentationListener(
- mActivity.getWindow().getDecorView().getWindowToken(), mThresholds,
- Runnable::run, mDefaultListener);
-
- Consumer<Boolean> mNewListener = new Listener(mReceivedResults);
-
- windowManager.registerTrustedPresentationListener(
- mActivity.getWindow().getDecorView().getWindowToken(), mThresholds,
- Runnable::run, mNewListener);
- assertResults(List.of(true, true));
- }
-
- private void waitForViewAttach(View view) {
- final CountDownLatch viewAttached = new CountDownLatch(1);
- view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(@NonNull View v) {
- viewAttached.countDown();
- }
-
- @Override
- public void onViewDetachedFromWindow(@NonNull View v) {
-
- }
- });
- try {
- viewAttached.await(2000, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- if (!wait(viewAttached, 2000 /* waitTimeMs */)) {
- fail("Couldn't attach view=" + view);
- }
- }
-
- @Test
- public void testAddListenerToScvh() {
- WindowManager windowManager = mActivity.getSystemService(WindowManager.class);
-
- var embeddedView = new View(mActivity);
- mActivityRule.getScenario().onActivity(activity -> {
- var attachedSurfaceControl =
- mActivity.getWindow().getDecorView().getRootSurfaceControl();
- var scvh = new SurfaceControlViewHost(mActivity, mActivity.getDisplay(),
- attachedSurfaceControl.getHostToken());
- mSurfacePackage = scvh.getSurfacePackage();
- scvh.setView(embeddedView, mActivity.getWindow().getDecorView().getWidth(),
- mActivity.getWindow().getDecorView().getHeight());
- attachedSurfaceControl.buildReparentTransaction(
- mSurfacePackage.getSurfaceControl());
- });
-
- waitForViewAttach(embeddedView);
- windowManager.registerTrustedPresentationListener(embeddedView.getWindowToken(),
- mThresholds,
- Runnable::run, mDefaultListener);
-
- assertResults(List.of(true));
- }
-
- private boolean wait(CountDownLatch latch, long waitTimeMs) {
- while (true) {
- long now = SystemClock.uptimeMillis();
- try {
- return latch.await(waitTimeMs, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- long elapsedTime = SystemClock.uptimeMillis() - now;
- waitTimeMs = Math.max(0, waitTimeMs - elapsedTime);
- }
- }
-
- }
-
- @GuardedBy("mResultsLock")
- private void assertResults(List<Boolean> results) {
- if (!wait(mReceivedResults, WAIT_TIME_MS)) {
- try {
- CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, "test " + mName.getMethodName());
- } catch (InterruptedException e) {
- Log.d(TAG, "Couldn't dump windows", e);
- }
- Assert.fail("Timed out waiting for results mReceivedResults.count="
- + mReceivedResults.getCount() + "mReceivedResults=" + mReceivedResults);
- }
-
- // Make sure we received the results
- assertEquals(results.toArray(), mResults.toArray());
- }
-
- public static class TestActivity extends Activity {
- }
-}