diff options
| author | 2023-12-05 19:11:29 +0000 | |
|---|---|---|
| committer | 2023-12-08 04:14:55 +0000 | |
| commit | 99249ffe60473ed6ecedb5b9b74053d34bf723b3 (patch) | |
| tree | 98afb112bab05192f7600b38473c61d4c72b534a | |
| parent | 06ebddace6ffe6c21bb3ee11121d7bfd507e540d (diff) | |
Expose TrustedPresentationListener for Window
Bug: 278027319
Test: TrustedPresentationCallbackTest
Change-Id: I87d4a0b786daa9255ba150ff2409028b874c7b7b
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 { - } -} |