Merge "Implemented click events for gear, see all and pair new device." into main
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 213e5cb..7704486 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -10335,11 +10335,14 @@
* @return the current credential manager policy if null then this policy has not been
* configured.
*/
+ @UserHandleAware(
+ enabledSinceTargetSdkVersion = UPSIDE_DOWN_CAKE,
+ requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS)
public @Nullable PackagePolicy getCredentialManagerPolicy() {
throwIfParentInstance("getCredentialManagerPolicy");
if (mService != null) {
try {
- return mService.getCredentialManagerPolicy();
+ return mService.getCredentialManagerPolicy(myUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c49b820..58f9d57 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -346,7 +346,7 @@
boolean hasManagedProfileCallerIdAccess(int userId, String packageName);
void setCredentialManagerPolicy(in PackagePolicy policy);
- PackagePolicy getCredentialManagerPolicy();
+ PackagePolicy getCredentialManagerPolicy(int userId);
void setManagedProfileContactsAccessPolicy(in PackagePolicy policy);
PackagePolicy getManagedProfileContactsAccessPolicy();
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index febe6f7..a95e66d 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -16,7 +16,7 @@
flag {
name: "allow_private_profile"
- namespace: "private_profile"
+ namespace: "profile_experiences"
description: "Guards a new Private Profile type in UserManager - everything from its setup to config to deletion."
bug: "299069460"
}
diff --git a/core/java/com/android/internal/policy/AttributeCache.java b/core/java/com/android/internal/policy/AttributeCache.java
index 1bdad25..970f511 100644
--- a/core/java/com/android/internal/policy/AttributeCache.java
+++ b/core/java/com/android/internal/policy/AttributeCache.java
@@ -16,12 +16,18 @@
package com.android.internal.policy;
+import android.annotation.RequiresPermission;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.net.Uri;
+import android.os.Handler;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.LruCache;
@@ -46,6 +52,8 @@
@GuardedBy("this")
private final Configuration mConfiguration = new Configuration();
+ private PackageMonitor mPackageMonitor;
+
public final static class Package {
public final Context context;
private final SparseArray<ArrayMap<int[], Entry>> mMap = new SparseArray<>();
@@ -77,6 +85,34 @@
}
}
+ /**
+ * Start monitor package change, so the resources can be loaded correctly.
+ */
+ void monitorPackageRemove(Handler handler) {
+ if (mPackageMonitor == null) {
+ mPackageMonitor = new PackageMonitor(mContext, handler);
+ }
+ }
+
+ static class PackageMonitor extends BroadcastReceiver {
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ PackageMonitor(Context context, Handler handler) {
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
+ context.registerReceiverAsUser(this, UserHandle.ALL, filter,
+ null /* broadcastPermission */, handler);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final Uri packageUri = intent.getData();
+ if (packageUri != null) {
+ final String packageName = packageUri.getEncodedSchemeSpecificPart();
+ AttributeCache.instance().removePackage(packageName);
+ }
+ }
+ }
+
public static AttributeCache instance() {
return sInstance;
}
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index 8f4df80..40a437f 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -48,6 +48,7 @@
import android.hardware.HardwareBuffer;
import android.media.Image;
import android.media.ImageReader;
+import android.os.Handler;
import android.os.SystemProperties;
import android.util.Slog;
import android.view.InflateException;
@@ -1399,4 +1400,14 @@
// Approximation of WCAG 2.0 relative luminance.
return ((r * 8) + (g * 22) + (b * 2)) >> 5;
}
+
+ /**
+ * For non-system server process, it must call this method to initialize the AttributeCache and
+ * start monitor package change, so the resources can be loaded correctly.
+ */
+ public static void initAttributeCache(Context context, Handler handler) {
+ AttributeCache.init(context);
+ AttributeCache.instance().monitorPackageRemove(handler);
+ }
+
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index 13c0ac4..b71c48e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -76,6 +76,10 @@
private IRemoteTransition mOccludeByDreamTransition = null;
private IRemoteTransition mUnoccludeTransition = null;
+ // While set true, Keyguard has created a remote animation runner to handle the open app
+ // transition.
+ private boolean mIsLaunchingActivityOverLockscreen;
+
private final class StartedTransition {
final TransitionInfo mInfo;
final SurfaceControl.Transaction mFinishT;
@@ -120,7 +124,7 @@
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull TransitionFinishCallback finishCallback) {
- if (!handles(info)) {
+ if (!handles(info) || mIsLaunchingActivityOverLockscreen) {
return false;
}
@@ -313,5 +317,11 @@
mUnoccludeTransition = unoccludeTransition;
});
}
+
+ @Override
+ public void setLaunchingActivityOverLockscreen(boolean isLaunchingActivityOverLockscreen) {
+ mMainExecutor.execute(() ->
+ mIsLaunchingActivityOverLockscreen = isLaunchingActivityOverLockscreen);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitions.java
index b4b327f..33c299f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitions.java
@@ -38,4 +38,9 @@
@NonNull IRemoteTransition occludeTransition,
@NonNull IRemoteTransition occludeByDreamTransition,
@NonNull IRemoteTransition unoccludeTransition) {}
+
+ /**
+ * Notify whether keyguard has created a remote animation runner for next app launch.
+ */
+ default void setLaunchingActivityOverLockscreen(boolean isLaunchingActivityOverLockscreen) {}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 00f6a1c..83dc7fa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -111,6 +111,14 @@
WindowContainerTransaction mFinishWCT = null;
/**
+ * Whether the transition has request for remote transition while mLeftoversHandler
+ * isn't remote transition handler.
+ * If true and the mLeftoversHandler can handle the transition, need to notify remote
+ * transition handler to consume the transition.
+ */
+ boolean mHasRequestToRemote;
+
+ /**
* Mixed transitions are made up of multiple "parts". This keeps track of how many
* parts are currently animating.
*/
@@ -200,6 +208,10 @@
MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE, transition);
mixed.mLeftoversHandler = handler.first;
mActiveTransitions.add(mixed);
+ if (mixed.mLeftoversHandler != mPlayer.getRemoteTransitionHandler()) {
+ mixed.mHasRequestToRemote = true;
+ mPlayer.getRemoteTransitionHandler().handleRequest(transition, request);
+ }
return handler.second;
} else if (mSplitHandler.isSplitScreenVisible()
&& isOpeningType(request.getType())
@@ -316,12 +328,22 @@
// the time of handleRequest, but we need more information than is available at that time.
if (KeyguardTransitionHandler.handles(info)) {
if (mixed != null && mixed.mType != MixedTransition.TYPE_KEYGUARD) {
- ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
- "Converting mixed transition into a keyguard transition");
- onTransitionConsumed(transition, false, null);
+ final MixedTransition keyguardMixed =
+ new MixedTransition(MixedTransition.TYPE_KEYGUARD, transition);
+ mActiveTransitions.add(keyguardMixed);
+ final boolean hasAnimateKeyguard = animateKeyguard(keyguardMixed, info,
+ startTransaction, finishTransaction, finishCallback);
+ if (hasAnimateKeyguard) {
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "Converting mixed transition into a keyguard transition");
+ // Consume the original mixed transition
+ onTransitionConsumed(transition, false, null);
+ return true;
+ } else {
+ // Keyguard handler cannot handle it, process through original mixed
+ mActiveTransitions.remove(keyguardMixed);
+ }
}
- mixed = new MixedTransition(MixedTransition.TYPE_KEYGUARD, transition);
- mActiveTransitions.add(mixed);
}
if (mixed == null) return false;
@@ -332,8 +354,17 @@
} else if (mixed.mType == MixedTransition.TYPE_DISPLAY_AND_SPLIT_CHANGE) {
return false;
} else if (mixed.mType == MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE) {
- return animateOpenIntentWithRemoteAndPip(mixed, info, startTransaction,
- finishTransaction, finishCallback);
+ final boolean handledToPip = animateOpenIntentWithRemoteAndPip(mixed, info,
+ startTransaction, finishTransaction, finishCallback);
+ // Consume the transition on remote handler if the leftover handler already handle this
+ // transition. And if it cannot, the transition will be handled by remote handler, so
+ // don't consume here.
+ // Need to check leftOverHandler as it may change in #animateOpenIntentWithRemoteAndPip
+ if (handledToPip && mixed.mHasRequestToRemote
+ && mixed.mLeftoversHandler != mPlayer.getRemoteTransitionHandler()) {
+ mPlayer.getRemoteTransitionHandler().onTransitionConsumed(transition, false, null);
+ }
+ return handledToPip;
} else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_SPLIT) {
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
@@ -799,5 +830,8 @@
} else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
mUnfoldHandler.onTransitionConsumed(transition, aborted, finishT);
}
+ if (mixed.mHasRequestToRemote) {
+ mPlayer.getRemoteTransitionHandler().onTransitionConsumed(transition, aborted, finishT);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 7df658e..de03f58 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -99,7 +99,6 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.AttributeCache;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.common.ProtoLog;
@@ -182,7 +181,7 @@
/* broadcastPermission = */ null,
mMainHandler);
- AttributeCache.init(mContext);
+ TransitionAnimation.initAttributeCache(mContext, mMainHandler);
}
private void updateEnterpriseThumbnailDrawable() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
index 77f14f1..adf92d8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -50,7 +50,7 @@
}
@Before
- fun before() {
+ fun setUp() {
Assume.assumeTrue(tapl.isTablet && letterboxRule.isIgnoreOrientationRequest)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
new file mode 100644
index 0000000..ba2b3e7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
@@ -0,0 +1,199 @@
+/*
+ * 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.wm.shell.flicker.appcompat
+
+import android.os.Build
+import android.tools.common.datatypes.Rect
+import android.platform.test.annotations.Postsubmit
+import android.system.helpers.CommandsHelper
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.assertions.FlickerTest
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.device.helpers.FIND_TIMEOUT
+import android.tools.device.traces.parsers.toFlickerComponent
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.helpers.LetterboxAppHelper
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test rotating an immersive app in fullscreen.
+ *
+ * To run this test: `atest WMShellFlickerTestsOther:RotateImmersiveAppInFullscreenTest`
+ *
+ * Actions:
+ * ```
+ * Rotate the device by 90 degrees to trigger a rotation through sensors
+ * Verify that the button exists
+ * ```
+ *
+ * Notes:
+ * ```
+ * Some default assertions that are inherited from
+ * the `BaseTest` are ignored due to the nature of the immersive apps.
+ *
+ * This test only works with Cuttlefish devices.
+ * ```
+ */
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+class RotateImmersiveAppInFullscreenTest(flicker: LegacyFlickerTest) : BaseAppCompat(flicker) {
+
+ private val immersiveApp = LetterboxAppHelper(instrumentation,
+ launcherName = ActivityOptions.PortraitImmersiveActivity.LABEL,
+ component =
+ ActivityOptions.PortraitImmersiveActivity.COMPONENT.toFlickerComponent())
+
+ private val cmdHelper: CommandsHelper = CommandsHelper.getInstance(instrumentation)
+ private val execAdb: (String) -> String = { cmd -> cmdHelper.executeShellCommand(cmd) }
+
+ protected val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
+
+ private val isCuttlefishDevice: Boolean = Build.MODEL.contains("Cuttlefish")
+
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ setStartRotation()
+ immersiveApp.launchViaIntent(wmHelper)
+ startDisplayBounds =
+ wmHelper.currentState.layerState.physicalDisplayBounds
+ ?: error("Display not found")
+ }
+ transitions {
+ if (isCuttlefishDevice) {
+ // Simulates a device rotation through sensors because the rotation button
+ // only appears in a rotation event through sensors
+ execAdb("/vendor/bin/cuttlefish_sensor_injection rotate 0")
+ // verify rotation button existence
+ val rotationButtonSelector = By.res(LAUNCHER_PACKAGE, "rotate_suggestion")
+ uiDevice.wait(Until.hasObject(rotationButtonSelector), FIND_TIMEOUT)
+ uiDevice.findObject(rotationButtonSelector)
+ ?: error("rotation button not found")
+ }
+ }
+ teardown {
+ immersiveApp.exit(wmHelper)
+ }
+ }
+
+ @Before
+ fun setUpForImmersiveAppTests() {
+ Assume.assumeTrue(isCuttlefishDevice)
+ }
+
+ /** {@inheritDoc} */
+ @Test
+ @Ignore("Not applicable to this CUJ. App is in immersive mode.")
+ override fun taskBarLayerIsVisibleAtStartAndEnd() {
+ }
+
+ /** {@inheritDoc} */
+ @Test
+ @Ignore("Not applicable to this CUJ. App is in immersive mode.")
+ override fun navBarLayerIsVisibleAtStartAndEnd() {
+ }
+
+ /** {@inheritDoc} */
+ @Test
+ @Ignore("Not applicable to this CUJ. App is in immersive mode.")
+ override fun statusBarLayerIsVisibleAtStartAndEnd() {
+ }
+
+ /** {@inheritDoc} */
+ @Test
+ @Ignore("Not applicable to this CUJ. App is in immersive mode.")
+ override fun taskBarWindowIsAlwaysVisible() {
+ }
+
+ /** {@inheritDoc} */
+ @Test
+ @Ignore("Not applicable to this CUJ. App is in immersive mode.")
+ override fun navBarWindowIsAlwaysVisible() {
+ }
+
+ /** {@inheritDoc} */
+ @Test
+ @Ignore("Not applicable to this CUJ. App is in immersive mode.")
+ override fun statusBarWindowIsAlwaysVisible() {
+ }
+
+ @Test
+ @Ignore("Not applicable to this CUJ. App is in immersive mode.")
+ override fun statusBarLayerPositionAtStartAndEnd() {
+ }
+
+ @Test
+ @Ignore("Not applicable to this CUJ. App is in immersive mode.")
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ }
+
+ /** Test that app is fullscreen by checking status bar and task bar visibility. */
+ @Postsubmit
+ @Test
+ fun appWindowFullScreen() {
+ flicker.assertWmEnd {
+ this.isAppWindowInvisible(ComponentNameMatcher.STATUS_BAR)
+ .isAppWindowInvisible(ComponentNameMatcher.TASK_BAR)
+ .visibleRegion(immersiveApp).coversExactly(startDisplayBounds)
+ }
+ }
+
+ /** Test that app is in the original rotation we have set up. */
+ @Postsubmit
+ @Test
+ fun appInOriginalRotation() {
+ flicker.assertWmEnd {
+ this.hasRotation(Rotation.ROTATION_90)
+ }
+ }
+
+ companion object {
+ private var startDisplayBounds = Rect.EMPTY
+ const val LAUNCHER_PACKAGE = "com.google.android.apps.nexuslauncher"
+
+ /**
+ * Creates the test configurations.
+ *
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return LegacyFlickerTestFactory.nonRotationTests(
+ supportedRotations = listOf(Rotation.ROTATION_90),
+ // TODO(b/292403378): 3 button mode not added as rotation button is hidden in taskbar
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 8c81733..d1067a9 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -105,6 +105,13 @@
screen. -->
<item name="half_opened_bouncer_height_ratio" type="dimen" format="float">0.0</item>
+ <!-- Proportion of the screen height to use to set the maximum height of the bouncer to when
+ the device is in the DEVICE_POSTURE_HALF_OPENED posture.
+
+ This value is only used when motion layout bouncer is used - when flag
+ landscape.enable_lockscreen (b/293252410) is on -->
+ <item name="motion_layout_half_fold_bouncer_height_ratio" type="dimen" format="float">0.55</item>
+
<!-- The actual amount of translation that is applied to the security when it animates from one
side of the screen to the other in one-handed or user switcher mode. Note that it will
always translate from the side of the screen to the other (it will "jump" closer to the
diff --git a/packages/SystemUI/res-keyguard/xml/keyguard_pattern_scene.xml b/packages/SystemUI/res-keyguard/xml/keyguard_pattern_scene.xml
index 6112411..751d6d8 100644
--- a/packages/SystemUI/res-keyguard/xml/keyguard_pattern_scene.xml
+++ b/packages/SystemUI/res-keyguard/xml/keyguard_pattern_scene.xml
@@ -10,9 +10,34 @@
motion:duration="0"
motion:autoTransition="none"/>
+ <Transition
+ motion:constraintSetStart="@id/single_constraints"
+ motion:constraintSetEnd="@+id/half_folded_single_constraints"
+ motion:duration="@integer/material_motion_duration_short_1"
+ motion:autoTransition="none"/>
+
<!-- No changes to default layout -->
<ConstraintSet android:id="@+id/single_constraints"/>
+ <ConstraintSet android:id="@+id/half_folded_single_constraints">
+
+ <Constraint
+ android:id="@+id/pattern_top_guideline"
+ androidprv:layout_constraintGuide_percent=
+ "@dimen/motion_layout_half_fold_bouncer_height_ratio"/>
+
+ <Constraint
+ android:id="@+id/keyguard_selector_fade_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="0dp"
+ android:layout_marginTop="@dimen/keyguard_eca_top_margin"
+ android:orientation="vertical"
+ androidprv:layout_constraintBottom_toBottomOf="parent"
+ androidprv:layout_constraintTop_toBottomOf="@+id/flow1"/>
+
+ </ConstraintSet>
+
<ConstraintSet android:id="@+id/split_constraints">
<Constraint
diff --git a/packages/SystemUI/res-keyguard/xml/keyguard_pin_scene.xml b/packages/SystemUI/res-keyguard/xml/keyguard_pin_scene.xml
index 2a1270c..cc498f4 100644
--- a/packages/SystemUI/res-keyguard/xml/keyguard_pin_scene.xml
+++ b/packages/SystemUI/res-keyguard/xml/keyguard_pin_scene.xml
@@ -26,11 +26,35 @@
motion:constraintSetStart="@id/single_constraints"
motion:constraintSetEnd="@+id/split_constraints"
motion:duration="0"
- motion:autoTransition="none"/>
+ motion:autoTransition="none" />
+
+ <Transition
+ motion:constraintSetStart="@id/single_constraints"
+ motion:constraintSetEnd="@+id/half_folded_single_constraints"
+ motion:duration="@integer/material_motion_duration_short_1" />
<!-- No changes to default layout -->
<ConstraintSet android:id="@+id/single_constraints"/>
+ <ConstraintSet android:id="@+id/half_folded_single_constraints">
+
+ <Constraint
+ android:id="@+id/pin_pad_top_guideline"
+ androidprv:layout_constraintGuide_percent=
+ "@dimen/motion_layout_half_fold_bouncer_height_ratio"/>
+
+ <Constraint
+ android:id="@+id/keyguard_selector_fade_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="0dp"
+ android:layout_marginTop="@dimen/keyguard_eca_top_margin"
+ android:orientation="vertical"
+ androidprv:layout_constraintBottom_toBottomOf="parent"
+ androidprv:layout_constraintTop_toBottomOf="@+id/flow1"/>
+
+ </ConstraintSet>
+
<ConstraintSet android:id="@+id/split_constraints">
<Constraint
@@ -68,4 +92,5 @@
android:layout_marginTop="@dimen/keyguard_eca_top_margin" />
</ConstraintSet>
+
</MotionScene>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 1741e30..622b67f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -17,6 +17,7 @@
package com.android.keyguard;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_APPEAR;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR;
@@ -52,6 +53,8 @@
private final DisappearAnimationUtils mDisappearAnimationUtils;
private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
@Nullable private MotionLayout mContainerMotionLayout;
+ // TODO (b/293252410) - usage of mContainerConstraintLayout should be removed
+ // when the flag is enabled/removed
@Nullable private ConstraintLayout mContainerConstraintLayout;
private int mDisappearYTranslation;
private View[][] mViews;
@@ -59,7 +62,7 @@
private int mYTransOffset;
private View mBouncerMessageArea;
private boolean mAlreadyUsingSplitBouncer = false;
- private boolean mIsLockScreenLandscapeEnabled = false;
+ private boolean mIsSmallLockScreenLandscapeEnabled = false;
@DevicePostureInt private int mLastDevicePosture = DEVICE_POSTURE_UNKNOWN;
public static final long ANIMATION_DURATION = 650;
@@ -87,12 +90,12 @@
/** Use motion layout (new bouncer implementation) if LOCKSCREEN_ENABLE_LANDSCAPE flag is
* enabled, instead of constraint layout (old bouncer implementation) */
public void setIsLockScreenLandscapeEnabled(boolean isLockScreenLandscapeEnabled) {
- mIsLockScreenLandscapeEnabled = isLockScreenLandscapeEnabled;
+ mIsSmallLockScreenLandscapeEnabled = isLockScreenLandscapeEnabled;
findContainerLayout();
}
private void findContainerLayout() {
- if (mIsLockScreenLandscapeEnabled) {
+ if (mIsSmallLockScreenLandscapeEnabled) {
mContainerMotionLayout = findViewById(R.id.pin_container);
} else {
mContainerConstraintLayout = findViewById(R.id.pin_container);
@@ -109,7 +112,7 @@
if (mLastDevicePosture == posture) return;
mLastDevicePosture = posture;
- if (mIsLockScreenLandscapeEnabled) {
+ if (mIsSmallLockScreenLandscapeEnabled) {
boolean useSplitBouncerAfterFold =
mLastDevicePosture == DEVICE_POSTURE_CLOSED
&& getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE
@@ -166,21 +169,45 @@
}
}
+ if (mIsSmallLockScreenLandscapeEnabled) {
+ updateHalfFoldedConstraints();
+ } else {
+ updateHalfFoldedGuideline();
+ }
+ }
+
+ private void updateHalfFoldedConstraints() {
+ // Update the constraints based on the device posture...
+ if (mAlreadyUsingSplitBouncer) return;
+
+ boolean shouldCollapsePin =
+ mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED
+ && mContext.getResources().getConfiguration().orientation
+ == ORIENTATION_PORTRAIT;
+
+ int expectedMotionLayoutState = shouldCollapsePin
+ ? R.id.half_folded_single_constraints
+ : R.id.single_constraints;
+
+ transitionToMotionLayoutState(expectedMotionLayoutState);
+ }
+
+ // TODO (b/293252410) - this method can be removed when the flag is enabled/removed
+ private void updateHalfFoldedGuideline() {
// Update the guideline based on the device posture...
float halfOpenPercentage =
mContext.getResources().getFloat(R.dimen.half_opened_bouncer_height_ratio);
- if (mIsLockScreenLandscapeEnabled) {
- ConstraintSet cs = mContainerMotionLayout.getConstraintSet(R.id.single_constraints);
- cs.setGuidelinePercent(R.id.pin_pad_top_guideline,
- mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED ? halfOpenPercentage : 0.0f);
- cs.applyTo(mContainerMotionLayout);
- } else {
- ConstraintSet cs = new ConstraintSet();
- cs.clone(mContainerConstraintLayout);
- cs.setGuidelinePercent(R.id.pin_pad_top_guideline,
- mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED ? halfOpenPercentage : 0.0f);
- cs.applyTo(mContainerConstraintLayout);
+ ConstraintSet cs = new ConstraintSet();
+ cs.clone(mContainerConstraintLayout);
+ cs.setGuidelinePercent(R.id.pin_pad_top_guideline,
+ mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED ? halfOpenPercentage : 0.0f);
+ cs.applyTo(mContainerConstraintLayout);
+ }
+
+ private void transitionToMotionLayoutState(int state) {
+ if (mContainerMotionLayout.getCurrentState() != state) {
+ mContainerMotionLayout.transitionToState(state);
}
}
@@ -189,12 +216,24 @@
* Only called when flag LANDSCAPE_ENABLE_LOCKSCREEN is enabled. */
@Override
protected void updateConstraints(boolean useSplitBouncer) {
+ if (!mIsSmallLockScreenLandscapeEnabled) return;
+
mAlreadyUsingSplitBouncer = useSplitBouncer;
+
if (useSplitBouncer) {
mContainerMotionLayout.jumpToState(R.id.split_constraints);
mContainerMotionLayout.setMaxWidth(Integer.MAX_VALUE);
} else {
- mContainerMotionLayout.jumpToState(R.id.single_constraints);
+ boolean useHalfFoldedConstraints =
+ mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED
+ && mContext.getResources().getConfiguration().orientation
+ == ORIENTATION_PORTRAIT;
+
+ if (useHalfFoldedConstraints) {
+ mContainerMotionLayout.jumpToState(R.id.half_folded_single_constraints);
+ } else {
+ mContainerMotionLayout.jumpToState(R.id.single_constraints);
+ }
mContainerMotionLayout.setMaxWidth(getResources()
.getDimensionPixelSize(R.dimen.keyguard_security_width));
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 802e222..5c206e9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
@@ -81,9 +82,11 @@
BouncerKeyguardMessageArea mSecurityMessageDisplay;
private View mEcaView;
@Nullable private MotionLayout mContainerMotionLayout;
+ // TODO (b/293252410) - usage of mContainerConstraintLayout should be removed
+ // when the flag is enabled/removed
@Nullable private ConstraintLayout mContainerConstraintLayout;
private boolean mAlreadyUsingSplitBouncer = false;
- private boolean mIsLockScreenLandscapeEnabled = false;
+ private boolean mIsSmallLockScreenLandscapeEnabled = false;
@DevicePostureInt private int mLastDevicePosture = DEVICE_POSTURE_UNKNOWN;
public KeyguardPatternView(Context context) {
@@ -111,12 +114,12 @@
* enabled, instead of constraint layout (old bouncer implementation)
*/
public void setIsLockScreenLandscapeEnabled(boolean isLockScreenLandscapeEnabled) {
- mIsLockScreenLandscapeEnabled = isLockScreenLandscapeEnabled;
+ mIsSmallLockScreenLandscapeEnabled = isLockScreenLandscapeEnabled;
findContainerLayout();
}
private void findContainerLayout() {
- if (mIsLockScreenLandscapeEnabled) {
+ if (mIsSmallLockScreenLandscapeEnabled) {
mContainerMotionLayout = findViewById(R.id.pattern_container);
} else {
mContainerConstraintLayout = findViewById(R.id.pattern_container);
@@ -132,7 +135,7 @@
if (mLastDevicePosture == posture) return;
mLastDevicePosture = posture;
- if (mIsLockScreenLandscapeEnabled) {
+ if (mIsSmallLockScreenLandscapeEnabled) {
boolean useSplitBouncerAfterFold =
mLastDevicePosture == DEVICE_POSTURE_CLOSED
&& getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE
@@ -147,21 +150,45 @@
}
private void updateMargins() {
+ if (mIsSmallLockScreenLandscapeEnabled) {
+ updateHalfFoldedConstraints();
+ } else {
+ updateHalfFoldedGuideline();
+ }
+ }
+
+ private void updateHalfFoldedConstraints() {
+ // Update the constraints based on the device posture...
+ if (mAlreadyUsingSplitBouncer) return;
+
+ boolean shouldCollapsePattern =
+ mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED
+ && mContext.getResources().getConfiguration().orientation
+ == ORIENTATION_PORTRAIT;
+
+ int expectedMotionLayoutState = shouldCollapsePattern
+ ? R.id.half_folded_single_constraints
+ : R.id.single_constraints;
+
+ transitionToMotionLayoutState(expectedMotionLayoutState);
+ }
+
+ // TODO (b/293252410) - this method can be removed when the flag is enabled/removed
+ private void updateHalfFoldedGuideline() {
// Update the guideline based on the device posture...
float halfOpenPercentage =
mContext.getResources().getFloat(R.dimen.half_opened_bouncer_height_ratio);
- if (mIsLockScreenLandscapeEnabled) {
- ConstraintSet cs = mContainerMotionLayout.getConstraintSet(R.id.single_constraints);
- cs.setGuidelinePercent(R.id.pattern_top_guideline,
- mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED ? halfOpenPercentage : 0.0f);
- cs.applyTo(mContainerMotionLayout);
- } else {
- ConstraintSet cs = new ConstraintSet();
- cs.clone(mContainerConstraintLayout);
- cs.setGuidelinePercent(R.id.pattern_top_guideline,
- mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED ? halfOpenPercentage : 0.0f);
- cs.applyTo(mContainerConstraintLayout);
+ ConstraintSet cs = new ConstraintSet();
+ cs.clone(mContainerConstraintLayout);
+ cs.setGuidelinePercent(R.id.pattern_top_guideline,
+ mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED ? halfOpenPercentage : 0.0f);
+ cs.applyTo(mContainerConstraintLayout);
+ }
+
+ private void transitionToMotionLayoutState(int state) {
+ if (mContainerMotionLayout.getCurrentState() != state) {
+ mContainerMotionLayout.transitionToState(state);
}
}
@@ -172,12 +199,24 @@
*/
@Override
protected void updateConstraints(boolean useSplitBouncer) {
+ if (!mIsSmallLockScreenLandscapeEnabled) return;
+
mAlreadyUsingSplitBouncer = useSplitBouncer;
+
if (useSplitBouncer) {
mContainerMotionLayout.jumpToState(R.id.split_constraints);
mContainerMotionLayout.setMaxWidth(Integer.MAX_VALUE);
} else {
- mContainerMotionLayout.jumpToState(R.id.single_constraints);
+ boolean useHalfFoldedConstraints =
+ mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED
+ && mContext.getResources().getConfiguration().orientation
+ == ORIENTATION_PORTRAIT;
+
+ if (useHalfFoldedConstraints) {
+ mContainerMotionLayout.jumpToState(R.id.half_folded_single_constraints);
+ } else {
+ mContainerMotionLayout.jumpToState(R.id.single_constraints);
+ }
mContainerMotionLayout.setMaxWidth(getResources()
.getDimensionPixelSize(R.dimen.biometric_auth_pattern_view_max_size));
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
index 9c4d224..ec2999f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -139,12 +139,12 @@
onViewInflatedListener.onViewInflated(childController);
// Single bouncer constrains are default
- if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)
- &&
- getResources().getBoolean(R.bool.update_bouncer_constraints)) {
+ if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)) {
boolean useSplitBouncer =
- getResources().getConfiguration().orientation
+ getResources().getBoolean(R.bool.update_bouncer_constraints)
+ && getResources().getConfiguration().orientation
== ORIENTATION_LANDSCAPE;
+
updateConstraints(useSplitBouncer);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index efd25d5..b506a36 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -3798,6 +3798,13 @@
}
/**
+ * Notify whether keyguard has created a remote animation runner for next app launch.
+ */
+ public void launchingActivityOverLockscreen(boolean isLaunchingActivityOverLockscreen) {
+ mKeyguardTransitions.setLaunchingActivityOverLockscreen(isLaunchingActivityOverLockscreen);
+ }
+
+ /**
* Implementation of RemoteAnimationRunner that creates a new
* {@link ActivityLaunchAnimator.Runner} whenever onAnimationStart is called, delegating the
* remote animation methods to that runner.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 3a88504..6f69ea81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -3429,6 +3429,7 @@
@Override
public void setIsLaunchingActivityOverLockscreen(boolean isLaunchingActivityOverLockscreen) {
mIsLaunchingActivityOverLockscreen = isLaunchingActivityOverLockscreen;
+ mKeyguardViewMediator.launchingActivityOverLockscreen(mIsLaunchingActivityOverLockscreen);
}
@Override
diff --git a/services/Android.bp b/services/Android.bp
index 9264172..f237095 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -34,17 +34,18 @@
},
}
-// Opt-in config for optimizing and shrinking the services target using R8.
-// Enabled via `export SYSTEM_OPTIMIZE_JAVA=true`, or explicitly in Make via the
+// Config to control optimizing and shrinking the services target using R8.
+// Set via `export SYSTEM_OPTIMIZE_JAVA=true|false`, or explicitly in Make via the
// `SOONG_CONFIG_ANDROID_SYSTEM_OPTIMIZE_JAVA` variable.
-// TODO(b/196084106): Enable optimizations by default after stabilizing and
-// building out retrace infrastructure.
soong_config_module_type {
name: "system_optimized_java_defaults",
module_type: "java_defaults",
config_namespace: "ANDROID",
bool_variables: ["SYSTEM_OPTIMIZE_JAVA"],
- properties: ["optimize"],
+ properties: [
+ "optimize",
+ "dxflags",
+ ],
}
system_optimized_java_defaults {
@@ -75,6 +76,9 @@
// permission subpackage to prune unused jarjar'ed Kotlin dependencies.
proguard_flags_files: ["proguard_permission.flags"],
},
+ // Explicitly configure R8 to preserve debug info, as this path should
+ // really only allow stripping of permission-specific code and deps.
+ dxflags: ["--debug"],
},
},
},
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index f328b22..31e5cb8 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -53,7 +53,7 @@
import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensorEvent;
import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledSince;
+import android.compat.annotation.EnabledAfter;
import android.content.AttributionSource;
import android.content.ComponentName;
import android.content.Context;
@@ -131,7 +131,7 @@
* @see DisplayManager#VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT
*/
@ChangeId
- @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public static final long MAKE_VIRTUAL_DISPLAY_FLAGS_CONSISTENT_WITH_DISPLAY_MANAGER =
294837146L;
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index cd867f6..2e5f2dc 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -408,12 +408,6 @@
}
}
- void stop() {
- if (mEglContext != null && mEglDisplay != null) {
- EGL14.eglDestroyContext(mEglDisplay, mEglContext);
- }
- }
-
/**
* Draws an animation frame showing the color fade activated at the
* specified level.
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index bc81491..83f4df9 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -3577,8 +3577,7 @@
DisplayPowerState getDisplayPowerState(DisplayBlanker blanker, ColorFade colorFade,
int displayId, int displayState) {
- return new DisplayPowerState(blanker, colorFade, displayId, displayState,
- new Handler(/*async=*/ true));
+ return new DisplayPowerState(blanker, colorFade, displayId, displayState);
}
DualRampAnimator<DisplayPowerState> getDualRampAnimator(DisplayPowerState dps,
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 90a8490..b0d293a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -324,6 +324,8 @@
// Must only be accessed on the handler thread.
private DisplayPowerState mPowerState;
+
+
// The currently active screen on unblocker. This field is non-null whenever
// we are waiting for a callback to release it and unblock the screen.
private ScreenOnUnblocker mPendingScreenOnUnblocker;
@@ -2914,8 +2916,7 @@
DisplayPowerState getDisplayPowerState(DisplayBlanker blanker, ColorFade colorFade,
int displayId, int displayState) {
- return new DisplayPowerState(blanker, colorFade, displayId, displayState,
- new Handler(/*async=*/ true));
+ return new DisplayPowerState(blanker, colorFade, displayId, displayState);
}
DualRampAnimator<DisplayPowerState> getDualRampAnimator(DisplayPowerState dps,
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 85c6a6d..2c257a1 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -74,9 +74,8 @@
private volatile boolean mStopped;
DisplayPowerState(
- DisplayBlanker blanker, ColorFade colorFade, int displayId, int displayState,
- Handler handler) {
- mHandler = handler;
+ DisplayBlanker blanker, ColorFade colorFade, int displayId, int displayState) {
+ mHandler = new Handler(true /*async*/);
mChoreographer = Choreographer.getInstance();
mBlanker = blanker;
mColorFade = colorFade;
@@ -318,7 +317,6 @@
mStopped = true;
mPhotonicModulator.interrupt();
dismissColorFade();
- stopColorFade();
mCleanListener = null;
mHandler.removeCallbacksAndMessages(null);
}
@@ -378,11 +376,6 @@
}
}
- // Clears up color fade resources.
- private void stopColorFade() {
- if (mColorFade != null) mColorFade.stop();
- }
-
private final Runnable mScreenUpdateRunnable = new Runnable() {
@Override
public void run() {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
index 7045e65..c01bc20 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
@@ -868,6 +868,28 @@
}
@ServiceThreadOnly
+ void removeUnusedLocalDevices(ArrayList<HdmiCecLocalDevice> allocatedDevices) {
+ ArrayList<Integer> deviceTypesToRemove = new ArrayList<>();
+ for (int i = 0; i < mLocalDevices.size(); i++) {
+ int deviceType = mLocalDevices.keyAt(i);
+ boolean shouldRemoveLocalDevice = allocatedDevices.stream().noneMatch(
+ localDevice -> localDevice.getDeviceInfo() != null
+ && localDevice.getDeviceInfo().getDeviceType() == deviceType);
+ if (shouldRemoveLocalDevice) {
+ deviceTypesToRemove.add(deviceType);
+ }
+ }
+ for (Integer deviceType : deviceTypesToRemove) {
+ mLocalDevices.remove(deviceType);
+ }
+ }
+
+ @ServiceThreadOnly
+ void removeLocalDeviceWithType(int deviceType) {
+ mLocalDevices.remove(deviceType);
+ }
+
+ @ServiceThreadOnly
public void clearDeviceList() {
assertRunOnServiceThread();
for (HdmiDeviceInfo info : HdmiUtils.sparseArrayToList(mDeviceInfos)) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 232bc47..429db5e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1313,9 +1313,6 @@
localDevice.init();
localDevices.add(localDevice);
}
- // It's now safe to flush existing local devices from mCecController since they were
- // already moved to 'localDevices'.
- clearCecLocalDevices();
mHdmiCecNetwork.clearDeviceList();
allocateLogicalAddress(localDevices, initiatedBy);
}
@@ -1344,6 +1341,7 @@
if (logicalAddress == Constants.ADDR_UNREGISTERED) {
Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType
+ "]");
+ mHdmiCecNetwork.removeLocalDeviceWithType(deviceType);
} else {
// Set POWER_STATUS_ON to all local devices because they share
// lifetime
@@ -1352,6 +1350,8 @@
deviceType,
HdmiControlManager.POWER_STATUS_ON, getCecVersion());
localDevice.setDeviceInfo(deviceInfo);
+ // If a local device of the same type already exists, it will be
+ // replaced.
mHdmiCecNetwork.addLocalDevice(deviceType, localDevice);
mHdmiCecNetwork.addCecDevice(localDevice.getDeviceInfo());
mCecController.addLogicalAddress(logicalAddress);
@@ -1367,6 +1367,10 @@
// since we reallocate the logical address only.
onInitializeCecComplete(initiatedBy);
}
+ // We remove local devices here, instead of before the start of
+ // address allocation, to prevent multiple local devices of the
+ // same type from existing simultaneously.
+ mHdmiCecNetwork.removeUnusedLocalDevices(allocatedDevices);
mAddressAllocated = true;
notifyAddressAllocated(allocatedDevices, initiatedBy);
// Reinvoke the saved display status callback once the local
@@ -1386,9 +1390,19 @@
}
}
+ /**
+ * Notifies local devices that address allocation finished.
+ * @param devices - list of local devices allocated.
+ * @param initiatedBy - reason for the address allocation.
+ */
+ @VisibleForTesting
@ServiceThreadOnly
- private void notifyAddressAllocated(ArrayList<HdmiCecLocalDevice> devices, int initiatedBy) {
+ public void notifyAddressAllocated(ArrayList<HdmiCecLocalDevice> devices, int initiatedBy) {
assertRunOnServiceThread();
+ if (devices == null || devices.isEmpty()) {
+ Slog.w(TAG, "No local device to notify.");
+ return;
+ }
List<HdmiCecMessage> bufferedMessages = mCecMessageBuffer.getBuffer();
for (HdmiCecLocalDevice device : devices) {
int address = device.getDeviceInfo().getLogicalAddress();
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d824534..a0c7870 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2887,7 +2887,7 @@
final boolean animate;
if (mStartingData != null) {
if (mStartingData.mWaitForSyncTransactionCommit
- || mTransitionController.inCollectingTransition(startingWindow)) {
+ || mTransitionController.isCollecting(this)) {
mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_REMOVE_DIRECTLY;
mStartingData.mPrepareRemoveAnimation = prepareAnimation;
return;
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 2d281c4..07ffa69e 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -108,4 +108,13 @@
boolean hasImeSurface() {
return false;
}
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " waitForSyncTransactionCommit=" + mWaitForSyncTransactionCommit
+ + " removeAfterTransaction= " + mRemoveAfterTransaction
+ + "}";
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 84d1a45..f604932 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -16017,16 +16017,20 @@
}
@Override
- public PackagePolicy getCredentialManagerPolicy() {
+ public PackagePolicy getCredentialManagerPolicy(int userId) {
if (!mHasFeature) {
return null;
}
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(
canWriteCredentialManagerPolicy(caller) || canQueryAdminPolicy(caller));
+ if (userId != caller.getUserId()) {
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS));
+ }
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(userId);
return (admin != null) ? admin.mCredentialManagerPolicy : null;
}
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
index 9174899..a56b59a 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -1255,21 +1255,6 @@
}
@Test
- public void testPowerStateStopsOnDpcStop() {
- // Set up
- DisplayPowerRequest dpr = new DisplayPowerRequest();
- mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
- advanceTime(1);
-
- // Stop dpc
- mHolder.dpc.stop();
- advanceTime(1);
-
- // Ensure dps has stopped
- verify(mHolder.displayPowerState, times(1)).stop();
- }
-
- @Test
public void testRampRateForHdrContent_HdrClamperOff() {
float hdrBrightness = 0.8f;
float clampedBrightness = 0.6f;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 412b65f..0572117 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1191,21 +1191,6 @@
}
@Test
- public void testPowerStateStopsOnDpcStop() {
- // Set up
- DisplayPowerRequest dpr = new DisplayPowerRequest();
- mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
- advanceTime(1);
-
- // Stop dpc
- mHolder.dpc.stop();
- advanceTime(1);
-
- // Ensure dps has stopped
- verify(mHolder.displayPowerState, times(1)).stop();
- }
-
- @Test
public void testDisplayBrightnessHdr_SkipAnimationOnHdrAppearance() {
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.java
deleted file mode 100644
index 167a412..0000000
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.java
+++ /dev/null
@@ -1,64 +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.display;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-
-import static org.mockito.Mockito.times;
-
-import android.os.Handler;
-import android.os.test.TestLooper;
-import android.view.Display;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-
-@SmallTest
-public class DisplayPowerStateTest {
- private static final int DISPLAY_ID = 123;
-
- private DisplayPowerState mDisplayPowerState;
- private TestLooper mTestLooper;
- @Mock
- private DisplayBlanker mDisplayBlankerMock;
- @Mock
- private ColorFade mColorFadeMock;
-
- @Rule
- public final MockitoRule mMockitoRule = MockitoJUnit.rule();
-
- @Before
- public void setUp() {
- mTestLooper = new TestLooper();
- mDisplayPowerState = new DisplayPowerState(
- mDisplayBlankerMock, mColorFadeMock, DISPLAY_ID, Display.STATE_ON,
- new Handler(mTestLooper.getLooper()));
- }
-
- @Test
- public void testColorFadeStopsOnDpsStop() {
- mDisplayPowerState.stop();
- verify(mColorFadeMock, times(1)).stop();
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 0d172fdb..708ee35 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -21,8 +21,15 @@
import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
+import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_3;
import static com.android.server.hdmi.HdmiControlService.DEVICE_CLEANUP_TIMEOUT;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
+import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_HOTPLUG;
+import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_SCREEN_ON;
+import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_SOUNDBAR_MODE;
import static com.android.server.hdmi.HdmiControlService.WAKE_UP_SCREEN_ON;
import static com.google.common.truth.Truth.assertThat;
@@ -51,6 +58,7 @@
import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
import android.hardware.hdmi.IHdmiControlStatusChangeListener;
import android.hardware.hdmi.IHdmiVendorCommandListener;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.Binder;
import android.os.Looper;
import android.os.RemoteException;
@@ -71,6 +79,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Optional;
+import java.util.concurrent.TimeUnit;
/**
* Tests for {@link HdmiControlService} class.
@@ -137,7 +146,7 @@
mLocalDevices.add(mAudioSystemDeviceSpy);
mLocalDevices.add(mPlaybackDeviceSpy);
- mHdmiPortInfo = new HdmiPortInfo[4];
+ mHdmiPortInfo = new HdmiPortInfo[5];
mHdmiPortInfo[0] =
new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_INPUT, 0x2100)
.setCecSupported(true)
@@ -166,6 +175,13 @@
.setArcSupported(false)
.setEarcSupported(false)
.build();
+ mHdmiPortInfo[4] =
+ new HdmiPortInfo.Builder(4, HdmiPortInfo.PORT_OUTPUT, 0x3000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .setEarcSupported(false)
+ .build();
mNativeWrapper.setPortInfo(mHdmiPortInfo);
mHdmiControlServiceSpy.initService();
mWakeLockSpy = spy(new FakePowerManagerWrapper.FakeWakeLockWrapper());
@@ -1396,6 +1412,207 @@
}
@Test
+ public void triggerMultipleAddressAllocations_uniqueLocalDevicePerDeviceType() {
+ long allocationDelay = TimeUnit.SECONDS.toMillis(60);
+ mHdmiCecController.setLogicalAddressAllocationDelay(allocationDelay);
+ mTestLooper.dispatchAll();
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ // Wake up process that will trigger the address allocation to start.
+ mHdmiControlServiceSpy.onWakeUp(HdmiControlService.WAKE_UP_SCREEN_ON);
+ verify(mHdmiControlServiceSpy, times(1))
+ .allocateLogicalAddress(any(), eq(INITIATED_BY_SCREEN_ON));
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+ mTestLooper.dispatchAll();
+
+ mTestLooper.moveTimeForward(allocationDelay / 2);
+ mTestLooper.dispatchAll();
+ // Hotplug In will trigger the address allocation to start.
+ mHdmiControlServiceSpy.onHotplug(4, true);
+ verify(mHdmiControlServiceSpy, times(1))
+ .allocateLogicalAddress(any(), eq(INITIATED_BY_HOTPLUG));
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ mTestLooper.moveTimeForward(allocationDelay / 2);
+ mTestLooper.dispatchAll();
+ // The first allocation finished. The second allocation is still in progress.
+ HdmiCecLocalDevicePlayback firstAllocatedPlayback = mHdmiControlServiceSpy.playback();
+ verify(mHdmiControlServiceSpy, times(1))
+ .notifyAddressAllocated(any(), eq(INITIATED_BY_SCREEN_ON));
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ mTestLooper.moveTimeForward(allocationDelay / 2);
+ mTestLooper.dispatchAll();
+ // The second allocation finished.
+ HdmiCecLocalDevicePlayback secondAllocatedPlayback = mHdmiControlServiceSpy.playback();
+ verify(mHdmiControlServiceSpy, times(1))
+ .notifyAddressAllocated(any(), eq(INITIATED_BY_HOTPLUG));
+ // Local devices have the same identity.
+ assertTrue(firstAllocatedPlayback == secondAllocatedPlayback);
+ }
+
+ @Test
+ public void triggerMultipleAddressAllocations_keepLastAllocatedAddress() {
+ // First logical address for playback is free.
+ mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.NACK);
+ mTestLooper.dispatchAll();
+
+ long allocationDelay = TimeUnit.SECONDS.toMillis(60);
+ mHdmiCecController.setLogicalAddressAllocationDelay(allocationDelay);
+ mTestLooper.dispatchAll();
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ // Wake up process that will trigger the address allocation to start.
+ mHdmiControlServiceSpy.onWakeUp(HdmiControlService.WAKE_UP_SCREEN_ON);
+ verify(mHdmiControlServiceSpy, times(1))
+ .allocateLogicalAddress(any(), eq(INITIATED_BY_SCREEN_ON));
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+ mTestLooper.dispatchAll();
+
+ mTestLooper.moveTimeForward(allocationDelay / 2);
+ mTestLooper.dispatchAll();
+
+ // First logical address for playback is busy.
+ mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlServiceSpy.onWakeUp(HdmiControlService.WAKE_UP_SCREEN_ON);
+ verify(mHdmiControlServiceSpy, times(1))
+ .allocateLogicalAddress(any(), eq(INITIATED_BY_SCREEN_ON));
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+ mTestLooper.dispatchAll();
+
+ mTestLooper.moveTimeForward(allocationDelay / 2);
+ mTestLooper.dispatchAll();
+ // The first allocation finished. The second allocation is still in progress.
+ verify(mHdmiControlServiceSpy, times(1))
+ .notifyAddressAllocated(any(), eq(INITIATED_BY_SCREEN_ON));
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ mTestLooper.moveTimeForward(allocationDelay / 2);
+ mTestLooper.dispatchAll();
+ // The second allocation finished. Second logical address for playback is used.
+ HdmiCecLocalDevicePlayback allocatedPlayback = mHdmiControlServiceSpy.playback();
+ verify(mHdmiControlServiceSpy, times(1))
+ .notifyAddressAllocated(any(), eq(INITIATED_BY_SCREEN_ON));
+ assertThat(allocatedPlayback.getDeviceInfo().getLogicalAddress())
+ .isEqualTo(ADDR_PLAYBACK_2);
+ }
+
+ @Test
+ public void triggerMultipleAddressAllocations_toggleSoundbarMode_addThenRemoveAudioSystem() {
+ mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
+ long allocationDelay = TimeUnit.SECONDS.toMillis(60);
+ mHdmiCecController.setLogicalAddressAllocationDelay(allocationDelay);
+ mTestLooper.dispatchAll();
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ // Enabling Dynamic soundbar mode will trigger address allocation.
+ mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
+ HdmiControlManager.SOUNDBAR_MODE_ENABLED);
+ mTestLooper.dispatchAll();
+ verify(mHdmiControlServiceSpy, times(1))
+ .allocateLogicalAddress(any(), eq(INITIATED_BY_SOUNDBAR_MODE));
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ mTestLooper.moveTimeForward(allocationDelay / 2);
+ mTestLooper.dispatchAll();
+ // Disabling Dynamic soundbar mode will trigger another address allocation.
+ mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
+ HdmiControlManager.SOUNDBAR_MODE_DISABLED);
+ mTestLooper.dispatchAll();
+ verify(mHdmiControlServiceSpy, times(1))
+ .allocateLogicalAddress(any(), eq(INITIATED_BY_SOUNDBAR_MODE));
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ mTestLooper.moveTimeForward(allocationDelay / 2);
+ mTestLooper.dispatchAll();
+ // The first allocation finished. The second allocation is still in progress.
+ // The audio system is present in the network.
+ verify(mHdmiControlServiceSpy, times(1))
+ .notifyAddressAllocated(any(), eq(INITIATED_BY_SOUNDBAR_MODE));
+ assertThat(mHdmiControlServiceSpy.audioSystem()).isNotNull();
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ mTestLooper.moveTimeForward(allocationDelay / 2);
+ mTestLooper.dispatchAll();
+ // The second allocation finished. The audio system is not present in the network.
+ verify(mHdmiControlServiceSpy, times(1))
+ .notifyAddressAllocated(any(), eq(INITIATED_BY_SOUNDBAR_MODE));
+ assertThat(mHdmiControlServiceSpy.audioSystem()).isNull();
+ }
+
+ @Test
+ public void triggerMultipleAddressAllocations_toggleSoundbarMode_removeThenAddAudioSystem() {
+ mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
+ // Enable the setting and check if the audio system local device is found in the network.
+ mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
+ HdmiControlManager.SOUNDBAR_MODE_ENABLED);
+ mTestLooper.dispatchAll();
+ assertThat(mHdmiControlServiceSpy.audioSystem()).isNotNull();
+
+ long allocationDelay = TimeUnit.SECONDS.toMillis(60);
+ mHdmiCecController.setLogicalAddressAllocationDelay(allocationDelay);
+ mTestLooper.dispatchAll();
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ // Disabling Dynamic soundbar mode will trigger address allocation.
+ mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
+ HdmiControlManager.SOUNDBAR_MODE_DISABLED);
+ mTestLooper.dispatchAll();
+ verify(mHdmiControlServiceSpy, times(1))
+ .allocateLogicalAddress(any(), eq(INITIATED_BY_SOUNDBAR_MODE));
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ mTestLooper.moveTimeForward(allocationDelay / 2);
+ mTestLooper.dispatchAll();
+ // Enabling Dynamic soundbar mode will trigger another address allocation.
+ mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
+ HdmiControlManager.SOUNDBAR_MODE_ENABLED);
+ mTestLooper.dispatchAll();
+ verify(mHdmiControlServiceSpy, times(1))
+ .allocateLogicalAddress(any(), eq(INITIATED_BY_SOUNDBAR_MODE));
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ mTestLooper.moveTimeForward(allocationDelay / 2);
+ mTestLooper.dispatchAll();
+ // The first allocation finished. The second allocation is still in progress.
+ // The audio system is not present in the network.
+ verify(mHdmiControlServiceSpy, times(1))
+ .notifyAddressAllocated(any(), eq(INITIATED_BY_SOUNDBAR_MODE));
+ assertThat(mHdmiControlServiceSpy.audioSystem()).isNull();
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+
+ mTestLooper.moveTimeForward(allocationDelay / 2);
+ mTestLooper.dispatchAll();
+ // The second allocation finished. The audio system is present in the network.
+ verify(mHdmiControlServiceSpy, times(1))
+ .notifyAddressAllocated(any(), eq(INITIATED_BY_SOUNDBAR_MODE));
+ assertThat(mHdmiControlServiceSpy.audioSystem()).isNotNull();
+ }
+
+ @Test
+ public void failedAddressAllocation_noLocalDevice() {
+ mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
+ mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS);
+ mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_3, SendMessageResult.SUCCESS);
+ mNativeWrapper.setPollAddressResponse(ADDR_AUDIO_SYSTEM, SendMessageResult.SUCCESS);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlServiceSpy.clearCecLocalDevices();
+ mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiControlServiceSpy.playback()).isNull();
+ assertThat(mHdmiControlServiceSpy.audioSystem()).isNull();
+ }
+
+ @Test
public void earcIdle_blocksArcConnection() {
mHdmiControlServiceSpy.clearEarcLocalDevice();
HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
index 030b292..b3c9c96 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
@@ -31,7 +31,8 @@
@RunWith(FlickerServiceJUnit4ClassRunner::class)
class CloseAppBackButton3ButtonLandscape :
CloseAppBackButton(NavBar.MODE_3BUTTON, Rotation.ROTATION_90) {
- @ExpectedScenarios(["APP_CLOSE_TO_HOME"])
+ // TODO: Missing CUJ (b/300078127)
+ @ExpectedScenarios(["ENTIRE_TRACE"])
@Test
override fun closeAppBackButtonTest() = super.closeAppBackButtonTest()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
index 770da143..29c11a4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
@@ -31,7 +31,8 @@
@RunWith(FlickerServiceJUnit4ClassRunner::class)
class CloseAppBackButton3ButtonPortrait :
CloseAppBackButton(NavBar.MODE_3BUTTON, Rotation.ROTATION_0) {
- @ExpectedScenarios(["APP_CLOSE_TO_HOME"])
+ // TODO: Missing CUJ (b/300078127)
+ @ExpectedScenarios(["ENTIRE_TRACE"])
@Test
override fun closeAppBackButtonTest() = super.closeAppBackButtonTest()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
index 4b2206d7..1bb4a25 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
@@ -31,7 +31,8 @@
@RunWith(FlickerServiceJUnit4ClassRunner::class)
class CloseAppBackButtonGesturalNavLandscape :
CloseAppBackButton(NavBar.MODE_GESTURAL, Rotation.ROTATION_90) {
- @ExpectedScenarios(["APP_CLOSE_TO_HOME"])
+ // TODO: Missing CUJ (b/300078127)
+ @ExpectedScenarios(["ENTIRE_TRACE"])
@Test
override fun closeAppBackButtonTest() = super.closeAppBackButtonTest()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
index 54b471e..17cb6e1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
@@ -31,7 +31,8 @@
@RunWith(FlickerServiceJUnit4ClassRunner::class)
class CloseAppBackButtonGesturalNavPortrait :
CloseAppBackButton(NavBar.MODE_GESTURAL, Rotation.ROTATION_0) {
- @ExpectedScenarios(["APP_CLOSE_TO_HOME"])
+ // TODO: Missing CUJ (b/300078127)
+ @ExpectedScenarios(["ENTIRE_TRACE"])
@Test
override fun closeAppBackButtonTest() = super.closeAppBackButtonTest()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
index 93130c4..a1708fe 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
@@ -19,6 +19,7 @@
import android.app.Instrumentation
import android.tools.common.NavBar
import android.tools.common.Rotation
+import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
import android.tools.device.traces.parsers.WindowManagerStateHelper
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.tapl.LauncherInstrumentation
@@ -46,7 +47,9 @@
tapl.setExpectedRotation(rotation.value)
tapl.setIgnoreTaskbarVisibility(true)
testApp1.launchViaIntent(wmHelper)
+ ChangeDisplayOrientationRule.setRotation(rotation)
testApp2.launchViaIntent(wmHelper)
+ ChangeDisplayOrientationRule.setRotation(rotation)
}
@Test
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index f867c98..9198ae1 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -102,6 +102,20 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity android:name=".PortraitImmersiveActivity"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.PortraitImmersiveActivity"
+ android:immersive="true"
+ android:resizeableActivity="true"
+ android:screenOrientation="portrait"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:configChanges="screenSize"
+ android:label="PortraitImmersiveActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
<activity android:name=".LaunchTransparentActivity"
android:resizeableActivity="false"
android:screenOrientation="portrait"
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 7c5e9a3..8b334c0 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -73,6 +73,12 @@
FLICKER_APP_PACKAGE + ".NonResizeablePortraitActivity");
}
+ public static class PortraitImmersiveActivity {
+ public static final String LABEL = "PortraitImmersiveActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".PortraitImmersiveActivity");
+ }
+
public static class TransparentActivity {
public static final String LABEL = "TransparentActivity";
public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitImmersiveActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitImmersiveActivity.java
new file mode 100644
index 0000000..0a7f81c
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitImmersiveActivity.java
@@ -0,0 +1,20 @@
+/*
+ * 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.flicker.testapp;
+
+public class PortraitImmersiveActivity extends GameActivity {
+}
diff --git a/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der
index 235bd47..fd888ec 100644
--- a/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der
+++ b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der
Binary files differ
diff --git a/tests/NetworkSecurityConfigTest/res/raw/ca_certs_pem.pem b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_pem.pem
index 413e3c0..66f7bfd 100644
--- a/tests/NetworkSecurityConfigTest/res/raw/ca_certs_pem.pem
+++ b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_pem.pem
@@ -1,35 +1,31 @@
-----BEGIN CERTIFICATE-----
-MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
-MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
-aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
-WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE
-AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m
-OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu
-T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c
-JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR
-Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz
-PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm
-aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM
-TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g
-LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO
-BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv
-dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB
-AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL
-NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W
-b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
-MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
-BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
-YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
-ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
-BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
-I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
-CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i
-2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ
-2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ
+MIIFYjCCBEqgAwIBAgIQd70NbNs2+RrqIQ/E8FjTDTANBgkqhkiG9w0BAQsFADBX
+MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE
+CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIwMDYx
+OTAwMDA0MloXDTI4MDEyODAwMDA0MlowRzELMAkGA1UEBhMCVVMxIjAgBgNVBAoT
+GUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBMTEMxFDASBgNVBAMTC0dUUyBSb290IFIx
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAthECix7joXebO9y/lD63
+ladAPKH9gvl9MgaCcfb2jH/76Nu8ai6Xl6OMS/kr9rH5zoQdsfnFl97vufKj6bwS
+iV6nqlKr+CMny6SxnGPb15l+8Ape62im9MZaRw1NEDPjTrETo8gYbEvs/AmQ351k
+KSUjB6G00j0uYODP0gmHu81I8E3CwnqIiru6z1kZ1q+PsAewnjHxgsHA3y6mbWwZ
+DrXYfiYaRQM9sHmklCitD38m5agI/pboPGiUU+6DOogrFZYJsuB6jC511pzrp1Zk
+j5ZPaK49l8KEj8C8QMALXL32h7M1bKwYUH+E4EzNktMg6TO8UpmvMrUpsyUqtEj5
+cuHKZPfmghCN6J3Cioj6OGaK/GP5Afl4/Xtcd/p2h/rs37EOeZVXtL0m79YB0esW
+CruOC7XFxYpVq9Os6pFLKcwZpDIlTirxZUTQAs6qzkm06p98g7BAe+dDq6dso499
+iYH6TKX/1Y7DzkvgtdizjkXPdsDtQCv9Uw+wp9U7DbGKogPeMa3Md+pvez7W35Ei
+Eua++tgy/BBjFFFy3l3WFpO9KWgz7zpm7AeKJt8T11dleCfeXkkUAKIAf5qoIbap
+sZWwpbkNFhHax2xIPEDgfg1azVY80ZcFuctL7TlLnMQ/0lUTbiSw1nH69MG6zO0b
+9f6BQdgAmD06yK56mDcYBZUCAwEAAaOCATgwggE0MA4GA1UdDwEB/wQEAwIBhjAP
+BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTkrysmcRorSCeFL1JmLO/wiRNxPjAf
+BgNVHSMEGDAWgBRge2YaRQ2XyolQL30EzTSo//z9SzBgBggrBgEFBQcBAQRUMFIw
+JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnBraS5nb29nL2dzcjEwKQYIKwYBBQUH
+MAKGHWh0dHA6Ly9wa2kuZ29vZy9nc3IxL2dzcjEuY3J0MDIGA1UdHwQrMCkwJ6Al
+oCOGIWh0dHA6Ly9jcmwucGtpLmdvb2cvZ3NyMS9nc3IxLmNybDA7BgNVHSAENDAy
+MAgGBmeBDAECATAIBgZngQwBAgIwDQYLKwYBBAHWeQIFAwIwDQYLKwYBBAHWeQIF
+AwMwDQYJKoZIhvcNAQELBQADggEBADSkHrEoo9C0dhemMXoh6dFSPsjbdBZBiLg9
+NR3t5P+T4Vxfq7vqfM/b5A3Ri1fyJm9bvhdGaJQ3b2t6yMAYN/olUazsaL+yyEn9
+WprKASOshIArAoyZl+tJaox118fessmXn1hIVw41oeQa1v1vg4Fv74zPl6/AhSrw
+9U5pCZEt4Wi4wStz6dTZ/CLANx8LZh1J7QJVj2fhMtfTJr9w4z30Z209fOU0iOMy
++qduBmpvvYuR7hZL6Dupszfnw0Skfths18dG9ZKb59UhvmaSGZRVbNQpsg3BZlvi
+d0lIKO2d1xozclOzgjXPYovJJIultzkMu34qQb9Sz/yilrbCgj8=
-----END CERTIFICATE-----
diff --git a/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml b/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
index 5d23d36e..99106ad 100644
--- a/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
+++ b/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
@@ -5,7 +5,7 @@
</domain>
<domain> developer.android.com </domain>
<pin-set>
- <pin digest="SHA-256"> 7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y= </pin>
+ <pin digest="SHA-256"> zCTnfLwLKbS9S2sbp+uFz4KZOocFvXxkV06Ce9O5M2w= </pin>
</pin-set>
</domain-config>
</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml b/tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml
index d45fd77..232f88f 100644
--- a/tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml
+++ b/tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml
@@ -9,7 +9,7 @@
<domain-config>
<domain>developer.android.com</domain>
<pin-set>
- <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
+ <pin digest="SHA-256">zCTnfLwLKbS9S2sbp+uFz4KZOocFvXxkV06Ce9O5M2w=</pin>
</pin-set>
</domain-config>
</domain-config>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/pins1.xml b/tests/NetworkSecurityConfigTest/res/xml/pins1.xml
index 1773d280..7cc81b0 100644
--- a/tests/NetworkSecurityConfigTest/res/xml/pins1.xml
+++ b/tests/NetworkSecurityConfigTest/res/xml/pins1.xml
@@ -3,7 +3,7 @@
<domain-config>
<domain>android.com</domain>
<pin-set>
- <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
+ <pin digest="SHA-256">zCTnfLwLKbS9S2sbp+uFz4KZOocFvXxkV06Ce9O5M2w=</pin>
</pin-set>
</domain-config>
</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
index 047be16..0494f17 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
@@ -22,23 +22,17 @@
import android.test.ActivityUnitTestCase;
import android.util.ArraySet;
import android.util.Pair;
+
+import com.android.org.conscrypt.TrustedCertificateStore;
+
import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.net.Socket;
-import java.net.URL;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.TrustManager;
-import com.android.org.conscrypt.TrustedCertificateStore;
+import javax.net.ssl.SSLContext;
public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
@@ -46,9 +40,9 @@
super(Activity.class);
}
- // SHA-256 of the G2 intermediate CA for android.com (as of 10/2015).
- private static final byte[] G2_SPKI_SHA256
- = hexToBytes("ec722969cb64200ab6638f68ac538e40abab5b19a6485661042a1061c4612776");
+ // SHA-256 of the GTS intermediate CA (CN = GTS CA 1C3) for android.com (as of 09/2023).
+ private static final byte[] GTS_INTERMEDIATE_SPKI_SHA256 =
+ hexToBytes("cc24e77cbc0b29b4bd4b6b1ba7eb85cf82993a8705bd7c64574e827bd3b9336c");
private static final byte[] TEST_CA_BYTES
= hexToBytes(
@@ -161,7 +155,7 @@
public void testGoodPin() throws Exception {
ArraySet<Pin> pins = new ArraySet<Pin>();
- pins.add(new Pin("SHA-256", G2_SPKI_SHA256));
+ pins.add(new Pin("SHA-256", GTS_INTERMEDIATE_SPKI_SHA256));
NetworkSecurityConfig domain = new NetworkSecurityConfig.Builder()
.setPinSet(new PinSet(pins, Long.MAX_VALUE))
.addCertificatesEntryRef(
@@ -247,7 +241,7 @@
public void testWithUrlConnection() throws Exception {
ArraySet<Pin> pins = new ArraySet<Pin>();
- pins.add(new Pin("SHA-256", G2_SPKI_SHA256));
+ pins.add(new Pin("SHA-256", GTS_INTERMEDIATE_SPKI_SHA256));
NetworkSecurityConfig domain = new NetworkSecurityConfig.Builder()
.setPinSet(new PinSet(pins, Long.MAX_VALUE))
.addCertificatesEntryRef(
@@ -304,7 +298,7 @@
} finally {
// Delete the user added CA. We don't know the alias so just delete them all.
for (String alias : store.aliases()) {
- if (store.isUser(alias)) {
+ if (TrustedCertificateStore.isUser(alias)) {
try {
store.deleteCertificateEntry(alias);
} catch (Exception ignored) {
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java
index 9dec21b..39b5cb4c 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java
@@ -16,19 +16,20 @@
package android.security.net.config;
+import static org.junit.Assert.fail;
+
import android.content.pm.ApplicationInfo;
import android.os.Build;
-import java.net.Socket;
+
import java.net.URL;
+
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.TrustManager;
+import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;
-import junit.framework.Assert;
-
-public final class TestUtils extends Assert {
+public final class TestUtils {
private TestUtils() {
}
@@ -36,8 +37,8 @@
public static void assertConnectionFails(SSLContext context, String host, int port)
throws Exception {
try {
- Socket s = context.getSocketFactory().createSocket(host, port);
- s.getInputStream();
+ SSLSocket s = (SSLSocket) context.getSocketFactory().createSocket(host, port);
+ s.startHandshake();
fail("Expected connection to " + host + ":" + port + " to fail.");
} catch (SSLHandshakeException expected) {
}
@@ -45,7 +46,8 @@
public static void assertConnectionSucceeds(SSLContext context, String host, int port)
throws Exception {
- Socket s = context.getSocketFactory().createSocket(host, port);
+ SSLSocket s = (SSLSocket) context.getSocketFactory().createSocket(host, port);
+ s.startHandshake();
s.getInputStream();
}
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
index 4b7a014..81e05c1 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
@@ -16,26 +16,18 @@
package android.security.net.config;
-import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
-import android.util.ArraySet;
-import android.util.Pair;
+
import java.io.IOException;
import java.net.InetAddress;
-import java.net.Socket;
-import java.net.URL;
import java.security.KeyStore;
import java.security.Provider;
-import java.security.Security;
import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.Set;
-import javax.net.ssl.HttpsURLConnection;
+
import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
@@ -52,7 +44,7 @@
NetworkSecurityConfig config = appConfig.getConfigForHostname("");
assertNotNull(config);
// Check defaults.
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
assertFalse(config.getTrustAnchors().isEmpty());
PinSet pinSet = config.getPins();
@@ -72,7 +64,7 @@
NetworkSecurityConfig config = appConfig.getConfigForHostname("");
assertNotNull(config);
// Check defaults.
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
assertTrue(config.getTrustAnchors().isEmpty());
PinSet pinSet = config.getPins();
@@ -91,14 +83,14 @@
NetworkSecurityConfig config = appConfig.getConfigForHostname("");
assertNotNull(config);
// Check defaults.
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
assertTrue(config.getTrustAnchors().isEmpty());
PinSet pinSet = config.getPins();
assertTrue(pinSet.pins.isEmpty());
// Check android.com.
config = appConfig.getConfigForHostname("android.com");
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
assertFalse(config.getTrustAnchors().isEmpty());
pinSet = config.getPins();
@@ -188,7 +180,7 @@
ApplicationConfig appConfig = new ApplicationConfig(source);
assertTrue(appConfig.hasPerDomainConfigs());
NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
assertFalse(config.getTrustAnchors().isEmpty());
PinSet pinSet = config.getPins();
@@ -250,9 +242,9 @@
ApplicationConfig appConfig = new ApplicationConfig(source);
// Check android.com.
NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
- assertEquals(2, config.getTrustAnchors().size());
+ assertEquals(1, config.getTrustAnchors().size());
// Try connections.
SSLContext context = TestUtils.getSSLContext(source);
TestUtils.assertConnectionSucceeds(context, "android.com", 443);
@@ -267,9 +259,9 @@
ApplicationConfig appConfig = new ApplicationConfig(source);
// Check android.com.
NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
- assertEquals(2, config.getTrustAnchors().size());
+ assertEquals(1, config.getTrustAnchors().size());
// Try connections.
SSLContext context = TestUtils.getSSLContext(source);
TestUtils.assertConnectionSucceeds(context, "android.com", 443);