Merge changes from topic "tc_change_23042206_37" into udc-dev
* changes:
[automerged blank] Import translations. DO NOT MERGE ANYWHERE 2p: 4981708bfb
Import translations. DO NOT MERGE ANYWHERE
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7b68357..27f5545 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9599,6 +9599,7 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (IllegalArgumentException ex) {
+ Log.e(TAG, "IllegalArgumentException checking isPackageSuspended", ex);
throw new NameNotFoundException(packageName);
}
}
diff --git a/core/java/android/app/admin/LockTaskPolicy.java b/core/java/android/app/admin/LockTaskPolicy.java
index f5d1cb4..b671d57 100644
--- a/core/java/android/app/admin/LockTaskPolicy.java
+++ b/core/java/android/app/admin/LockTaskPolicy.java
@@ -38,6 +38,7 @@
/**
* @hide
*/
+ // We default on the power button menu, in order to be consistent with pre-P behaviour
public static final int DEFAULT_LOCK_TASK_FLAG =
DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS;
@@ -72,18 +73,28 @@
/**
* @hide
*/
- public LockTaskPolicy(@NonNull Set<String> packages) {
- Objects.requireNonNull(packages);
- mPackages.addAll(packages);
+ public LockTaskPolicy(@Nullable Set<String> packages) {
+ if (packages != null) {
+ mPackages.addAll(packages);
+ }
setValue(this);
}
/**
* @hide
*/
- public LockTaskPolicy(@NonNull Set<String> packages, int flags) {
- Objects.requireNonNull(packages);
- mPackages = new HashSet<>(packages);
+ public LockTaskPolicy(int flags) {
+ mFlags = flags;
+ setValue(this);
+ }
+
+ /**
+ * @hide
+ */
+ public LockTaskPolicy(@Nullable Set<String> packages, int flags) {
+ if (packages != null) {
+ mPackages.addAll(packages);
+ }
mFlags = flags;
setValue(this);
}
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index ed6a88f..70b72c8 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -304,7 +304,9 @@
return;
}
case DO_SET_STYLUS_WINDOW_IDLE_TIMEOUT: {
- inputMethod.setStylusWindowIdleTimeoutForTest((long) msg.obj);
+ if (isValid(inputMethod, target, "DO_SET_STYLUS_WINDOW_IDLE_TIMEOUT")) {
+ inputMethod.setStylusWindowIdleTimeoutForTest((long) msg.obj);
+ }
return;
}
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index efed688..365f913 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -16,6 +16,7 @@
package android.net;
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ActivityManager.procStateToString;
import static android.content.pm.PackageManager.GET_SIGNATURES;
@@ -805,6 +806,9 @@
/** @hide */
public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(
int procState, @ProcessCapability int capability) {
+ if (procState == PROCESS_STATE_UNKNOWN) {
+ return false;
+ }
return procState <= FOREGROUND_THRESHOLD_STATE
|| (capability & ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0;
}
@@ -832,6 +836,9 @@
/** @hide */
public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState,
@ProcessCapability int capabilities) {
+ if (procState == PROCESS_STATE_UNKNOWN) {
+ return false;
+ }
return procState <= FOREGROUND_THRESHOLD_STATE
// This is meant to be a user-initiated job, and therefore gets similar network
// access to FGS.
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 7383e63..9f9c222 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -493,7 +493,7 @@
* @hide
*/
@TestApi
- public static final int RESOURCES_SDK_INT = SDK_INT;
+ public static final int RESOURCES_SDK_INT = SDK_INT + ACTIVE_CODENAMES.length;
/**
* The current lowest supported value of app target SDK. Applications targeting
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 24c96ea..91c350a 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -1334,13 +1334,7 @@
@Override
public void destroy() {
synchronized (mLock) {
- if (mAvailability == STATE_KEYPHRASE_ENROLLED) {
- try {
- stopRecognition();
- } catch (Exception e) {
- Log.i(TAG, "failed to stopRecognition in destroy", e);
- }
- }
+ detachSessionLocked();
mAvailability = STATE_INVALID;
mIsAvailabilityOverriddenByTestApi = false;
@@ -1349,6 +1343,17 @@
super.destroy();
}
+ private void detachSessionLocked() {
+ try {
+ if (DBG) Slog.d(TAG, "detachSessionLocked() " + mSoundTriggerSession);
+ if (mSoundTriggerSession != null) {
+ mSoundTriggerSession.detach();
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index e31adcf..f2373fb 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -341,6 +341,9 @@
@Nullable
public DisplayShape displayShape;
+ /**
+ * Refresh rate range limitation based on the current device layout
+ */
@Nullable
public SurfaceControl.RefreshRateRange layoutLimitedRefreshRate;
@@ -354,7 +357,7 @@
* RefreshRateRange limitation for @Temperature.ThrottlingStatus
*/
@NonNull
- public SparseArray<SurfaceControl.RefreshRateRange> refreshRateThermalThrottling =
+ public SparseArray<SurfaceControl.RefreshRateRange> thermalRefreshRateThrottling =
new SparseArray<>();
public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
@@ -434,7 +437,7 @@
&& Objects.equals(displayShape, other.displayShape)
&& Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate)
&& BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio)
- && refreshRateThermalThrottling.contentEquals(other.refreshRateThermalThrottling);
+ && thermalRefreshRateThrottling.contentEquals(other.thermalRefreshRateThrottling);
}
@Override
@@ -491,7 +494,7 @@
displayShape = other.displayShape;
layoutLimitedRefreshRate = other.layoutLimitedRefreshRate;
hdrSdrRatio = other.hdrSdrRatio;
- refreshRateThermalThrottling = other.refreshRateThermalThrottling;
+ thermalRefreshRateThrottling = other.thermalRefreshRateThrottling;
}
public void readFromParcel(Parcel source) {
@@ -554,7 +557,7 @@
displayShape = source.readTypedObject(DisplayShape.CREATOR);
layoutLimitedRefreshRate = source.readTypedObject(SurfaceControl.RefreshRateRange.CREATOR);
hdrSdrRatio = source.readFloat();
- refreshRateThermalThrottling = source.readSparseArray(null,
+ thermalRefreshRateThrottling = source.readSparseArray(null,
SurfaceControl.RefreshRateRange.class);
}
@@ -616,7 +619,7 @@
dest.writeTypedObject(displayShape, flags);
dest.writeTypedObject(layoutLimitedRefreshRate, flags);
dest.writeFloat(hdrSdrRatio);
- dest.writeSparseArray(refreshRateThermalThrottling);
+ dest.writeSparseArray(thermalRefreshRateThrottling);
}
@Override
@@ -884,8 +887,8 @@
} else {
sb.append(hdrSdrRatio);
}
- sb.append(", refreshRateThermalThrottling ");
- sb.append(refreshRateThermalThrottling);
+ sb.append(", thermalRefreshRateThrottling ");
+ sb.append(thermalRefreshRateThrottling);
sb.append("}");
return sb.toString();
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionSoundTriggerSession.aidl b/core/java/com/android/internal/app/IVoiceInteractionSoundTriggerSession.aidl
index 1ccc71a..23de50c 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionSoundTriggerSession.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionSoundTriggerSession.aidl
@@ -94,4 +94,9 @@
*/
@nullable SoundTrigger.ModelParamRange queryParameter(int keyphraseId,
in ModelParams modelParam);
+ /**
+ * Invalidates the sound trigger session and clears any associated resources. Subsequent calls
+ * to this object will throw IllegalStateException.
+ */
+ void detach();
}
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index a57a051..fd74185 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -133,6 +133,10 @@
<string name="config_pointing_ui_package" translatable="false"></string>
<java-symbol type="string" name="config_pointing_ui_package" />
+ <!-- Telephony pointing UI class name to be launched. -->
+ <string name="config_pointing_ui_class" translatable="false"></string>
+ <java-symbol type="string" name="config_pointing_ui_class" />
+
<!-- Telephony resends received satellite datagram to listener
if ack is not received within this timeout -->
<integer name="config_timeout_to_receive_delivered_ack_millis">300000</integer>
diff --git a/core/tests/coretests/src/android/util/RotationUtilsTest.java b/core/tests/coretests/src/android/util/RotationUtilsTest.java
index 1b1ee4f..06b28f5 100644
--- a/core/tests/coretests/src/android/util/RotationUtilsTest.java
+++ b/core/tests/coretests/src/android/util/RotationUtilsTest.java
@@ -19,6 +19,7 @@
import static android.util.RotationUtils.rotateBounds;
import static android.util.RotationUtils.rotatePoint;
import static android.util.RotationUtils.rotatePointF;
+import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
@@ -103,4 +104,19 @@
assertEquals(560f, testResult.x, .1f);
assertEquals(60f, testResult.y, .1f);
}
+
+ @Test
+ public void testReverseRotationDirectionAroundZAxis() {
+ assertEquals(ROTATION_90,
+ RotationUtils.reverseRotationDirectionAroundZAxis(ROTATION_270));
+ assertEquals(ROTATION_270,
+ RotationUtils.reverseRotationDirectionAroundZAxis(ROTATION_90));
+ assertEquals(ROTATION_0,
+ RotationUtils.reverseRotationDirectionAroundZAxis(ROTATION_0));
+ assertEquals(ROTATION_180,
+ RotationUtils.reverseRotationDirectionAroundZAxis(ROTATION_180));
+
+ assertEquals(-1,
+ RotationUtils.reverseRotationDirectionAroundZAxis(-1));
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index 27eda16..9467578 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -193,8 +193,11 @@
// This Transition animates a task to fullscreen after being dragged from the status
// bar and then released back into the status bar area
final SurfaceControl sc = change.getLeash();
- startT.setWindowCrop(sc, null);
- startT.apply();
+ // Hide the first (fullscreen) frame because the animation will start from the smaller
+ // scale size.
+ startT.hide(sc)
+ .setWindowCrop(sc, endBounds.width(), endBounds.height())
+ .apply();
final ValueAnimator animator = new ValueAnimator();
animator.setFloatValues(DRAG_FREEFORM_SCALE, 1f);
@@ -202,10 +205,10 @@
final SurfaceControl.Transaction t = mTransactionSupplier.get();
animator.addUpdateListener(animation -> {
final float scale = animation.getAnimatedFraction();
- t.setPosition(sc, mStartPosition.x * (1 - scale),
- mStartPosition.y * (1 - scale));
- t.setScale(sc, scale, scale);
- t.apply();
+ t.setPosition(sc, mStartPosition.x * (1 - scale), mStartPosition.y * (1 - scale))
+ .setScale(sc, scale, scale)
+ .show(sc)
+ .apply();
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
index 248a5fc..fa3eee2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
@@ -129,8 +129,12 @@
final int screenWidth = metrics.widthPixels;
final int screenHeight = metrics.heightPixels;
final SurfaceControl sc = change.getLeash();
- startT.setCrop(sc, null);
- startT.apply();
+ final Rect endBounds = change.getEndAbsBounds();
+ // Hide the first (fullscreen) frame because the animation will start from the freeform
+ // size.
+ startT.hide(sc)
+ .setWindowCrop(sc, endBounds.width(), endBounds.height())
+ .apply();
final ValueAnimator animator = new ValueAnimator();
animator.setFloatValues(0f, 1f);
animator.setDuration(FULLSCREEN_ANIMATION_DURATION);
@@ -144,9 +148,10 @@
float fraction = animation.getAnimatedFraction();
float currentScaleX = scaleX + ((1 - scaleX) * fraction);
float currentScaleY = scaleY + ((1 - scaleY) * fraction);
- t.setPosition(sc, startPos.x * (1 - fraction), startPos.y * (1 - fraction));
- t.setScale(sc, currentScaleX, currentScaleY);
- t.apply();
+ t.setPosition(sc, startPos.x * (1 - fraction), startPos.y * (1 - fraction))
+ .setScale(sc, currentScaleX, currentScaleY)
+ .show(sc)
+ .apply();
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
index 2c5a5cd..4fad054 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
@@ -71,12 +71,6 @@
@Mock
Resources mResources;
@Mock
- SurfaceControl.Transaction mStartT;
- @Mock
- SurfaceControl.Transaction mFinishT;
- @Mock
- SurfaceControl.Transaction mAnimationT;
- @Mock
Transitions.TransitionFinishCallback mTransitionFinishCallback;
@Mock
ShellExecutor mExecutor;
@@ -88,7 +82,7 @@
MockitoAnnotations.initMocks(this);
doReturn(mExecutor).when(mTransitions).getMainExecutor();
- doReturn(mAnimationT).when(mTransactionFactory).get();
+ doReturn(new SurfaceControl.Transaction()).when(mTransactionFactory).get();
doReturn(mResources).when(mContext).getResources();
doReturn(mDisplayMetrics).when(mResources).getDisplayMetrics();
when(mResources.getDisplayMetrics())
@@ -115,7 +109,9 @@
runOnUiThread(() -> {
try {
assertTrue(mExitDesktopTaskTransitionHandler
- .startAnimation(mToken, info, mStartT, mFinishT,
+ .startAnimation(mToken, info,
+ new SurfaceControl.Transaction(),
+ new SurfaceControl.Transaction(),
mTransitionFinishCallback));
} catch (Exception e) {
exceptions.add(e);
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index 80a3e70..d749b91 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -223,7 +223,8 @@
break;
}
case DO_TIME_SHIFT_SET_MODE: {
- mTvInputSessionImpl.timeShiftSetMode((Integer) msg.obj);
+ mTvInputSessionImpl.timeShiftSetMode(msg.arg1);
+ break;
}
case DO_TIME_SHIFT_ENABLE_POSITION_TRACKING: {
mTvInputSessionImpl.timeShiftEnablePositionTracking((Boolean) msg.obj);
diff --git a/packages/CredentialManager/res/values/colors.xml b/packages/CredentialManager/res/values/colors.xml
deleted file mode 100644
index 09837df62..0000000
--- a/packages/CredentialManager/res/values/colors.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <color name="purple_200">#FFBB86FC</color>
- <color name="purple_500">#FF6200EE</color>
- <color name="purple_700">#FF3700B3</color>
- <color name="teal_200">#FF03DAC5</color>
- <color name="teal_700">#FF018786</color>
- <color name="black">#FF000000</color>
- <color name="white">#FFFFFFFF</color>
-</resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 3e65251..905e0ca 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -1,4 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- The name of this application. Credential Manager is a service that centralizes and provides
access to a user's credentials used to sign in to various apps. [CHAR LIMIT=80] -->
diff --git a/packages/CredentialManager/res/values/themes.xml b/packages/CredentialManager/res/values/themes.xml
index 428c85a..22329e9f 100644
--- a/packages/CredentialManager/res/values/themes.xml
+++ b/packages/CredentialManager/res/values/themes.xml
@@ -1,4 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
<resources>
<style name="Theme.CredentialSelector" parent="@*android:style/ThemeOverlay.DeviceDefault.Accent.DayNight">
<item name="android:windowContentOverlay">@null</item>
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 8b9c8b9..6549b2d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -16,6 +16,7 @@
package com.android.credentialmanager
+import android.app.Activity
import android.content.Intent
import android.credentials.ui.BaseDialogResult
import android.credentials.ui.RequestInfo
@@ -47,6 +48,8 @@
class CredentialSelectorActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ overrideActivityTransition(Activity.OVERRIDE_TRANSITION_OPEN,
+ 0, 0)
Log.d(Constants.LOG_TAG, "Creating new CredentialSelectorActivity")
try {
val (isCancellationRequest, shouldShowCancellationUi, _) =
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt
index 10a75d4..250e3b1 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt
@@ -454,7 +454,7 @@
if (color.isSpecified) {
val alpha by animateFloatAsState(
targetValue = if (visible) 1f else 0f,
- animationSpec = TweenSpec()
+ animationSpec = TweenSpec(durationMillis = SwipeableDefaults.DefaultDurationMillis)
)
LocalConfiguration.current
val resources = LocalContext.current.resources
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/material/Swipeable.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/material/Swipeable.kt
index 3e2de83..e9aaeee 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/material/Swipeable.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/material/Swipeable.kt
@@ -19,6 +19,7 @@
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.SpringSpec
+import androidx.compose.animation.core.Spring
import androidx.compose.foundation.gestures.DraggableState
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.draggable
@@ -791,7 +792,12 @@
/**
* The default animation used by [SwipeableState].
*/
- val AnimationSpec = SpringSpec<Float>()
+ val AnimationSpec = SpringSpec<Float>(stiffness = Spring.StiffnessMediumLow)
+
+ /**
+ * The default animation duration used by Scrim in enter/exit transitions.
+ */
+ val DefaultDurationMillis: Int = 400
/**
* The default velocity threshold (1.8 dp per millisecond) used by [swipeable].
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
index 53731f0..3399681 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
@@ -20,6 +20,11 @@
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import com.android.compose.rememberSystemUiController
@@ -28,6 +33,8 @@
import com.android.credentialmanager.common.material.rememberModalBottomSheetState
import com.android.credentialmanager.ui.theme.EntryShape
import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme
+import kotlinx.coroutines.launch
+
/** Draws a modal bottom sheet with the same styles and effects shared by various flows. */
@Composable
@@ -35,8 +42,10 @@
sheetContent: @Composable ColumnScope.() -> Unit,
onDismiss: () -> Unit
) {
+ var isInitialRender by remember { mutableStateOf(true) }
+ val scope = rememberCoroutineScope()
val state = rememberModalBottomSheetState(
- initialValue = ModalBottomSheetValue.Expanded,
+ initialValue = ModalBottomSheetValue.Hidden,
skipHalfExpanded = true
)
val sysUiController = rememberSystemUiController()
@@ -54,7 +63,12 @@
) {}
LaunchedEffect(state.currentValue) {
if (state.currentValue == ModalBottomSheetValue.Hidden) {
- onDismiss()
+ if (isInitialRender) {
+ isInitialRender = false
+ scope.launch { state.show() }
+ } else {
+ onDismiss()
+ }
}
}
}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/build.gradle b/packages/SettingsLib/Spa/build.gradle
index 4fd2b5d..e68ef85 100644
--- a/packages/SettingsLib/Spa/build.gradle
+++ b/packages/SettingsLib/Spa/build.gradle
@@ -14,17 +14,27 @@
* limitations under the License.
*/
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
buildscript {
ext {
BUILD_TOOLS_VERSION = "30.0.3"
MIN_SDK = 21
TARGET_SDK = 33
jetpack_compose_version = '1.4.0-beta01'
- jetpack_compose_compiler_version = '1.4.0'
+ jetpack_compose_compiler_version = '1.4.4'
}
}
plugins {
- id 'com.android.application' version '8.0.0-beta05' apply false
- id 'com.android.library' version '8.0.0-beta05' apply false
- id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
+ id 'com.android.application' version '8.0.0' apply false
+ id 'com.android.library' version '8.0.0' apply false
+ id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
+}
+subprojects {
+ tasks.withType(KotlinCompile).configureEach {
+ kotlinOptions {
+ jvmTarget = "17"
+ freeCompilerArgs = ["-Xjvm-default=all"]
+ }
+ }
}
diff --git a/packages/SettingsLib/Spa/gallery/build.gradle b/packages/SettingsLib/Spa/gallery/build.gradle
index 416a403..212aa7b 100644
--- a/packages/SettingsLib/Spa/gallery/build.gradle
+++ b/packages/SettingsLib/Spa/gallery/build.gradle
@@ -42,12 +42,8 @@
}
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_11
- targetCompatibility JavaVersion.VERSION_11
- }
- kotlinOptions {
- jvmTarget = '11'
- freeCompilerArgs = ["-Xjvm-default=all"]
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
}
buildFeatures {
compose true
diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle
index 9962c93..fb945a3 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ b/packages/SettingsLib/Spa/spa/build.gradle
@@ -51,10 +51,6 @@
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
- kotlinOptions {
- jvmTarget = '17'
- freeCompilerArgs = ["-Xjvm-default=all"]
- }
buildFeatures {
compose true
}
@@ -79,7 +75,7 @@
api "androidx.compose.ui:ui-tooling-preview:$jetpack_compose_version"
api "androidx.lifecycle:lifecycle-livedata-ktx"
api "androidx.lifecycle:lifecycle-runtime-compose"
- api "androidx.navigation:navigation-compose:2.6.0-alpha07"
+ api "androidx.navigation:navigation-compose:2.6.0-alpha08"
api "com.github.PhilJay:MPAndroidChart:v3.1.0-alpha"
api "com.google.android.material:material:1.7.0-alpha03"
debugApi "androidx.compose.ui:ui-tooling:$jetpack_compose_version"
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
index f0df9a6..8cbf7cc 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
@@ -19,7 +19,6 @@
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material.icons.Icons
@@ -40,7 +39,6 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -60,13 +58,17 @@
Box(
modifier = Modifier
- .padding(SettingsDimension.itemPadding)
+ .padding(
+ start = SettingsDimension.itemPaddingStart,
+ top = SettingsDimension.itemPaddingAround,
+ end = SettingsDimension.itemPaddingEnd,
+ bottom = SettingsDimension.itemPaddingAround,
+ )
.selectableGroup(),
) {
val contentPadding = PaddingValues(horizontal = SettingsDimension.itemPaddingEnd)
Button(
onClick = { expanded = true },
- modifier = Modifier.height(36.dp),
colors = ButtonDefaults.buttonColors(
containerColor = SettingsTheme.colorScheme.spinnerHeaderContainer,
contentColor = SettingsTheme.colorScheme.onSpinnerHeaderContainer,
@@ -86,7 +88,6 @@
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier.background(SettingsTheme.colorScheme.spinnerItemContainer),
- offset = DpOffset(x = 0.dp, y = 4.dp),
) {
for (option in options) {
DropdownMenuItem(
@@ -116,7 +117,9 @@
) {
Text(
text = option?.text ?: "",
- modifier = modifier.padding(end = SettingsDimension.itemPaddingEnd),
+ modifier = modifier
+ .padding(end = SettingsDimension.itemPaddingEnd)
+ .padding(vertical = SettingsDimension.itemPaddingAround),
color = color,
style = MaterialTheme.typography.labelLarge,
)
diff --git a/packages/SettingsLib/Spa/testutils/build.gradle b/packages/SettingsLib/Spa/testutils/build.gradle
index e7f7db2..23a9add 100644
--- a/packages/SettingsLib/Spa/testutils/build.gradle
+++ b/packages/SettingsLib/Spa/testutils/build.gradle
@@ -41,10 +41,6 @@
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
- kotlinOptions {
- jvmTarget = '17'
- freeCompilerArgs = ["-Xjvm-default=all"]
- }
buildFeatures {
compose true
}
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index 8eb012d..5b5871f 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -43,7 +43,6 @@
"androidx.core_core-ktx",
"androidx.annotation_annotation",
"SystemUIShaderLib",
- "animationlib",
],
manifest: "AndroidManifest.xml",
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 2e80379..296c2ae 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -39,9 +39,9 @@
import android.view.animation.PathInterpolator
import androidx.annotation.BinderThread
import androidx.annotation.UiThread
-import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.policy.ScreenDecorationsUtils
+import java.lang.IllegalArgumentException
import kotlin.math.roundToInt
private const val TAG = "ActivityLaunchAnimator"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index 48dd08f..42a8636 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -33,10 +33,10 @@
import android.view.WindowManager
import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
import android.widget.FrameLayout
-import com.android.app.animation.Interpolators
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor.CujType
import com.android.systemui.util.registerAnimationOnBackInvoked
+import java.lang.IllegalArgumentException
import kotlin.math.roundToInt
private const val TAG = "DialogLaunchAnimator"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
new file mode 100644
index 0000000..9dbb920
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2016 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.systemui.animation;
+
+import android.graphics.Path;
+import android.util.MathUtils;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.BounceInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.PathInterpolator;
+
+/**
+ * Utility class to receive interpolators from.
+ *
+ * Make sure that changes made to this class are also reflected in {@link InterpolatorsAndroidX}.
+ * Please consider using the androidx dependencies featuring better testability altogether.
+ */
+public class Interpolators {
+
+ /*
+ * ============================================================================================
+ * Emphasized interpolators.
+ * ============================================================================================
+ */
+
+ /**
+ * The default emphasized interpolator. Used for hero / emphasized movement of content.
+ */
+ public static final Interpolator EMPHASIZED = createEmphasizedInterpolator();
+
+ /**
+ * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
+ * is disappearing e.g. when moving off screen.
+ */
+ public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
+ 0.3f, 0f, 0.8f, 0.15f);
+
+ /**
+ * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
+ * is appearing e.g. when coming from off screen
+ */
+ public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
+ 0.05f, 0.7f, 0.1f, 1f);
+
+
+ /*
+ * ============================================================================================
+ * Standard interpolators.
+ * ============================================================================================
+ */
+
+ /**
+ * The standard interpolator that should be used on every normal animation
+ */
+ public static final Interpolator STANDARD = new PathInterpolator(
+ 0.2f, 0f, 0f, 1f);
+
+ /**
+ * The standard accelerating interpolator that should be used on every regular movement of
+ * content that is disappearing e.g. when moving off screen.
+ */
+ public static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(
+ 0.3f, 0f, 1f, 1f);
+
+ /**
+ * The standard decelerating interpolator that should be used on every regular movement of
+ * content that is appearing e.g. when coming from off screen.
+ */
+ public static final Interpolator STANDARD_DECELERATE = new PathInterpolator(
+ 0f, 0f, 0f, 1f);
+
+ /*
+ * ============================================================================================
+ * Legacy
+ * ============================================================================================
+ */
+
+ /**
+ * The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN.
+ */
+ public static final Interpolator LEGACY = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+
+ /**
+ * The default legacy accelerating interpolator as defined in Material 1.
+ * Also known as FAST_OUT_LINEAR_IN.
+ */
+ public static final Interpolator LEGACY_ACCELERATE = new PathInterpolator(0.4f, 0f, 1f, 1f);
+
+ /**
+ * The default legacy decelerating interpolator as defined in Material 1.
+ * Also known as LINEAR_OUT_SLOW_IN.
+ */
+ public static final Interpolator LEGACY_DECELERATE = new PathInterpolator(0f, 0f, 0.2f, 1f);
+
+ /**
+ * Linear interpolator. Often used if the interpolator is for different properties who need
+ * different interpolations.
+ */
+ public static final Interpolator LINEAR = new LinearInterpolator();
+
+ /*
+ * ============================================================================================
+ * Custom interpolators
+ * ============================================================================================
+ */
+
+ public static final Interpolator FAST_OUT_SLOW_IN = LEGACY;
+ public static final Interpolator FAST_OUT_LINEAR_IN = LEGACY_ACCELERATE;
+ public static final Interpolator LINEAR_OUT_SLOW_IN = LEGACY_DECELERATE;
+
+ /**
+ * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t
+ * goes from 1 to 0 instead of 0 to 1).
+ */
+ public static final Interpolator FAST_OUT_SLOW_IN_REVERSE =
+ new PathInterpolator(0.8f, 0f, 0.6f, 1f);
+ public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f);
+ public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+ public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
+ public static final Interpolator ACCELERATE = new AccelerateInterpolator();
+ public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
+ public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
+ public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f);
+ public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
+ public static final Interpolator ICON_OVERSHOT_LESS = new PathInterpolator(0.4f, 0f, 0.2f,
+ 1.1f);
+ public static final Interpolator PANEL_CLOSE_ACCELERATED = new PathInterpolator(0.3f, 0, 0.5f,
+ 1);
+ public static final Interpolator BOUNCE = new BounceInterpolator();
+ /**
+ * For state transitions on the control panel that lives in GlobalActions.
+ */
+ public static final Interpolator CONTROL_STATE = new PathInterpolator(0.4f, 0f, 0.2f,
+ 1.0f);
+
+ /**
+ * Interpolator to be used when animating a move based on a click. Pair with enough duration.
+ */
+ public static final Interpolator TOUCH_RESPONSE =
+ new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
+ /**
+ * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t
+ * goes from 1 to 0 instead of 0 to 1).
+ */
+ public static final Interpolator TOUCH_RESPONSE_REVERSE =
+ new PathInterpolator(0.9f, 0f, 0.7f, 1f);
+
+ /*
+ * ============================================================================================
+ * Functions / Utilities
+ * ============================================================================================
+ */
+
+ /**
+ * Calculate the amount of overshoot using an exponential falloff function with desired
+ * properties, where the overshoot smoothly transitions at the 1.0f boundary into the
+ * overshoot, retaining its acceleration.
+ *
+ * @param progress a progress value going from 0 to 1
+ * @param overshootAmount the amount > 0 of overshoot desired. A value of 0.1 means the max
+ * value of the overall progress will be at 1.1.
+ * @param overshootStart the point in (0,1] where the result should reach 1
+ * @return the interpolated overshoot
+ */
+ public static float getOvershootInterpolation(float progress, float overshootAmount,
+ float overshootStart) {
+ if (overshootAmount == 0.0f || overshootStart == 0.0f) {
+ throw new IllegalArgumentException("Invalid values for overshoot");
+ }
+ float b = MathUtils.log((overshootAmount + 1) / (overshootAmount)) / overshootStart;
+ return MathUtils.max(0.0f,
+ (float) (1.0f - Math.exp(-b * progress)) * (overshootAmount + 1.0f));
+ }
+
+ /**
+ * Similar to {@link #getOvershootInterpolation(float, float, float)} but the overshoot
+ * starts immediately here, instead of first having a section of non-overshooting
+ *
+ * @param progress a progress value going from 0 to 1
+ */
+ public static float getOvershootInterpolation(float progress) {
+ return MathUtils.max(0.0f, (float) (1.0f - Math.exp(-4 * progress)));
+ }
+
+ // Create the default emphasized interpolator
+ private static PathInterpolator createEmphasizedInterpolator() {
+ Path path = new Path();
+ // Doing the same as fast_out_extra_slow_in
+ path.moveTo(0f, 0f);
+ path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f);
+ path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f);
+ return new PathInterpolator(path);
+ }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java b/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java
new file mode 100644
index 0000000..8da87feb
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2022 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.systemui.animation;
+
+import android.graphics.Path;
+import android.util.MathUtils;
+
+import androidx.core.animation.AccelerateDecelerateInterpolator;
+import androidx.core.animation.AccelerateInterpolator;
+import androidx.core.animation.BounceInterpolator;
+import androidx.core.animation.DecelerateInterpolator;
+import androidx.core.animation.Interpolator;
+import androidx.core.animation.LinearInterpolator;
+import androidx.core.animation.PathInterpolator;
+
+/**
+ * Utility class to receive interpolators from. (androidx compatible version)
+ *
+ * This is the androidx compatible version of {@link Interpolators}. Make sure that changes made to
+ * this class are also reflected in {@link Interpolators}.
+ *
+ * Using the androidx versions of {@link androidx.core.animation.ValueAnimator} or
+ * {@link androidx.core.animation.ObjectAnimator} improves animation testability. This file provides
+ * the androidx compatible versions of the interpolators defined in {@link Interpolators}.
+ * AnimatorTestRule can be used in Tests to manipulate the animation under test (e.g. artificially
+ * advancing the time).
+ */
+public class InterpolatorsAndroidX {
+
+ /*
+ * ============================================================================================
+ * Emphasized interpolators.
+ * ============================================================================================
+ */
+
+ /**
+ * The default emphasized interpolator. Used for hero / emphasized movement of content.
+ */
+ public static final Interpolator EMPHASIZED = createEmphasizedInterpolator();
+
+ /**
+ * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
+ * is disappearing e.g. when moving off screen.
+ */
+ public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
+ 0.3f, 0f, 0.8f, 0.15f);
+
+ /**
+ * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
+ * is appearing e.g. when coming from off screen
+ */
+ public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
+ 0.05f, 0.7f, 0.1f, 1f);
+
+
+ /*
+ * ============================================================================================
+ * Standard interpolators.
+ * ============================================================================================
+ */
+
+ /**
+ * The standard interpolator that should be used on every normal animation
+ */
+ public static final Interpolator STANDARD = new PathInterpolator(
+ 0.2f, 0f, 0f, 1f);
+
+ /**
+ * The standard accelerating interpolator that should be used on every regular movement of
+ * content that is disappearing e.g. when moving off screen.
+ */
+ public static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(
+ 0.3f, 0f, 1f, 1f);
+
+ /**
+ * The standard decelerating interpolator that should be used on every regular movement of
+ * content that is appearing e.g. when coming from off screen.
+ */
+ public static final Interpolator STANDARD_DECELERATE = new PathInterpolator(
+ 0f, 0f, 0f, 1f);
+
+ /*
+ * ============================================================================================
+ * Legacy
+ * ============================================================================================
+ */
+
+ /**
+ * The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN.
+ */
+ public static final Interpolator LEGACY = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+
+ /**
+ * The default legacy accelerating interpolator as defined in Material 1.
+ * Also known as FAST_OUT_LINEAR_IN.
+ */
+ public static final Interpolator LEGACY_ACCELERATE = new PathInterpolator(0.4f, 0f, 1f, 1f);
+
+ /**
+ * The default legacy decelerating interpolator as defined in Material 1.
+ * Also known as LINEAR_OUT_SLOW_IN.
+ */
+ public static final Interpolator LEGACY_DECELERATE = new PathInterpolator(0f, 0f, 0.2f, 1f);
+
+ /**
+ * Linear interpolator. Often used if the interpolator is for different properties who need
+ * different interpolations.
+ */
+ public static final Interpolator LINEAR = new LinearInterpolator();
+
+ /*
+ * ============================================================================================
+ * Custom interpolators
+ * ============================================================================================
+ */
+
+ public static final Interpolator FAST_OUT_SLOW_IN = LEGACY;
+ public static final Interpolator FAST_OUT_LINEAR_IN = LEGACY_ACCELERATE;
+ public static final Interpolator LINEAR_OUT_SLOW_IN = LEGACY_DECELERATE;
+
+ /**
+ * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t
+ * goes from 1 to 0 instead of 0 to 1).
+ */
+ public static final Interpolator FAST_OUT_SLOW_IN_REVERSE =
+ new PathInterpolator(0.8f, 0f, 0.6f, 1f);
+ public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f);
+ public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+ public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
+ public static final Interpolator ACCELERATE = new AccelerateInterpolator();
+ public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
+ public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
+ public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f);
+ public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
+ public static final Interpolator ICON_OVERSHOT_LESS = new PathInterpolator(0.4f, 0f, 0.2f,
+ 1.1f);
+ public static final Interpolator PANEL_CLOSE_ACCELERATED = new PathInterpolator(0.3f, 0, 0.5f,
+ 1);
+ public static final Interpolator BOUNCE = new BounceInterpolator();
+ /**
+ * For state transitions on the control panel that lives in GlobalActions.
+ */
+ public static final Interpolator CONTROL_STATE = new PathInterpolator(0.4f, 0f, 0.2f,
+ 1.0f);
+
+ /**
+ * Interpolator to be used when animating a move based on a click. Pair with enough duration.
+ */
+ public static final Interpolator TOUCH_RESPONSE =
+ new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
+ /**
+ * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t
+ * goes from 1 to 0 instead of 0 to 1).
+ */
+ public static final Interpolator TOUCH_RESPONSE_REVERSE =
+ new PathInterpolator(0.9f, 0f, 0.7f, 1f);
+
+ /*
+ * ============================================================================================
+ * Functions / Utilities
+ * ============================================================================================
+ */
+
+ /**
+ * Calculate the amount of overshoot using an exponential falloff function with desired
+ * properties, where the overshoot smoothly transitions at the 1.0f boundary into the
+ * overshoot, retaining its acceleration.
+ *
+ * @param progress a progress value going from 0 to 1
+ * @param overshootAmount the amount > 0 of overshoot desired. A value of 0.1 means the max
+ * value of the overall progress will be at 1.1.
+ * @param overshootStart the point in (0,1] where the result should reach 1
+ * @return the interpolated overshoot
+ */
+ public static float getOvershootInterpolation(float progress, float overshootAmount,
+ float overshootStart) {
+ if (overshootAmount == 0.0f || overshootStart == 0.0f) {
+ throw new IllegalArgumentException("Invalid values for overshoot");
+ }
+ float b = MathUtils.log((overshootAmount + 1) / (overshootAmount)) / overshootStart;
+ return MathUtils.max(0.0f,
+ (float) (1.0f - Math.exp(-b * progress)) * (overshootAmount + 1.0f));
+ }
+
+ /**
+ * Similar to {@link #getOvershootInterpolation(float, float, float)} but the overshoot
+ * starts immediately here, instead of first having a section of non-overshooting
+ *
+ * @param progress a progress value going from 0 to 1
+ */
+ public static float getOvershootInterpolation(float progress) {
+ return MathUtils.max(0.0f, (float) (1.0f - Math.exp(-4 * progress)));
+ }
+
+ // Create the default emphasized interpolator
+ private static PathInterpolator createEmphasizedInterpolator() {
+ Path path = new Path();
+ // Doing the same as fast_out_extra_slow_in
+ path.moveTo(0f, 0f);
+ path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f);
+ path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f);
+ return new PathInterpolator(path);
+ }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
index 142fd21..3417ffd 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
@@ -28,7 +28,7 @@
import android.view.View
import android.view.ViewGroup
import android.view.animation.Interpolator
-import com.android.app.animation.Interpolators.LINEAR
+import com.android.systemui.animation.Interpolators.LINEAR
import kotlin.math.roundToInt
private const val TAG = "LaunchAnimator"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
index 8e79e3c..58ffef2 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
@@ -25,7 +25,6 @@
import android.view.View
import android.view.ViewGroup
import android.view.animation.Interpolator
-import com.android.app.animation.Interpolators
import kotlin.math.max
import kotlin.math.min
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
index dd32851..f3d8b17 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
@@ -19,7 +19,7 @@
import android.util.DisplayMetrics
import android.view.animation.Interpolator
import android.window.BackEvent
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.util.dpToPx
/** Used to convert [BackEvent] into a [BackTransformation]. */
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 3688f9e..9d1dd1b 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -29,9 +29,9 @@
import android.util.AttributeSet
import android.util.MathUtils
import android.widget.TextView
-import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.animation.GlyphCallback
+import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.TextAnimator
import com.android.systemui.customization.R
import com.android.systemui.plugins.log.LogBuffer
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 6d4dbf6..33c7c11 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -102,6 +102,33 @@
void dismissKeyguardThenExecute(OnDismissAction action, @Nullable Runnable cancel,
boolean afterKeyguardGone, @Nullable String customMessage);
+ /** Starts an activity and dismisses keyguard. */
+ void startActivityDismissingKeyguard(Intent intent,
+ boolean onlyProvisioned,
+ boolean dismissShade,
+ boolean disallowEnterPictureInPictureWhileLaunching,
+ Callback callback,
+ int flags,
+ @Nullable ActivityLaunchAnimator.Controller animationController,
+ UserHandle userHandle);
+
+ /** Execute a runnable after dismissing keyguard. */
+ void executeRunnableDismissingKeyguard(Runnable runnable,
+ Runnable cancelAction,
+ boolean dismissShade,
+ boolean afterKeyguardGone,
+ boolean deferred);
+
+ /** Execute a runnable after dismissing keyguard. */
+ void executeRunnableDismissingKeyguard(
+ Runnable runnable,
+ Runnable cancelAction,
+ boolean dismissShade,
+ boolean afterKeyguardGone,
+ boolean deferred,
+ boolean willAnimateOnKeyguard,
+ @Nullable String customMessage);
+
interface Callback {
void onActivityStarted(int resultCode);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
index 64d766d..f59bf8e 100644
--- a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
+++ b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
@@ -26,8 +26,8 @@
import android.graphics.Color
import android.util.AttributeSet
import android.view.View
-import com.android.app.animation.Interpolators
import com.android.settingslib.Utils
+import com.android.systemui.animation.Interpolators
/** Displays security messages for the keyguard bouncer. */
open class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) :
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index a30cae9..a6c782d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -15,9 +15,9 @@
import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
-import com.android.app.animation.Interpolators;
import com.android.keyguard.dagger.KeyguardStatusViewScope;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.ClockController;
import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.plugins.log.LogLevel;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 0982030..0394754 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -32,9 +32,9 @@
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
-import com.android.app.animation.Interpolators;
import com.android.settingslib.animation.DisappearAnimationUtils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 1d7c35d..33bea02 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -45,11 +45,11 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.app.animation.Interpolators;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.TextViewInputDisabler;
import com.android.systemui.DejankUtils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
/**
* Displays an alphanumeric (latin-1) key entry for the user to enter
* an unlock password
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index b4ddc9a..0a91150 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -34,9 +34,9 @@
import android.view.KeyEvent;
import android.view.View;
-import com.android.app.animation.Interpolators;
import com.android.internal.widget.LockscreenCredential;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 78021ad..ba5a8c9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -32,7 +32,7 @@
import static androidx.constraintlayout.widget.ConstraintSet.TOP;
import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
-import static com.android.app.animation.InterpolatorsAndroidX.DECELERATE_QUINT;
+import static com.android.systemui.animation.InterpolatorsAndroidX.DECELERATE_QUINT;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
import static java.lang.Integer.max;
@@ -86,7 +86,6 @@
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringAnimation;
-import com.android.app.animation.Interpolators;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -97,6 +96,7 @@
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
index 96ac8ad..c9128e5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
@@ -26,9 +26,9 @@
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
-import com.android.app.animation.Interpolators
import com.android.internal.R.interpolator.fast_out_extra_slow_in
import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
/** Animates constraint layout changes for the security view. */
class KeyguardSecurityViewTransition : Transition() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index b4f124a..65a7166 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -44,11 +44,11 @@
import androidx.slice.widget.RowContent;
import androidx.slice.widget.SliceContent;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 89e7e17..edfcb8d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -40,11 +40,11 @@
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
-import com.android.app.animation.Interpolators;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ClockController;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index aa652fa..651c979 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -21,7 +21,7 @@
import android.util.Property;
import android.view.View;
-import com.android.app.animation.Interpolators;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.statusbar.StatusBarState;
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index e761123..ad66909 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -30,7 +30,7 @@
import androidx.annotation.StyleRes;
-import com.android.app.animation.Interpolators;
+import com.android.systemui.animation.Interpolators;
/**
* Provides background color and radius animations for key pad buttons.
diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
index c4ecb39..14810d9 100644
--- a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
@@ -35,9 +35,9 @@
import androidx.core.graphics.drawable.DrawableCompat;
-import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
/**
* This class contains implementation for methods that will be used when user has set a
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index 401f6c9..bf84f8a 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -35,6 +35,8 @@
/**
* Single common instance of ActivityStarter that can be gotten and referenced from anywhere, but
* delegates to an actual implementation (CentralSurfaces).
+ *
+ * @deprecated Migrating to ActivityStarterImpl
*/
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@SysUISingleton
@@ -92,6 +94,14 @@
}
@Override
+ public void startActivity(Intent intent,
+ boolean dismissShade,
+ @Nullable ActivityLaunchAnimator.Controller animationController) {
+ mActualStarterOptionalLazy.get().ifPresent(
+ starter -> starter.startActivity(intent, dismissShade, animationController));
+ }
+
+ @Override
public void startActivity(Intent intent, boolean dismissShade,
@Nullable ActivityLaunchAnimator.Controller animationController,
boolean showOverLockscreenWhenLocked) {
@@ -177,4 +187,35 @@
starter -> starter.dismissKeyguardThenExecute(action, cancel, afterKeyguardGone,
customMessage));
}
+
+ @Override
+ public void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned,
+ boolean dismissShade, boolean disallowEnterPictureInPictureWhileLaunching,
+ Callback callback, int flags,
+ @Nullable ActivityLaunchAnimator.Controller animationController,
+ UserHandle userHandle) {
+ mActualStarterOptionalLazy.get().ifPresent(
+ starter -> starter.startActivityDismissingKeyguard(intent, onlyProvisioned,
+ dismissShade, disallowEnterPictureInPictureWhileLaunching, callback,
+ flags, animationController, userHandle));
+ }
+
+ @Override
+ public void executeRunnableDismissingKeyguard(Runnable runnable,
+ Runnable cancelAction, boolean dismissShade,
+ boolean afterKeyguardGone, boolean deferred) {
+ mActualStarterOptionalLazy.get().ifPresent(
+ starter -> starter.executeRunnableDismissingKeyguard(runnable, cancelAction,
+ dismissShade, afterKeyguardGone, deferred));
+ }
+
+ @Override
+ public void executeRunnableDismissingKeyguard(Runnable runnable, Runnable cancelAction,
+ boolean dismissShade, boolean afterKeyguardGone, boolean deferred,
+ boolean willAnimateOnKeyguard, @Nullable String customMessage) {
+ mActualStarterOptionalLazy.get().ifPresent(
+ starter -> starter.executeRunnableDismissingKeyguard(runnable, cancelAction,
+ dismissShade, afterKeyguardGone, deferred, willAnimateOnKeyguard,
+ customMessage));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
index c1871e0..de82ca0 100644
--- a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
+++ b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
@@ -36,7 +36,7 @@
import android.view.View
import androidx.annotation.VisibleForTesting
import com.android.systemui.RegionInterceptingFrameLayout.RegionInterceptableView
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.util.asIndenting
import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
index e72ad82..a3e7d71 100644
--- a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
@@ -34,7 +34,7 @@
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.settingslib.Utils
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.biometrics.AuthController
import com.android.systemui.log.ScreenDecorationsLogger
import com.android.systemui.plugins.statusbar.StatusBarStateController
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 9adfcc9..aa94ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -43,8 +43,8 @@
import androidx.annotation.VisibleForTesting;
-import com.android.app.animation.Interpolators;
import com.android.internal.dynamicanimation.animation.SpringForce;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.FalsingManager;
@@ -374,11 +374,10 @@
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
final boolean captured = (mIsSwiping || mLongPressSent || mMenuRowIntercepting);
- mIsSwiping = false;
- mTouchedView = null;
mLongPressSent = false;
mCallback.onLongPressSent(null);
mMenuRowIntercepting = false;
+ resetSwipeState();
cancelLongPress();
if (captured) return true;
break;
@@ -491,7 +490,7 @@
}
if (!mCancelled || wasRemoved) {
mCallback.onChildDismissed(animView);
- resetSwipeState();
+ resetSwipeOfView(animView);
}
if (endAction != null) {
endAction.accept(mCancelled);
@@ -546,7 +545,7 @@
if (!cancelled) {
updateSwipeProgressFromOffset(animView, canBeDismissed);
- resetSwipeState();
+ resetSwipeOfView(animView);
}
onChildSnappedBack(animView, targetLeft);
});
@@ -806,9 +805,20 @@
return mIsSwiping ? mTouchedView : null;
}
+ protected void resetSwipeOfView(View view) {
+ if (getSwipedView() == view) {
+ resetSwipeState();
+ }
+ }
+
public void resetSwipeState() {
+ View swipedView = getSwipedView();
mTouchedView = null;
mIsSwiping = false;
+ if (swipedView != null) {
+ snapChildIfNeeded(swipedView, false, 0);
+ onChildSnappedBack(swipedView, 0);
+ }
}
private float getTouchSlop(MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
index d491975..d6f0b59 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
@@ -32,8 +32,8 @@
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
-import com.android.app.animation.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
/**
* Visually discloses that contextual data was provided to an assistant.
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index 2aac056..0002ae9 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -45,9 +45,9 @@
import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
-import com.android.app.animation.Interpolators;
import com.android.systemui.DualToneHandler;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.policy.BatteryController;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index be585ed..aeebb01 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -59,11 +59,11 @@
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.biometrics.AuthController.ScaleFactorProvider;
import com.android.systemui.biometrics.domain.interactor.BiometricPromptCredentialInteractor;
import com.android.systemui.biometrics.ui.CredentialView;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 782a10b..d0ac296 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -32,7 +32,7 @@
import com.android.settingslib.udfps.UdfpsOverlayParams
import com.android.systemui.CoreStartable
import com.android.systemui.R
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 5ede16d..b007134 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -28,7 +28,7 @@
import android.view.View
import android.view.animation.PathInterpolator
import com.android.internal.graphics.ColorUtils
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.surfaceeffects.ripple.RippleShader
private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
index 1dbafc6..ef7dcb7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
@@ -19,7 +19,7 @@
import android.graphics.PointF
import android.graphics.RectF
import com.android.systemui.Dumpable
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionListener
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index 52db4ab..ba8e60a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -40,9 +40,9 @@
import androidx.annotation.Nullable;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
-import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieProperty;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
index eaab75a..3b50bbc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
@@ -23,11 +23,11 @@
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.animation.Interpolators
import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
index 9292bd7..e2d36dc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
@@ -6,8 +6,8 @@
import android.widget.TextView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.animation.Interpolators
import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
import com.android.systemui.biometrics.AuthDialog
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.ui.CredentialPasswordView
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index 7bf8f4d..11ef749 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -30,9 +30,9 @@
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.surfaceeffects.ripple.RippleShader;
import com.android.systemui.surfaceeffects.ripple.RippleShader.RippleShape;
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
index b447d66..8d0edf8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
@@ -32,7 +32,7 @@
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import com.android.systemui.R
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.controls.ui.ControlsUiController
object ControlsAnimations {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index e6361f4..6a9aaf8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -50,7 +50,7 @@
import androidx.annotation.VisibleForTesting
import com.android.internal.graphics.ColorUtils
import com.android.systemui.R
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.util.concurrency.DelayableExecutor
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index 1461135..fa36eee 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -38,7 +38,7 @@
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import com.android.systemui.R
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MAX_LEVEL
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MIN_LEVEL
import java.util.IllegalFormatException
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index f6435a7..0dcba50 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -278,6 +278,7 @@
@Provides
@Singleton
+ @Nullable
static IVrManager provideIVrManager() {
return IVrManager.Stub.asInterface(ServiceManager.getService(Context.VR_SERVICE));
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java b/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java
index 67ad3db..8764297 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java
@@ -18,6 +18,8 @@
import com.android.systemui.ActivityStarterDelegate;
import com.android.systemui.classifier.FalsingManagerProxy;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.globalactions.GlobalActionsComponent;
import com.android.systemui.globalactions.GlobalActionsImpl;
import com.android.systemui.plugins.ActivityStarter;
@@ -28,6 +30,7 @@
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.phone.ActivityStarterImpl;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
import com.android.systemui.volume.VolumeDialogControllerImpl;
@@ -46,7 +49,11 @@
/** */
@Provides
static ActivityStarter provideActivityStarter(ActivityStarterDelegate delegate,
- PluginDependencyProvider dependencyProvider) {
+ PluginDependencyProvider dependencyProvider, ActivityStarterImpl activityStarterImpl,
+ FeatureFlags featureFlags) {
+ if (featureFlags.isEnabled(Flags.USE_NEW_ACTIVITY_STARTER)) {
+ return activityStarterImpl;
+ }
dependencyProvider.allowPluginDependency(ActivityStarter.class, delegate);
return delegate;
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index 83f39b5..5b56c04 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -24,8 +24,8 @@
import androidx.core.animation.doOnEnd
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.animation.Interpolators
import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
import com.android.systemui.complication.ComplicationHostViewController
import com.android.systemui.complication.ComplicationLayoutParams
import com.android.systemui.complication.ComplicationLayoutParams.POSITION_BOTTOM
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index c22019e..15a32d2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -33,9 +33,9 @@
import androidx.annotation.NonNull;
-import com.android.app.animation.Interpolators;
import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.complication.ComplicationHostViewController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index 0f370ac..b141db1 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -199,7 +199,8 @@
if (mShouldShowComplications) {
return (requiredTypes & getAvailableComplicationTypes()) == requiredTypes;
}
- return (requiredTypes & mSupportedTypes) == requiredTypes;
+ final int typesToAlwaysShow = mSupportedTypes & getAvailableComplicationTypes();
+ return (requiredTypes & typesToAlwaysShow) == requiredTypes;
})
.collect(Collectors.toCollection(HashSet::new))
: mComplications);
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 2ecb0a0..17e66a7 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -675,4 +675,8 @@
@JvmField
val ADVANCED_VPN_ENABLED = unreleasedFlag(2800, name = "AdvancedVpn__enable_feature",
namespace = "vpn", teamfood = true)
+
+ // TODO(b/278761837): Tracking Bug
+ @JvmField
+ val USE_NEW_ACTIVITY_STARTER = unreleasedFlag(2801, name = "use_new_activity_starter")
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 5189944..d3b6fc2 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -97,7 +97,6 @@
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
-import com.android.app.animation.Interpolators;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
@@ -117,6 +116,7 @@
import com.android.systemui.animation.DialogCuj;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.animation.Expandable;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Background;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
index d3fe2c5..8c0cfba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
@@ -23,6 +23,7 @@
import android.text.TextUtils;
import androidx.annotation.IntDef;
+import androidx.annotation.VisibleForTesting;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.Dumpable;
@@ -74,7 +75,9 @@
// Executor that will show the next message after a delay
private final DelayableExecutor mExecutor;
- @Nullable private ShowNextIndication mShowNextIndicationRunnable;
+
+ @VisibleForTesting
+ @Nullable ShowNextIndication mShowNextIndicationRunnable;
// List of indication types to show. The next indication to show is always at index 0
private final List<Integer> mIndicationQueue = new ArrayList<>();
@@ -111,6 +114,12 @@
cancelScheduledIndication();
}
+ /** Destroy ViewController, removing any listeners. */
+ public void destroy() {
+ super.destroy();
+ onViewDetached();
+ }
+
/**
* Update the indication type with the given String.
* @param type of indication
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 9844ca0..2925d8d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -36,7 +36,7 @@
import com.android.internal.R
import com.android.keyguard.KeyguardClockSwitchController
import com.android.keyguard.KeyguardViewController
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 99a9bed5..93ddfba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -98,7 +98,6 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import com.android.app.animation.Interpolators;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -122,6 +121,7 @@
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index cde67f9..e6568f2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index 7e9cbc1..c2d139c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index aca4019..86f65dde 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index fc7bfb4..3beac0b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index 39c630b..b5bcd45 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 0505d37..87f3164 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index 944adba..1fbfff9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index d4af381..94961cb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -17,10 +17,10 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.app.animation.Interpolators
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password
import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
index 9d7477c..38b9d50 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui
import android.view.animation.Interpolator
-import com.android.app.animation.Interpolators.LINEAR
+import com.android.systemui.animation.Interpolators.LINEAR
import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index c8d37a1..d96609c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -32,11 +32,11 @@
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.animation.Interpolators
import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.Expandable
+import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.view.LaunchableLinearLayout
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.binder.IconViewBinder
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
index 2c9a9b3..8d6545a4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
@@ -16,8 +16,8 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
-import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
index c135786..f16827d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DREAMING_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
index c6187dd..bc9dc4f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
index d3ea89c..a60665a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
index 6845c55..ddce516 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index 68810f9..df93d23 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
index e38abc2..37d956b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
@@ -21,9 +21,9 @@
import android.text.format.DateUtils
import androidx.annotation.UiThread
import androidx.lifecycle.Observer
-import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
import com.android.systemui.media.controls.ui.SquigglyProgress
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
index b46ebb2..3669493 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
@@ -34,10 +34,10 @@
import android.util.MathUtils
import android.view.View
import androidx.annotation.Keep
-import com.android.app.animation.Interpolators
import com.android.internal.graphics.ColorUtils
import com.android.internal.graphics.ColorUtils.blendARGB
import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
import org.xmlpull.v1.XmlPullParser
private const val BACKGROUND_ANIM_DURATION = 370L
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
index 937a618..dd5c2bf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
@@ -35,9 +35,9 @@
import android.util.AttributeSet
import android.util.MathUtils.lerp
import androidx.annotation.Keep
-import com.android.app.animation.Interpolators
import com.android.internal.graphics.ColorUtils
import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
import org.xmlpull.v1.XmlPullParser
private const val RIPPLE_ANIM_DURATION = 800L
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index f9d3094..40027a1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -72,7 +72,6 @@
import androidx.annotation.UiThread;
import androidx.constraintlayout.widget.ConstraintSet;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.jank.InteractionJankMonitor;
@@ -83,6 +82,7 @@
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.GhostedViewLaunchAnimatorController;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.bluetooth.BroadcastDialogController;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.qualifiers.Background;
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index fe8ebaf..49e1665 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -33,9 +33,9 @@
import android.view.ViewGroup
import android.view.ViewGroupOverlay
import androidx.annotation.VisibleForTesting
-import com.android.app.animation.Interpolators
import com.android.keyguard.KeyguardViewController
import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dreams.DreamOverlayStateController
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
index 583c626..e9b2cf2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
@@ -31,8 +31,8 @@
import android.util.MathUtils.lerpInv
import android.util.MathUtils.lerpInvSat
import androidx.annotation.VisibleForTesting
-import com.android.app.animation.Interpolators
import com.android.internal.graphics.ColorUtils
+import com.android.systemui.animation.Interpolators
import kotlin.math.abs
import kotlin.math.cos
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 77ff036..78082c3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -36,7 +36,7 @@
import android.view.View.ACCESSIBILITY_LIVE_REGION_NONE
import com.android.internal.widget.CachingIconView
import com.android.systemui.R
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.ui.binder.TintedIconViewBinder
import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 146b5f5..94f01b8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -58,11 +58,11 @@
import androidx.annotation.Nullable;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.Utils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
import com.android.systemui.navigationbar.buttons.ContextualButton;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
index 10084bd..0218016 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
@@ -16,7 +16,7 @@
package com.android.systemui.navigationbar.buttons;
-import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.systemui.animation.Interpolators.LINEAR;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -24,6 +24,9 @@
import android.view.View;
import android.view.View.AccessibilityDelegate;
+import com.android.systemui.Dependency;
+import com.android.systemui.assist.AssistManager;
+
import java.util.ArrayList;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index ff22398..590efbb 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -48,10 +48,10 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.app.animation.Interpolators;
import com.android.internal.util.LatencyTracker;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.NavigationEdgeBackPlugin;
import com.android.systemui.settings.DisplayTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 463c79c..a7aac5a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -26,7 +26,7 @@
import androidx.annotation.Nullable;
-import com.android.app.animation.Interpolators;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 09cc2c5..d806afa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -18,10 +18,9 @@
import static com.android.systemui.media.dagger.MediaModule.QS_PANEL;
import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
+import static com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
-import static com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.res.Configuration;
@@ -44,10 +43,10 @@
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
-import com.android.app.animation.Interpolators;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.compose.ComposeFacade;
import com.android.systemui.dump.DumpManager;
@@ -120,6 +119,7 @@
private final QSLogger mLogger;
private final FooterActionsController mFooterActionsController;
private final FooterActionsViewModel.Factory mFooterActionsViewModelFactory;
+ private final FooterActionsViewBinder mFooterActionsViewBinder;
private final ListeningAndVisibilityLifecycleOwner mListeningAndVisibilityLifecycleOwner;
private boolean mShowCollapsedOnKeyguard;
private boolean mLastKeyguardAndExpanded;
@@ -177,6 +177,7 @@
DumpManager dumpManager, QSLogger qsLogger,
FooterActionsController footerActionsController,
FooterActionsViewModel.Factory footerActionsViewModelFactory,
+ FooterActionsViewBinder footerActionsViewBinder,
LargeScreenShadeInterpolator largeScreenShadeInterpolator,
FeatureFlags featureFlags) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
@@ -193,6 +194,7 @@
mDumpManager = dumpManager;
mFooterActionsController = footerActionsController;
mFooterActionsViewModelFactory = footerActionsViewModelFactory;
+ mFooterActionsViewBinder = footerActionsViewBinder;
mListeningAndVisibilityLifecycleOwner = new ListeningAndVisibilityLifecycleOwner();
}
@@ -285,7 +287,7 @@
if (!ComposeFacade.INSTANCE.isComposeAvailable()) {
Log.d(TAG, "Binding the View implementation of the QS footer actions");
- FooterActionsViewBinder.bind(footerActionsView, mQSFooterActionsViewModel,
+ mFooterActionsViewBinder.bind(footerActionsView, mQSFooterActionsViewModel,
mListeningAndVisibilityLifecycleOwner);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
index 1921586..9c9ad33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
@@ -33,27 +33,27 @@
import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.ui.binder.IconViewBinder
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.people.ui.view.PeopleViewBinder.bind
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsButtonViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsForegroundServicesButtonViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsSecurityButtonViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
+import javax.inject.Inject
import kotlin.math.roundToInt
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
/** A ViewBinder for [FooterActionsViewBinder]. */
-object FooterActionsViewBinder {
+@SysUISingleton
+class FooterActionsViewBinder @Inject constructor() {
/** Create a view that can later be [bound][bind] to a [FooterActionsViewModel]. */
- @JvmStatic
fun create(context: Context): LinearLayout {
return LayoutInflater.from(context).inflate(R.layout.footer_actions, /* root= */ null)
as LinearLayout
}
/** Bind [view] to [viewModel]. */
- @JvmStatic
fun bind(
view: LinearLayout,
viewModel: FooterActionsViewModel,
@@ -98,6 +98,11 @@
var previousForegroundServices: FooterActionsForegroundServicesButtonViewModel? = null
var previousUserSwitcher: FooterActionsButtonViewModel? = null
+ // Set the initial visibility on the View directly so that we don't briefly show it for a
+ // few frames before [viewModel.isVisible] is collected.
+ view.isInvisible = !viewModel.isVisible.value
+
+ // Listen for ViewModel updates when the View is attached.
view.repeatWhenAttached {
val attachedScope = this.lifecycleScope
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index 3a9098a..b3596a2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -64,7 +64,7 @@
* the UI should still participate to the layout it is included in (i.e. in the View world it
* should be INVISIBLE, not GONE).
*/
- private val _isVisible = MutableStateFlow(true)
+ private val _isVisible = MutableStateFlow(false)
val isVisible: StateFlow<Boolean> = _isVisible.asStateFlow()
/** The alpha the UI rendering this ViewModel should have. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index 5ea1c0b..4b22edc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -23,15 +23,16 @@
import android.util.Log;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+import dagger.Lazy;
+
import java.util.Optional;
import javax.inject.Inject;
-import dagger.Lazy;
-
/**
* An implementation of the Recents interface which proxies to the OverviewProxyService.
*/
@@ -44,13 +45,15 @@
private Handler mHandler;
private final OverviewProxyService mOverviewProxyService;
+ private final ActivityStarter mActivityStarter;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyRecentsImpl(Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
- OverviewProxyService overviewProxyService) {
+ OverviewProxyService overviewProxyService, ActivityStarter activityStarter) {
mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
mOverviewProxyService = overviewProxyService;
+ mActivityStarter = activityStarter;
}
@Override
@@ -101,7 +104,7 @@
final Optional<CentralSurfaces> centralSurfacesOptional =
mCentralSurfacesOptionalLazy.get();
if (centralSurfacesOptional.map(CentralSurfaces::isKeyguardShowing).orElse(false)) {
- centralSurfacesOptional.get().executeRunnableDismissingKeyguard(
+ mActivityStarter.executeRunnableDismissingKeyguard(
() -> mHandler.post(toggleRecents), null, true /* dismissShade */,
false /* afterKeyguardGone */,
true /* deferred */);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
index 4f5cb72..3aefcb3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
@@ -33,11 +33,9 @@
import android.view.RemoteAnimationAdapter;
import android.view.WindowManagerGlobal;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
-
-import java.util.Optional;
import javax.inject.Inject;
@@ -48,20 +46,20 @@
public class ActionProxyReceiver extends BroadcastReceiver {
private static final String TAG = "ActionProxyReceiver";
- private final CentralSurfaces mCentralSurfaces;
private final ActivityManagerWrapper mActivityManagerWrapper;
private final ScreenshotSmartActions mScreenshotSmartActions;
private final DisplayTracker mDisplayTracker;
+ private final ActivityStarter mActivityStarter;
@Inject
- public ActionProxyReceiver(Optional<CentralSurfaces> centralSurfacesOptional,
- ActivityManagerWrapper activityManagerWrapper,
+ public ActionProxyReceiver(ActivityManagerWrapper activityManagerWrapper,
ScreenshotSmartActions screenshotSmartActions,
- DisplayTracker displayTracker) {
- mCentralSurfaces = centralSurfacesOptional.orElse(null);
+ DisplayTracker displayTracker,
+ ActivityStarter activityStarter) {
mActivityManagerWrapper = activityManagerWrapper;
mScreenshotSmartActions = screenshotSmartActions;
mDisplayTracker = displayTracker;
+ mActivityStarter = activityStarter;
}
@Override
@@ -92,13 +90,9 @@
};
- if (mCentralSurfaces != null) {
- mCentralSurfaces.executeRunnableDismissingKeyguard(startActivityRunnable, null,
- true /* dismissShade */, true /* afterKeyguardGone */,
- true /* deferred */);
- } else {
- startActivityRunnable.run();
- }
+ mActivityStarter.executeRunnableDismissingKeyguard(startActivityRunnable, null,
+ true /* dismissShade */, true /* afterKeyguardGone */,
+ true /* deferred */);
if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) {
String actionType = Intent.ACTION_EDIT.equals(intent.getAction())
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
index 4cb91e1..14e875d2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
@@ -21,53 +21,44 @@
import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.shade.ShadeExpansionStateManager
-import com.android.systemui.statusbar.phone.CentralSurfaces
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import java.util.Optional
-import javax.inject.Inject
-/**
- * Provides state from the main SystemUI process on behalf of the Screenshot process.
- */
-internal class ScreenshotProxyService @Inject constructor(
+/** Provides state from the main SystemUI process on behalf of the Screenshot process. */
+internal class ScreenshotProxyService
+@Inject
+constructor(
private val mExpansionMgr: ShadeExpansionStateManager,
- private val mCentralSurfacesOptional: Optional<CentralSurfaces>,
@Main private val mMainDispatcher: CoroutineDispatcher,
+ private val activityStarter: ActivityStarter,
) : LifecycleService() {
- private val mBinder: IBinder = object : IScreenshotProxy.Stub() {
- /**
- * @return true when the notification shade is partially or fully expanded.
- */
- override fun isNotificationShadeExpanded(): Boolean {
- val expanded = !mExpansionMgr.isClosed()
- Log.d(TAG, "isNotificationShadeExpanded(): $expanded")
- return expanded
- }
+ private val mBinder: IBinder =
+ object : IScreenshotProxy.Stub() {
+ /** @return true when the notification shade is partially or fully expanded. */
+ override fun isNotificationShadeExpanded(): Boolean {
+ val expanded = !mExpansionMgr.isClosed()
+ Log.d(TAG, "isNotificationShadeExpanded(): $expanded")
+ return expanded
+ }
- override fun dismissKeyguard(callback: IOnDoneCallback) {
- lifecycleScope.launch {
- executeAfterDismissing(callback)
+ override fun dismissKeyguard(callback: IOnDoneCallback) {
+ lifecycleScope.launch { executeAfterDismissing(callback) }
}
}
- }
private suspend fun executeAfterDismissing(callback: IOnDoneCallback) =
withContext(mMainDispatcher) {
- mCentralSurfacesOptional.ifPresentOrElse(
- {
- it.executeRunnableDismissingKeyguard(
- Runnable {
- callback.onDone(true)
- }, null,
- true /* dismissShade */, true /* afterKeyguardGone */,
- true /* deferred */
- )
- },
- { callback.onDone(false) }
+ activityStarter.executeRunnableDismissingKeyguard(
+ Runnable { callback.onDone(true) },
+ null,
+ true /* dismissShade */,
+ true /* afterKeyguardGone */,
+ true /* deferred */
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index be92bd4..5117915 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -22,10 +22,10 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
-import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
-import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
+import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
+import static com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
import static com.android.systemui.classifier.Classifier.GENERIC;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -88,7 +88,6 @@
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
@@ -112,6 +111,7 @@
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.Classifier;
@@ -4086,7 +4086,7 @@
if (!mFalsingManager.isUnlockingDisabled() && qsFullyExpanded
&& mFalsingCollector.shouldEnforceBouncer()) {
- mCentralSurfaces.executeRunnableDismissingKeyguard(null, null,
+ mActivityStarter.executeRunnableDismissingKeyguard(null, null,
false, true, false);
}
if (DEBUG_DRAWABLE) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index 7a79e85..ef14d1c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -50,7 +50,6 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
@@ -60,6 +59,7 @@
import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index 4131e7d..f0815e9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -34,10 +34,10 @@
import android.widget.TextView
import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.motion.widget.MotionLayout
-import com.android.app.animation.Interpolators
import com.android.settingslib.Utils
import com.android.systemui.Dumpable
import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterViewController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index c1ebf12..63179da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -18,8 +18,8 @@
import android.view.View;
-import com.android.app.animation.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 1a32d70..54b341f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -38,8 +38,8 @@
import android.view.animation.Interpolator;
import android.widget.ImageView;
-import com.android.app.animation.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.wm.shell.animation.FlingAnimationUtils;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 142689e..ea5a1c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -335,6 +335,9 @@
R.id.keyguard_indication_text_bottom);
mInitialTextColorState = mTopIndicationView != null
? mTopIndicationView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
+ if (mRotateTextViewController != null) {
+ mRotateTextViewController.destroy();
+ }
mRotateTextViewController = new KeyguardIndicationRotateTextViewController(
mLockScreenIndicationView,
mExecutor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 823bb35..9421524 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -16,7 +16,7 @@
import android.util.MathUtils.lerp
import android.view.View
import android.view.animation.PathInterpolator
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.statusbar.LightRevealEffect.Companion.getPercentPastThreshold
import com.android.systemui.util.getColorWithAlpha
import com.android.systemui.util.leak.RotationUtils
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 2258968..c5f64b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -18,7 +18,7 @@
import com.android.systemui.ExpandHelper
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.biometrics.UdfpsKeyguardViewController
import com.android.systemui.classifier.Classifier
import com.android.systemui.classifier.FalsingCollector
@@ -26,6 +26,7 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.media.controls.ui.MediaHierarchyManager
+import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.ActivityStarter.OnDismissAction
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QS
@@ -62,11 +63,12 @@
private val mediaHierarchyManager: MediaHierarchyManager,
private val scrimTransitionController: LockscreenShadeScrimTransitionController,
private val keyguardTransitionControllerFactory:
- LockscreenShadeKeyguardTransitionController.Factory,
+ LockscreenShadeKeyguardTransitionController.Factory,
private val depthController: NotificationShadeDepthController,
private val context: Context,
private val splitShadeOverScrollerFactory: SplitShadeLockScreenOverScroller.Factory,
private val singleShadeOverScrollerFactory: SingleShadeLockScreenOverScroller.Factory,
+ private val activityStarter: ActivityStarter,
wakefulnessLifecycle: WakefulnessLifecycle,
configurationController: ConfigurationController,
falsingManager: FalsingManager,
@@ -305,7 +307,7 @@
if (nsslController.isInLockedDownShade()) {
logger.logDraggedDownLockDownShade(startingChild)
statusBarStateController.setLeaveOpenOnKeyguardHide(true)
- centralSurfaces.dismissKeyguardThenExecute(OnDismissAction {
+ activityStarter.dismissKeyguardThenExecute(OnDismissAction {
nextHideKeyguardNeedsNoAnimation = true
false
}, cancelRunnable, false /* afterKeyguardGone */)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index fb88a96..72ae16e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -44,9 +44,9 @@
import android.view.View;
import android.widget.ImageView;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index d37cbcc..8dc7842 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -33,7 +33,7 @@
import androidx.dynamicanimation.animation.SpringAnimation
import androidx.dynamicanimation.animation.SpringForce
import com.android.systemui.Dumpable
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 5c3bacc..7eb63da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -35,10 +35,10 @@
import androidx.annotation.NonNull;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index f9d4f1a..976924a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -31,7 +31,7 @@
import com.android.systemui.Dumpable
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
index f1e51e2..575f354 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
@@ -4,7 +4,7 @@
import android.content.res.Configuration
import android.util.MathUtils
import com.android.systemui.R
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.policy.ConfigurationController
import dagger.assisted.Assisted
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
index 3d574ca..572c0e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
@@ -8,7 +8,7 @@
import android.view.animation.PathInterpolator
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.qs.QS
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 91c08a0..7755003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -52,10 +52,10 @@
import androidx.core.graphics.ColorUtils;
-import com.android.app.animation.Interpolators;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.util.drawable.DrawableSize;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index d6a14604..79d01b4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -42,7 +42,6 @@
import androidx.annotation.NonNull;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
@@ -50,6 +49,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index 67ab060..2fa27ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -25,8 +25,8 @@
import android.view.ViewGroup;
import android.view.animation.Interpolator;
-import com.android.app.animation.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.TransformState;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
index eddb683..bfc4e9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -26,7 +26,7 @@
import android.widget.FrameLayout
import com.android.internal.annotations.GuardedBy
import com.android.systemui.R
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.statusbar.StatusBarStateController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index b09b9f4..0446165 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -21,8 +21,8 @@
import android.view.View;
import android.widget.ImageView;
-import com.android.app.animation.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.notification.row.HybridNotificationView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
index 785e65d..c22dbf6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
@@ -3,7 +3,7 @@
import android.util.MathUtils
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.LaunchAnimator
import kotlin.math.min
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
index 5a14200..c22cd1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
@@ -23,13 +23,13 @@
import android.view.ViewGroup;
import android.widget.TextView;
-import com.android.app.animation.Interpolators;
import com.android.internal.widget.IMessagingLayout;
import com.android.internal.widget.MessagingGroup;
import com.android.internal.widget.MessagingImageMessage;
import com.android.internal.widget.MessagingLinearLayout;
import com.android.internal.widget.MessagingMessage;
import com.android.internal.widget.MessagingPropertyAnimator;
+import com.android.systemui.animation.Interpolators;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
index a045698..3fc7b13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
@@ -24,8 +24,8 @@
import android.view.View;
import android.widget.ImageView;
-import com.android.app.animation.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import java.util.function.Consumer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 9ba2199..fe0b28d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -21,8 +21,8 @@
import androidx.annotation.VisibleForTesting
import androidx.core.animation.ObjectAnimator
import com.android.systemui.Dumpable
-import com.android.app.animation.Interpolators
-import com.android.app.animation.InterpolatorsAndroidX
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.animation.InterpolatorsAndroidX
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
index 57d20246..5d07cac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
@@ -24,7 +24,7 @@
import android.view.View;
import android.view.animation.Interpolator;
-import com.android.app.animation.Interpolators;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.AnimationFilter;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ViewState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 90eb630..9f9fba4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -23,11 +23,11 @@
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.android.app.animation.Interpolators;
import com.android.internal.widget.MessagingImageMessage;
import com.android.internal.widget.MessagingPropertyAnimator;
import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
index 16f1a45..dc16274 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
@@ -22,7 +22,7 @@
import android.view.View
import android.view.ViewGroup
import com.android.systemui.R
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
/**
* Class to help with fading of view groups without fading one subview
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index f70d5e6..766ad88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -31,12 +31,12 @@
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
-import com.android.app.animation.Interpolators;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.settingslib.Utils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 2695410..e468a59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -64,7 +64,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -73,6 +72,7 @@
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.CallLayout;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
index 7a2bee9..b56bae1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
@@ -45,10 +45,10 @@
import androidx.annotation.VisibleForTesting;
-import com.android.app.animation.Interpolators;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.InstanceIdSequence;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 9dbbc58..5edff5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -32,9 +32,9 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.app.animation.Interpolators;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.Roundable;
import com.android.systemui.statusbar.notification.RoundableState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 9bc0333..f21db0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -25,7 +25,7 @@
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
-import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.systemui.animation.Interpolators.FAST_OUT_SLOW_IN;
import static java.lang.annotation.RetentionPolicy.SOURCE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index 047db20..596bdc0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -33,9 +33,9 @@
import androidx.annotation.Nullable;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index e6e6b99..0c4b092 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -49,6 +49,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserContextProvider;
@@ -73,8 +74,6 @@
import javax.inject.Inject;
-import dagger.Lazy;
-
/**
* Handles various NotificationGuts related tasks, such as binding guts to a row, opening and
* closing guts, and keeping track of the currently exposed notification guts.
@@ -107,7 +106,6 @@
private NotificationListContainer mListContainer;
private OnSettingsClickListener mOnSettingsClickListener;
- private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
private final Handler mMainHandler;
private final Handler mBgHandler;
private final Optional<BubblesManager> mBubblesManagerOptional;
@@ -121,10 +119,10 @@
private final ShadeController mShadeController;
private NotifGutsViewListener mGutsListener;
private final HeadsUpManagerPhone mHeadsUpManagerPhone;
+ private final ActivityStarter mActivityStarter;
@Inject
public NotificationGutsManager(Context context,
- Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
@Main Handler mainHandler,
@Background Handler bgHandler,
AccessibilityManager accessibilityManager,
@@ -144,9 +142,9 @@
StatusBarStateController statusBarStateController,
DeviceProvisionedController deviceProvisionedController,
MetricsLogger metricsLogger,
- HeadsUpManagerPhone headsUpManagerPhone) {
+ HeadsUpManagerPhone headsUpManagerPhone,
+ ActivityStarter activityStarter) {
mContext = context;
- mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
mMainHandler = mainHandler;
mBgHandler = bgHandler;
mAccessibilityManager = accessibilityManager;
@@ -167,6 +165,7 @@
mDeviceProvisionedController = deviceProvisionedController;
mMetricsLogger = metricsLogger;
mHeadsUpManagerPhone = headsUpManagerPhone;
+ mActivityStarter = activityStarter;
}
public void setUpWithPresenter(NotificationPresenter presenter,
@@ -551,19 +550,15 @@
.setLeaveOpenOnKeyguardHide(true);
}
- Optional<CentralSurfaces> centralSurfacesOptional =
- mCentralSurfacesOptionalLazy.get();
- if (centralSurfacesOptional.isPresent()) {
- Runnable r = () -> mMainHandler.post(
- () -> openGutsInternal(view, x, y, menuItem));
- centralSurfacesOptional.get().executeRunnableDismissingKeyguard(
- r,
- null /* cancelAction */,
- false /* dismissShade */,
- true /* afterKeyguardGone */,
- true /* deferred */);
- return true;
- }
+ Runnable r = () -> mMainHandler.post(
+ () -> openGutsInternal(view, x, y, menuItem));
+ mActivityStarter.executeRunnableDismissingKeyguard(
+ r,
+ null /* cancelAction */,
+ false /* dismissShade */,
+ true /* afterKeyguardGone */,
+ true /* deferred */);
+ return true;
/**
* When {@link CentralSurfaces} doesn't exist, falling through to call
* {@link #openGutsInternal(View,int,int,NotificationMenuRowPlugin.MenuItem)}.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 99a7755..8a50f2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -20,7 +20,7 @@
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
-import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.systemui.animation.Interpolators.FAST_OUT_SLOW_IN;
import static java.lang.annotation.RetentionPolicy.SOURCE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index 5a129fc..bafc474 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -39,9 +39,9 @@
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index d5d7f75..5f4c926 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -45,11 +45,11 @@
import android.widget.LinearLayout;
import android.widget.TextView;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index b24cec1..5aaf63f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -23,8 +23,8 @@
import android.view.View;
import android.view.animation.Interpolator;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.animation.Interpolators;
import java.util.function.Consumer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 84fe9ef..9a777ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -34,10 +34,10 @@
import androidx.annotation.Nullable;
-import com.android.app.animation.Interpolators;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.notification.CustomInterpolatorTransformation;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
index d73bbeb..7f3381c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
@@ -22,8 +22,8 @@
import android.animation.ValueAnimator;
import android.view.View;
-import com.android.app.animation.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index 9a33a94..0b435fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -26,7 +26,7 @@
import android.view.View;
import android.view.animation.Interpolator;
-import com.android.app.animation.Interpolators;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.ShadeViewRefactor;
import com.android.systemui.statusbar.notification.row.ExpandableView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 24e8f39..3bc2066 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -75,7 +75,6 @@
import android.widget.OverScroller;
import android.widget.ScrollView;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.jank.InteractionJankMonitor;
@@ -87,8 +86,10 @@
import com.android.systemui.Dumpable;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.CommandQueue;
@@ -319,6 +320,7 @@
};
private NotificationStackScrollLogger mLogger;
private CentralSurfaces mCentralSurfaces;
+ private ActivityStarter mActivityStarter;
private final int[] mTempInt2 = new int[2];
private boolean mGenerateChildOrderChangedEvent;
private final HashSet<Runnable> mAnimationFinishedRunnables = new HashSet<>();
@@ -4189,10 +4191,7 @@
mCentralSurfaces.resetUserExpandedStates();
clearTemporaryViews();
clearUserLockedViews();
- if (mSwipeHelper.isSwiping()) {
- mSwipeHelper.resetSwipeState();
- updateContinuousShadowDrawing();
- }
+ cancelActiveSwipe();
}
}
@@ -4264,6 +4263,9 @@
if (!mIsExpanded) {
mGroupExpansionManager.collapseGroups();
mExpandHelper.cancelImmediately();
+ if (!mIsExpansionChanging) {
+ cancelActiveSwipe();
+ }
}
updateNotificationAnimationStates();
updateChronometers();
@@ -4814,6 +4816,10 @@
this.mCentralSurfaces = centralSurfaces;
}
+ public void setActivityStarter(ActivityStarter activityStarter) {
+ mActivityStarter = activityStarter;
+ }
+
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
void requestAnimateEverything() {
if (mIsExpanded && mAnimationsEnabled) {
@@ -5579,7 +5585,7 @@
Intent intent = showHistory
? new Intent(Settings.ACTION_NOTIFICATION_HISTORY)
: new Intent(Settings.ACTION_NOTIFICATION_SETTINGS);
- mCentralSurfaces.startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ mActivityStarter.startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
});
setEmptyShadeView(view);
updateEmptyShadeView(
@@ -6113,7 +6119,11 @@
}
}
- @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+ private void cancelActiveSwipe() {
+ mSwipeHelper.resetSwipeState();
+ updateContinuousShadowDrawing();
+ }
+
void updateContinuousShadowDrawing() {
boolean continuousShadowUpdate = mAnimationRunning
|| mSwipeHelper.isSwiping();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index b69ce38..4751fb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -63,6 +63,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
@@ -198,6 +199,7 @@
private final NotificationTargetsHelper mNotificationTargetsHelper;
private final SecureSettings mSecureSettings;
private final NotificationDismissibilityProvider mDismissibilityProvider;
+ private final ActivityStarter mActivityStarter;
private View mLongPressedView;
@@ -487,7 +489,7 @@
mView.addSwipedOutView(view);
mFalsingCollector.onNotificationDismissed();
if (mFalsingCollector.shouldEnforceBouncer()) {
- mCentralSurfaces.executeRunnableDismissingKeyguard(
+ mActivityStarter.executeRunnableDismissingKeyguard(
null,
null /* cancelAction */,
false /* dismissShade */,
@@ -678,7 +680,8 @@
FeatureFlags featureFlags,
NotificationTargetsHelper notificationTargetsHelper,
SecureSettings secureSettings,
- NotificationDismissibilityProvider dismissibilityProvider) {
+ NotificationDismissibilityProvider dismissibilityProvider,
+ ActivityStarter activityStarter) {
mView = view;
mStackStateLogger = stackLogger;
mLogger = logger;
@@ -724,6 +727,7 @@
mNotificationTargetsHelper = notificationTargetsHelper;
mSecureSettings = secureSettings;
mDismissibilityProvider = dismissibilityProvider;
+ mActivityStarter = activityStarter;
updateResources();
setUpView();
}
@@ -734,6 +738,7 @@
mView.setLogger(mLogger);
mView.setTouchHandler(new TouchHandler());
mView.setCentralSurfaces(mCentralSurfaces);
+ mView.setActivityStarter(mActivityStarter);
mView.setClearAllAnimationListener(this::onAnimationEnd);
mView.setClearAllListener((selection) -> mUiEventLogger.log(
NotificationPanelEvent.fromSelection(selection)));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index f07dd00..ee72943 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -22,9 +22,9 @@
import android.util.Property;
import android.view.View;
-import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardSliceView;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
index f4605be..d07da38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
@@ -26,9 +26,9 @@
import android.view.View;
import android.view.animation.Interpolator;
-import com.android.app.animation.Interpolators;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.NotificationFadeAware.FadeOptimizedNotification;
import com.android.systemui.statusbar.notification.PropertyAnimator;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
new file mode 100644
index 0000000..d9dc887
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -0,0 +1,867 @@
+/*
+ * 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.systemui.statusbar.phone
+
+import android.app.ActivityManager
+import android.app.ActivityOptions
+import android.app.ActivityTaskManager
+import android.app.PendingIntent
+import android.app.TaskStackBuilder
+import android.content.Context
+import android.content.Intent
+import android.os.RemoteException
+import android.os.UserHandle
+import android.provider.Settings
+import android.util.Log
+import android.view.RemoteAnimationAdapter
+import android.view.View
+import android.view.WindowManager
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.ActivityIntentHelper
+import com.android.systemui.R
+import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.ActivityLaunchAnimator.PendingIntentStarter
+import com.android.systemui.animation.DelegateLaunchAnimatorController
+import com.android.systemui.assist.AssistManager
+import com.android.systemui.camera.CameraIntents.Companion.isInsecureCameraIntent
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.KeyguardViewMediator
+import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeController
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.kotlin.getOrNull
+import dagger.Lazy
+import java.util.Optional
+import javax.inject.Inject
+
+/** Handles start activity logic in SystemUI. */
+@SysUISingleton
+class ActivityStarterImpl
+@Inject
+constructor(
+ private val centralSurfacesOptLazy: Lazy<Optional<CentralSurfaces>>,
+ private val assistManagerLazy: Lazy<AssistManager>,
+ private val dozeServiceHostLazy: Lazy<DozeServiceHost>,
+ private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController>,
+ private val keyguardViewMediatorLazy: Lazy<KeyguardViewMediator>,
+ private val shadeControllerLazy: Lazy<ShadeController>,
+ private val statusBarKeyguardViewManagerLazy: Lazy<StatusBarKeyguardViewManager>,
+ private val activityLaunchAnimator: ActivityLaunchAnimator,
+ private val context: Context,
+ private val lockScreenUserManager: NotificationLockscreenUserManager,
+ private val statusBarWindowController: StatusBarWindowController,
+ private val wakefulnessLifecycle: WakefulnessLifecycle,
+ private val keyguardStateController: KeyguardStateController,
+ private val statusBarStateController: SysuiStatusBarStateController,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val deviceProvisionedController: DeviceProvisionedController,
+ private val userTracker: UserTracker,
+ private val activityIntentHelper: ActivityIntentHelper,
+ @Main private val mainExecutor: DelayableExecutor,
+) : ActivityStarter {
+ companion object {
+ const val TAG = "ActivityStarterImpl"
+ }
+
+ private val centralSurfaces: CentralSurfaces?
+ get() = centralSurfacesOptLazy.get().getOrNull()
+
+ private val activityStarterInternal = ActivityStarterInternal()
+
+ override fun startPendingIntentDismissingKeyguard(intent: PendingIntent) {
+ activityStarterInternal.startPendingIntentDismissingKeyguard(intent = intent)
+ }
+
+ override fun startPendingIntentDismissingKeyguard(
+ intent: PendingIntent,
+ intentSentUiThreadCallback: Runnable?,
+ ) {
+ activityStarterInternal.startPendingIntentDismissingKeyguard(
+ intent = intent,
+ intentSentUiThreadCallback = intentSentUiThreadCallback,
+ )
+ }
+
+ override fun startPendingIntentDismissingKeyguard(
+ intent: PendingIntent,
+ intentSentUiThreadCallback: Runnable?,
+ associatedView: View?,
+ ) {
+ activityStarterInternal.startPendingIntentDismissingKeyguard(
+ intent = intent,
+ intentSentUiThreadCallback = intentSentUiThreadCallback,
+ associatedView = associatedView,
+ )
+ }
+
+ override fun startPendingIntentDismissingKeyguard(
+ intent: PendingIntent,
+ intentSentUiThreadCallback: Runnable?,
+ animationController: ActivityLaunchAnimator.Controller?,
+ ) {
+ activityStarterInternal.startPendingIntentDismissingKeyguard(
+ intent = intent,
+ intentSentUiThreadCallback = intentSentUiThreadCallback,
+ animationController = animationController,
+ )
+ }
+
+ /**
+ * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate
+ * this.
+ */
+ override fun startActivity(intent: Intent, dismissShade: Boolean) {
+ activityStarterInternal.startActivityDismissingKeyguard(
+ intent = intent,
+ dismissShade = dismissShade,
+ )
+ }
+
+ /**
+ * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate
+ * this.
+ */
+ override fun startActivity(intent: Intent, onlyProvisioned: Boolean, dismissShade: Boolean) {
+ activityStarterInternal.startActivityDismissingKeyguard(
+ intent = intent,
+ onlyProvisioned = onlyProvisioned,
+ dismissShade = dismissShade,
+ )
+ }
+
+ /**
+ * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate
+ * this.
+ */
+ override fun startActivity(
+ intent: Intent,
+ dismissShade: Boolean,
+ callback: ActivityStarter.Callback?,
+ ) {
+ activityStarterInternal.startActivityDismissingKeyguard(
+ intent = intent,
+ dismissShade = dismissShade,
+ callback = callback,
+ )
+ }
+
+ /**
+ * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate
+ * this.
+ */
+ override fun startActivity(
+ intent: Intent,
+ onlyProvisioned: Boolean,
+ dismissShade: Boolean,
+ flags: Int,
+ ) {
+ activityStarterInternal.startActivityDismissingKeyguard(
+ intent = intent,
+ onlyProvisioned = onlyProvisioned,
+ dismissShade = dismissShade,
+ flags = flags,
+ )
+ }
+
+ override fun startActivity(
+ intent: Intent,
+ dismissShade: Boolean,
+ animationController: ActivityLaunchAnimator.Controller?,
+ showOverLockscreenWhenLocked: Boolean,
+ ) {
+ activityStarterInternal.startActivity(
+ intent = intent,
+ dismissShade = dismissShade,
+ animationController = animationController,
+ showOverLockscreenWhenLocked = showOverLockscreenWhenLocked,
+ )
+ }
+ override fun startActivity(
+ intent: Intent,
+ dismissShade: Boolean,
+ animationController: ActivityLaunchAnimator.Controller?,
+ showOverLockscreenWhenLocked: Boolean,
+ userHandle: UserHandle?,
+ ) {
+ activityStarterInternal.startActivity(
+ intent = intent,
+ dismissShade = dismissShade,
+ animationController = animationController,
+ showOverLockscreenWhenLocked = showOverLockscreenWhenLocked,
+ userHandle = userHandle,
+ )
+ }
+
+ override fun postStartActivityDismissingKeyguard(intent: PendingIntent) {
+ postOnUiThread {
+ activityStarterInternal.startPendingIntentDismissingKeyguard(
+ intent = intent,
+ )
+ }
+ }
+
+ override fun postStartActivityDismissingKeyguard(
+ intent: PendingIntent,
+ animationController: ActivityLaunchAnimator.Controller?
+ ) {
+ postOnUiThread {
+ activityStarterInternal.startPendingIntentDismissingKeyguard(
+ intent = intent,
+ animationController = animationController,
+ )
+ }
+ }
+
+ override fun postStartActivityDismissingKeyguard(intent: Intent, delay: Int) {
+ postOnUiThread(delay) {
+ activityStarterInternal.startActivityDismissingKeyguard(intent = intent)
+ }
+ }
+
+ override fun postStartActivityDismissingKeyguard(
+ intent: Intent,
+ delay: Int,
+ animationController: ActivityLaunchAnimator.Controller?,
+ ) {
+ postOnUiThread(delay) {
+ activityStarterInternal.startActivityDismissingKeyguard(
+ intent = intent,
+ animationController = animationController,
+ )
+ }
+ }
+
+ override fun postStartActivityDismissingKeyguard(
+ intent: Intent,
+ delay: Int,
+ animationController: ActivityLaunchAnimator.Controller?,
+ customMessage: String?,
+ ) {
+ postOnUiThread(delay) {
+ activityStarterInternal.startActivityDismissingKeyguard(
+ intent = intent,
+ animationController = animationController,
+ customMessage = customMessage,
+ )
+ }
+ }
+
+ override fun dismissKeyguardThenExecute(
+ action: OnDismissAction,
+ cancel: Runnable?,
+ afterKeyguardGone: Boolean,
+ ) {
+ activityStarterInternal.dismissKeyguardThenExecute(
+ action = action,
+ cancel = cancel,
+ afterKeyguardGone = afterKeyguardGone,
+ )
+ }
+
+ override fun dismissKeyguardThenExecute(
+ action: OnDismissAction,
+ cancel: Runnable?,
+ afterKeyguardGone: Boolean,
+ customMessage: String?,
+ ) {
+ activityStarterInternal.dismissKeyguardThenExecute(
+ action = action,
+ cancel = cancel,
+ afterKeyguardGone = afterKeyguardGone,
+ customMessage = customMessage,
+ )
+ }
+
+ override fun startActivityDismissingKeyguard(
+ intent: Intent,
+ onlyProvisioned: Boolean,
+ dismissShade: Boolean,
+ disallowEnterPictureInPictureWhileLaunching: Boolean,
+ callback: ActivityStarter.Callback?,
+ flags: Int,
+ animationController: ActivityLaunchAnimator.Controller?,
+ userHandle: UserHandle?,
+ ) {
+ activityStarterInternal.startActivityDismissingKeyguard(
+ intent = intent,
+ onlyProvisioned = onlyProvisioned,
+ dismissShade = dismissShade,
+ disallowEnterPictureInPictureWhileLaunching =
+ disallowEnterPictureInPictureWhileLaunching,
+ callback = callback,
+ flags = flags,
+ animationController = animationController,
+ userHandle = userHandle,
+ )
+ }
+
+ override fun executeRunnableDismissingKeyguard(
+ runnable: Runnable?,
+ cancelAction: Runnable?,
+ dismissShade: Boolean,
+ afterKeyguardGone: Boolean,
+ deferred: Boolean,
+ ) {
+ activityStarterInternal.executeRunnableDismissingKeyguard(
+ runnable = runnable,
+ cancelAction = cancelAction,
+ dismissShade = dismissShade,
+ afterKeyguardGone = afterKeyguardGone,
+ deferred = deferred,
+ )
+ }
+
+ override fun executeRunnableDismissingKeyguard(
+ runnable: Runnable?,
+ cancelAction: Runnable?,
+ dismissShade: Boolean,
+ afterKeyguardGone: Boolean,
+ deferred: Boolean,
+ willAnimateOnKeyguard: Boolean,
+ customMessage: String?,
+ ) {
+ activityStarterInternal.executeRunnableDismissingKeyguard(
+ runnable = runnable,
+ cancelAction = cancelAction,
+ dismissShade = dismissShade,
+ afterKeyguardGone = afterKeyguardGone,
+ deferred = deferred,
+ willAnimateOnKeyguard = willAnimateOnKeyguard,
+ customMessage = customMessage,
+ )
+ }
+
+ override fun postQSRunnableDismissingKeyguard(runnable: Runnable?) {
+ postOnUiThread {
+ statusBarStateController.setLeaveOpenOnKeyguardHide(true)
+ activityStarterInternal.executeRunnableDismissingKeyguard(
+ runnable = { runnable?.let { postOnUiThread(runnable = it) } },
+ )
+ }
+ }
+
+ private fun postOnUiThread(delay: Int = 0, runnable: Runnable) {
+ mainExecutor.executeDelayed(runnable, delay.toLong())
+ }
+
+ /**
+ * Encapsulates the activity logic for activity starter.
+ *
+ * Logic is duplicated in {@link CentralSurfacesImpl}
+ */
+ private inner class ActivityStarterInternal {
+ /** Starts an activity after dismissing keyguard. */
+ fun startActivityDismissingKeyguard(
+ intent: Intent,
+ onlyProvisioned: Boolean = false,
+ dismissShade: Boolean = false,
+ disallowEnterPictureInPictureWhileLaunching: Boolean = false,
+ callback: ActivityStarter.Callback? = null,
+ flags: Int = 0,
+ animationController: ActivityLaunchAnimator.Controller? = null,
+ userHandle: UserHandle? = null,
+ customMessage: String? = null,
+ ) {
+ val userHandle: UserHandle = userHandle ?: getActivityUserHandle(intent)
+
+ if (onlyProvisioned && !deviceProvisionedController.isDeviceProvisioned) return
+
+ val willLaunchResolverActivity: Boolean =
+ activityIntentHelper.wouldLaunchResolverActivity(
+ intent,
+ lockScreenUserManager.currentUserId
+ )
+
+ val animate =
+ animationController != null &&
+ !willLaunchResolverActivity &&
+ centralSurfaces?.shouldAnimateLaunch(true /* isActivityIntent */) == true
+ val animController =
+ wrapAnimationController(
+ animationController = animationController,
+ dismissShade = dismissShade,
+ isLaunchForActivity = true,
+ )
+
+ // If we animate, we will dismiss the shade only once the animation is done. This is
+ // taken care of by the StatusBarLaunchAnimationController.
+ val dismissShadeDirectly = dismissShade && animController == null
+
+ val runnable = Runnable {
+ assistManagerLazy.get().hideAssist()
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
+ intent.addFlags(flags)
+ val result = intArrayOf(ActivityManager.START_CANCELED)
+ activityLaunchAnimator.startIntentWithAnimation(
+ animController,
+ animate,
+ intent.getPackage()
+ ) { adapter: RemoteAnimationAdapter? ->
+ val options =
+ ActivityOptions(
+ CentralSurfaces.getActivityOptions(centralSurfaces!!.displayId, adapter)
+ )
+
+ // We know that the intent of the caller is to dismiss the keyguard and
+ // this runnable is called right after the keyguard is solved, so we tell
+ // WM that we should dismiss it to avoid flickers when opening an activity
+ // that can also be shown over the keyguard.
+ options.setDismissKeyguard()
+ options.setDisallowEnterPictureInPictureWhileLaunching(
+ disallowEnterPictureInPictureWhileLaunching
+ )
+ if (isInsecureCameraIntent(intent)) {
+ // Normally an activity will set it's requested rotation
+ // animation on its window. However when launching an activity
+ // causes the orientation to change this is too late. In these cases
+ // the default animation is used. This doesn't look good for
+ // the camera (as it rotates the camera contents out of sync
+ // with physical reality). So, we ask the WindowManager to
+ // force the cross fade animation if an orientation change
+ // happens to occur during the launch.
+ options.rotationAnimationHint =
+ WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS
+ }
+ if (Settings.Panel.ACTION_VOLUME == intent.action) {
+ // Settings Panel is implemented as activity(not a dialog), so
+ // underlying app is paused and may enter picture-in-picture mode
+ // as a result.
+ // So we need to disable picture-in-picture mode here
+ // if it is volume panel.
+ options.setDisallowEnterPictureInPictureWhileLaunching(true)
+ }
+ try {
+ result[0] =
+ ActivityTaskManager.getService()
+ .startActivityAsUser(
+ null,
+ context.basePackageName,
+ context.attributionTag,
+ intent,
+ intent.resolveTypeIfNeeded(context.contentResolver),
+ null,
+ null,
+ 0,
+ Intent.FLAG_ACTIVITY_NEW_TASK,
+ null,
+ options.toBundle(),
+ userHandle.identifier,
+ )
+ } catch (e: RemoteException) {
+ Log.w(TAG, "Unable to start activity", e)
+ }
+ result[0]
+ }
+ callback?.onActivityStarted(result[0])
+ }
+ val cancelRunnable = Runnable {
+ callback?.onActivityStarted(ActivityManager.START_CANCELED)
+ }
+ // Do not deferKeyguard when occluded because, when keyguard is occluded,
+ // we do not launch the activity until keyguard is done.
+ val occluded = (keyguardStateController.isShowing && keyguardStateController.isOccluded)
+ val deferred = !occluded
+ executeRunnableDismissingKeyguard(
+ runnable,
+ cancelRunnable,
+ dismissShadeDirectly,
+ willLaunchResolverActivity,
+ deferred,
+ animate,
+ customMessage,
+ )
+ }
+
+ /** Starts a pending intent after dismissing keyguard. */
+ fun startPendingIntentDismissingKeyguard(
+ intent: PendingIntent,
+ intentSentUiThreadCallback: Runnable? = null,
+ associatedView: View? = null,
+ animationController: ActivityLaunchAnimator.Controller? = null,
+ ) {
+ val animationController =
+ if (associatedView is ExpandableNotificationRow) {
+ centralSurfaces?.getAnimatorControllerFromNotification(associatedView)
+ } else animationController
+
+ val willLaunchResolverActivity =
+ (intent.isActivity &&
+ activityIntentHelper.wouldPendingLaunchResolverActivity(
+ intent,
+ lockScreenUserManager.currentUserId,
+ ))
+
+ val animate =
+ !willLaunchResolverActivity &&
+ animationController != null &&
+ centralSurfaces?.shouldAnimateLaunch(intent.isActivity) == true
+
+ // If we animate, don't collapse the shade and defer the keyguard dismiss (in case we
+ // run the animation on the keyguard). The animation will take care of (instantly)
+ // collapsing the shade and hiding the keyguard once it is done.
+ val collapse = !animate
+ executeRunnableDismissingKeyguard(
+ runnable = {
+ try {
+ // We wrap animationCallback with a StatusBarLaunchAnimatorController so
+ // that the shade is collapsed after the animation (or when it is cancelled,
+ // aborted, etc).
+ val controller: ActivityLaunchAnimator.Controller? =
+ wrapAnimationController(
+ animationController = animationController,
+ dismissShade = true,
+ isLaunchForActivity = intent.isActivity,
+ )
+ activityLaunchAnimator.startPendingIntentWithAnimation(
+ controller,
+ animate,
+ intent.creatorPackage,
+ object : PendingIntentStarter {
+ override fun startPendingIntent(
+ animationAdapter: RemoteAnimationAdapter?
+ ): Int {
+ val options =
+ ActivityOptions(
+ CentralSurfaces.getActivityOptions(
+ centralSurfaces!!.displayId,
+ animationAdapter
+ )
+ )
+ // TODO b/221255671: restrict this to only be set for
+ // notifications
+ options.isEligibleForLegacyPermissionPrompt = true
+ return intent.sendAndReturnResult(
+ null,
+ 0,
+ null,
+ null,
+ null,
+ null,
+ options.toBundle()
+ )
+ }
+ },
+ )
+ } catch (e: PendingIntent.CanceledException) {
+ // the stack trace isn't very helpful here.
+ // Just log the exception message.
+ Log.w(TAG, "Sending intent failed: $e")
+ if (!collapse) {
+ // executeRunnableDismissingKeyguard did not collapse for us already.
+ centralSurfaces?.collapsePanelOnMainThread()
+ }
+ // TODO: Dismiss Keyguard.
+ }
+ if (intent.isActivity) {
+ assistManagerLazy.get().hideAssist()
+ }
+ intentSentUiThreadCallback?.let { postOnUiThread(runnable = it) }
+ },
+ afterKeyguardGone = willLaunchResolverActivity,
+ dismissShade = collapse,
+ willAnimateOnKeyguard = animate,
+ )
+ }
+
+ /** Starts an Activity. */
+ fun startActivity(
+ intent: Intent,
+ dismissShade: Boolean = false,
+ animationController: ActivityLaunchAnimator.Controller? = null,
+ showOverLockscreenWhenLocked: Boolean = false,
+ userHandle: UserHandle? = null,
+ ) {
+ val userHandle = userHandle ?: getActivityUserHandle(intent)
+ // Make sure that we dismiss the keyguard if it is directly dismissible or when we don't
+ // want to show the activity above it.
+ if (keyguardStateController.isUnlocked || !showOverLockscreenWhenLocked) {
+ startActivityDismissingKeyguard(
+ intent = intent,
+ onlyProvisioned = false,
+ dismissShade = dismissShade,
+ disallowEnterPictureInPictureWhileLaunching = false,
+ callback = null,
+ flags = 0,
+ animationController = animationController,
+ userHandle = userHandle,
+ )
+ return
+ }
+
+ val animate =
+ animationController != null &&
+ centralSurfaces?.shouldAnimateLaunch(
+ /* isActivityIntent= */ true,
+ showOverLockscreenWhenLocked
+ ) == true
+
+ var controller: ActivityLaunchAnimator.Controller? = null
+ if (animate) {
+ // Wrap the animation controller to dismiss the shade and set
+ // mIsLaunchingActivityOverLockscreen during the animation.
+ val delegate =
+ wrapAnimationController(
+ animationController = animationController,
+ dismissShade = dismissShade,
+ isLaunchForActivity = true,
+ )
+ delegate?.let {
+ controller =
+ object : DelegateLaunchAnimatorController(delegate) {
+ override fun onIntentStarted(willAnimate: Boolean) {
+ delegate?.onIntentStarted(willAnimate)
+ if (willAnimate) {
+ centralSurfaces?.setIsLaunchingActivityOverLockscreen(true)
+ }
+ }
+
+ override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
+ super.onLaunchAnimationStart(isExpandingFullyAbove)
+
+ // Double check that the keyguard is still showing and not going
+ // away, but if so set the keyguard occluded. Typically, WM will let
+ // KeyguardViewMediator know directly, but we're overriding that to
+ // play the custom launch animation, so we need to take care of that
+ // here. The unocclude animation is not overridden, so WM will call
+ // KeyguardViewMediator's unocclude animation runner when the
+ // activity is exited.
+ if (
+ keyguardStateController.isShowing &&
+ !keyguardStateController.isKeyguardGoingAway
+ ) {
+ Log.d(TAG, "Setting occluded = true in #startActivity.")
+ keyguardViewMediatorLazy
+ .get()
+ .setOccluded(true /* isOccluded */, true /* animate */)
+ }
+ }
+
+ override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
+ // Set mIsLaunchingActivityOverLockscreen to false before actually
+ // finishing the animation so that we can assume that
+ // mIsLaunchingActivityOverLockscreen being true means that we will
+ // collapse the shade (or at least run the post collapse runnables)
+ // later on.
+ centralSurfaces?.setIsLaunchingActivityOverLockscreen(false)
+ delegate?.onLaunchAnimationEnd(isExpandingFullyAbove)
+ }
+
+ override fun onLaunchAnimationCancelled(
+ newKeyguardOccludedState: Boolean?
+ ) {
+ if (newKeyguardOccludedState != null) {
+ keyguardViewMediatorLazy
+ .get()
+ .setOccluded(newKeyguardOccludedState, false /* animate */)
+ }
+
+ // Set mIsLaunchingActivityOverLockscreen to false before actually
+ // finishing the animation so that we can assume that
+ // mIsLaunchingActivityOverLockscreen being true means that we will
+ // collapse the shade (or at least run the // post collapse
+ // runnables) later on.
+ centralSurfaces?.setIsLaunchingActivityOverLockscreen(false)
+ delegate.onLaunchAnimationCancelled(newKeyguardOccludedState)
+ }
+ }
+ }
+ } else if (dismissShade) {
+ // The animation will take care of dismissing the shade at the end of the animation.
+ // If we don't animate, collapse it directly.
+ centralSurfaces?.collapseShade()
+ }
+
+ // We should exit the dream to prevent the activity from starting below the
+ // dream.
+ if (keyguardUpdateMonitor.isDreaming) {
+ centralSurfaces?.awakenDreams()
+ }
+
+ activityLaunchAnimator.startIntentWithAnimation(
+ controller,
+ animate,
+ intent.getPackage(),
+ showOverLockscreenWhenLocked
+ ) { adapter: RemoteAnimationAdapter? ->
+ TaskStackBuilder.create(context)
+ .addNextIntent(intent)
+ .startActivities(
+ CentralSurfaces.getActivityOptions(centralSurfaces!!.displayId, adapter),
+ userHandle
+ )
+ }
+ }
+
+ /** Executes an action after dismissing keyguard. */
+ fun dismissKeyguardThenExecute(
+ action: OnDismissAction,
+ cancel: Runnable? = null,
+ afterKeyguardGone: Boolean = false,
+ customMessage: String? = null,
+ ) {
+ if (
+ !action.willRunAnimationOnKeyguard() &&
+ wakefulnessLifecycle.wakefulness == WakefulnessLifecycle.WAKEFULNESS_ASLEEP &&
+ keyguardStateController.canDismissLockScreen() &&
+ !statusBarStateController.leaveOpenOnKeyguardHide() &&
+ dozeServiceHostLazy.get().isPulsing
+ ) {
+ // Reuse the biometric wake-and-unlock transition if we dismiss keyguard from a
+ // pulse.
+ // TODO: Factor this transition out of BiometricUnlockController.
+ biometricUnlockControllerLazy
+ .get()
+ .startWakeAndUnlock(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING)
+ }
+ if (keyguardStateController.isShowing) {
+ statusBarKeyguardViewManagerLazy
+ .get()
+ .dismissWithAction(action, cancel, afterKeyguardGone, customMessage)
+ } else {
+ // If the keyguard isn't showing but the device is dreaming, we should exit the
+ // dream.
+ if (keyguardUpdateMonitor.isDreaming) {
+ centralSurfaces?.awakenDreams()
+ }
+ action.onDismiss()
+ }
+ }
+
+ /** Executes an action after dismissing keyguard. */
+ fun executeRunnableDismissingKeyguard(
+ runnable: Runnable? = null,
+ cancelAction: Runnable? = null,
+ dismissShade: Boolean = false,
+ afterKeyguardGone: Boolean = false,
+ deferred: Boolean = false,
+ willAnimateOnKeyguard: Boolean = false,
+ customMessage: String? = null,
+ ) {
+ val onDismissAction: OnDismissAction =
+ object : OnDismissAction {
+ override fun onDismiss(): Boolean {
+ if (runnable != null) {
+ if (
+ keyguardStateController.isShowing &&
+ keyguardStateController.isOccluded
+ ) {
+ statusBarKeyguardViewManagerLazy
+ .get()
+ .addAfterKeyguardGoneRunnable(runnable)
+ } else {
+ mainExecutor.execute(runnable)
+ }
+ }
+ if (dismissShade) {
+ if (
+ shadeControllerLazy.get().isExpandedVisible &&
+ !statusBarKeyguardViewManagerLazy.get().isBouncerShowing
+ ) {
+ shadeControllerLazy.get().animateCollapseShadeDelayed()
+ } else {
+ // Do it after DismissAction has been processed to conserve the
+ // needed ordering.
+ postOnUiThread {
+ shadeControllerLazy.get().runPostCollapseRunnables()
+ }
+ }
+ }
+ return deferred
+ }
+
+ override fun willRunAnimationOnKeyguard(): Boolean {
+ return willAnimateOnKeyguard
+ }
+ }
+ dismissKeyguardThenExecute(
+ onDismissAction,
+ cancelAction,
+ afterKeyguardGone,
+ customMessage,
+ )
+ }
+
+ /**
+ * Return a [ActivityLaunchAnimator.Controller] wrapping `animationController` so that:
+ * - if it launches in the notification shade window and `dismissShade` is true, then the
+ * shade will be instantly dismissed at the end of the animation.
+ * - if it launches in status bar window, it will make the status bar window match the
+ * device size during the animation (that way, the animation won't be clipped by the
+ * status bar size).
+ *
+ * @param animationController the controller that is wrapped and will drive the main
+ * animation.
+ * @param dismissShade whether the notification shade will be dismissed at the end of the
+ * animation. This is ignored if `animationController` is not animating in the shade
+ * window.
+ * @param isLaunchForActivity whether the launch is for an activity.
+ */
+ private fun wrapAnimationController(
+ animationController: ActivityLaunchAnimator.Controller?,
+ dismissShade: Boolean,
+ isLaunchForActivity: Boolean,
+ ): ActivityLaunchAnimator.Controller? {
+ if (animationController == null) {
+ return null
+ }
+ val rootView = animationController.launchContainer.rootView
+ val controllerFromStatusBar: Optional<ActivityLaunchAnimator.Controller> =
+ statusBarWindowController.wrapAnimationControllerIfInStatusBar(
+ rootView,
+ animationController
+ )
+ if (controllerFromStatusBar.isPresent) {
+ return controllerFromStatusBar.get()
+ }
+
+ centralSurfaces?.let {
+ // If the view is not in the status bar, then we are animating a view in the shade.
+ // We have to make sure that we collapse it when the animation ends or is cancelled.
+ if (dismissShade) {
+ return StatusBarLaunchAnimatorController(
+ animationController,
+ it,
+ isLaunchForActivity
+ )
+ }
+ }
+
+ return animationController
+ }
+
+ /** Retrieves the current user handle to start the Activity. */
+ private fun getActivityUserHandle(intent: Intent): UserHandle {
+ val packages: Array<String> =
+ context.resources.getStringArray(R.array.system_ui_packages)
+ for (pkg in packages) {
+ if (intent.component == null) break
+ if (pkg == intent.component.packageName) {
+ return UserHandle(UserHandle.myUserId())
+ }
+ }
+ return userTracker.userHandle
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 4590712..9dce332 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -33,9 +33,9 @@
import android.util.Log;
import android.view.View;
-import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index f579d30..4e69069 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -45,7 +45,8 @@
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.RemoteTransitionAdapter;
import com.android.systemui.navigationbar.NavigationBarView;
-import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter.Callback;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.shade.NotificationShadeWindowView;
@@ -53,11 +54,13 @@
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.LightRevealScrim;
import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.util.Compile;
import java.io.PrintWriter;
-public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwner {
+/** */
+public interface CentralSurfaces extends Dumpable, LifecycleOwner {
boolean MULTIUSER_DEBUG = false;
// Should match the values in PhoneWindowManager
String SYSTEM_DIALOG_REASON_KEY = "reason";
@@ -230,29 +233,33 @@
boolean isShadeDisabled();
- @Override
+ /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */
void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade,
int flags);
- @Override
+ /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */
void startActivity(Intent intent, boolean dismissShade);
- @Override
+ /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */
+ void startActivity(Intent intent, boolean dismissShade,
+ @Nullable ActivityLaunchAnimator.Controller animationController);
+
+ /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */
void startActivity(Intent intent, boolean dismissShade,
@Nullable ActivityLaunchAnimator.Controller animationController,
boolean showOverLockscreenWhenLocked);
- @Override
+ /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */
void startActivity(Intent intent, boolean dismissShade,
@Nullable ActivityLaunchAnimator.Controller animationController,
boolean showOverLockscreenWhenLocked, UserHandle userHandle);
boolean isLaunchingActivityOverLockscreen();
- @Override
+ /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */
void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade);
- @Override
+ /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */
void startActivity(Intent intent, boolean dismissShade, Callback callback);
boolean isWakeUpComingFromTouch();
@@ -315,19 +322,34 @@
float getDisplayHeight();
+ /** Starts an activity intent that dismisses keyguard.
+ *
+ * Please use ActivityStarter instead of using these methods directly.
+ */
void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned,
boolean dismissShade, int flags);
+ /** Starts an activity intent that dismisses keyguard.
+ *
+ * Please use ActivityStarter instead of using these methods directly.
+ */
void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned,
boolean dismissShade);
+ /** Starts an activity intent that dismisses keyguard.
+ *
+ * Please use ActivityStarter instead of using these methods directly.
+ */
void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned,
boolean dismissShade, boolean disallowEnterPictureInPictureWhileLaunching,
Callback callback, int flags,
@Nullable ActivityLaunchAnimator.Controller animationController,
UserHandle userHandle);
- /** Starts an activity intent that dismisses keyguard. */
+ /** Starts an activity intent that dismisses keyguard.
+ *
+ * Please use ActivityStarter instead of using these methods directly.
+ */
void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned,
boolean dismissShade, boolean disallowEnterPictureInPictureWhileLaunching,
Callback callback, int flags,
@@ -352,29 +374,70 @@
void resetUserExpandedStates();
- @Override
+ /**
+ * Dismisses Keyguard and executes an action afterwards.
+ *
+ * Please use ActivityStarter instead of using these methods directly.
+ */
void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
boolean afterKeyguardGone);
+ /**
+ * Dismisses Keyguard and executes an action afterwards.
+ *
+ * Please use ActivityStarter instead of using these methods directly.
+ */
+ void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
+ boolean afterKeyguardGone, @Nullable String customMessage);
+
void setLockscreenUser(int newUserId);
- @Override
+ /**
+ * Starts a QS runnable on the main thread and dismisses keyguard.
+ *
+ * Please use ActivityStarter instead of using these methods directly.
+ */
void postQSRunnableDismissingKeyguard(Runnable runnable);
- @Override
+ /**
+ * Starts an activity on the main thread with a delay.
+ *
+ * Please use ActivityStarter instead of using these methods directly.
+ */
void postStartActivityDismissingKeyguard(PendingIntent intent);
- @Override
+ /**
+ * Starts an activity on the main thread with a delay.
+ *
+ * Please use ActivityStarter instead of using these methods directly.
+ */
void postStartActivityDismissingKeyguard(PendingIntent intent,
@Nullable ActivityLaunchAnimator.Controller animationController);
- @Override
+ /**
+ * Starts an activity on the main thread with a delay.
+ *
+ * Please use ActivityStarter instead of using these methods directly.
+ */
void postStartActivityDismissingKeyguard(Intent intent, int delay);
- @Override
+ /**
+ * Starts an activity on the main thread with a delay.
+ *
+ * Please use ActivityStarter instead of using these methods directly.
+ */
void postStartActivityDismissingKeyguard(Intent intent, int delay,
@Nullable ActivityLaunchAnimator.Controller animationController);
+ /**
+ * Starts an activity on the main thread with a delay.
+ *
+ * Please use ActivityStarter instead of using these methods directly.
+ */
+ void postStartActivityDismissingKeyguard(Intent intent, int delay,
+ @Nullable ActivityLaunchAnimator.Controller animationController,
+ @Nullable String customMessage);
+
void showKeyguard();
boolean hideKeyguard();
@@ -468,18 +531,14 @@
void awakenDreams();
- @Override
void startPendingIntentDismissingKeyguard(PendingIntent intent);
- @Override
void startPendingIntentDismissingKeyguard(
PendingIntent intent, @Nullable Runnable intentSentUiThreadCallback);
- @Override
void startPendingIntentDismissingKeyguard(PendingIntent intent,
Runnable intentSentUiThreadCallback, View associatedView);
- @Override
void startPendingIntentDismissingKeyguard(
PendingIntent intent, @Nullable Runnable intentSentUiThreadCallback,
@Nullable ActivityLaunchAnimator.Controller animationController);
@@ -554,4 +613,15 @@
mDeviceId = deviceId;
}
}
+
+ /**
+ * Sets launching activity over LS state in central surfaces.
+ */
+ void setIsLaunchingActivityOverLockscreen(boolean isLaunchingActivityOverLockscreen);
+
+ /**
+ * Gets an animation controller from a notification row.
+ */
+ ActivityLaunchAnimator.Controller getAnimatorControllerFromNotification(
+ ExpandableNotificationRow associatedView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index c0a7a34..37e77766 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -50,6 +50,7 @@
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.settings.UserTracker;
@@ -102,6 +103,7 @@
private final boolean mVibrateOnOpening;
private final VibrationEffect mCameraLaunchGestureVibrationEffect;
private final SystemBarAttributesListener mSystemBarAttributesListener;
+ private final ActivityStarter mActivityStarter;
private final Lazy<CameraLauncher> mCameraLauncherLazy;
private final QuickSettingsController mQsController;
private final QSHost mQSHost;
@@ -138,7 +140,8 @@
SystemBarAttributesListener systemBarAttributesListener,
Lazy<CameraLauncher> cameraLauncherLazy,
UserTracker userTracker,
- QSHost qsHost) {
+ QSHost qsHost,
+ ActivityStarter activityStarter) {
mCentralSurfaces = centralSurfaces;
mQsController = quickSettingsController;
mContext = context;
@@ -170,6 +173,7 @@
mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
mVibratorOptional, resources);
mSystemBarAttributesListener = systemBarAttributesListener;
+ mActivityStarter = activityStarter;
}
@Override
@@ -375,7 +379,7 @@
if (!mKeyguardStateController.isShowing()) {
final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext);
cameraIntent.putExtra(CameraIntents.EXTRA_LAUNCH_SOURCE, source);
- mCentralSurfaces.startActivityDismissingKeyguard(cameraIntent,
+ mActivityStarter.startActivityDismissingKeyguard(cameraIntent,
false /* onlyProvisioned */, true /* dismissShade */,
true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
null /* animationController */, mUserTracker.getUserHandle());
@@ -432,7 +436,7 @@
// app-side haptic experimentation.
if (!mKeyguardStateController.isShowing()) {
- mCentralSurfaces.startActivityDismissingKeyguard(emergencyIntent,
+ mActivityStarter.startActivityDismissingKeyguard(emergencyIntent,
false /* onlyProvisioned */, true /* dismissShade */,
true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
null /* animationController */, mUserTracker.getUserHandle());
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 2387495..aa5aed7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -168,6 +168,8 @@
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.notetask.NoteTaskController;
+import com.android.systemui.plugins.ActivityStarter.Callback;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.OverlayPlugin;
@@ -281,6 +283,9 @@
* <b>If at all possible, please avoid adding additional code to this monstrous class! Our goal is
* to break up this class into many small classes, and any code added here will slow down that goal.
* </b>
+ *
+ * Note that ActivityStarter logic here is deprecated and should be added here as well as
+ * {@link ActivityStarterImpl}
*/
@SysUISingleton
public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
@@ -1790,17 +1795,27 @@
return (mDisabled1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade,
int flags) {
startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, flags);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void startActivity(Intent intent, boolean dismissShade) {
startActivityDismissingKeyguard(intent, false /* onlyProvisioned */, dismissShade);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
+ @Override
+ public void startActivity(Intent intent, boolean dismissShade,
+ @androidx.annotation.Nullable ActivityLaunchAnimator.Controller animationController) {
+ startActivity(intent, dismissShade, animationController, false);
+ }
+
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void startActivity(Intent intent, boolean dismissShade,
@Nullable ActivityLaunchAnimator.Controller animationController,
@@ -1809,6 +1824,7 @@
getActivityUserHandle(intent));
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void startActivity(Intent intent, boolean dismissShade,
@Nullable ActivityLaunchAnimator.Controller animationController,
@@ -2406,6 +2422,7 @@
return mDisplayId;
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
boolean dismissShade, int flags) {
@@ -2414,12 +2431,14 @@
flags, null /* animationController */, getActivityUserHandle(intent));
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
boolean dismissShade) {
startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, 0);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned,
boolean dismissShade, boolean disallowEnterPictureInPictureWhileLaunching,
@@ -2431,6 +2450,7 @@
userHandle, null /* customMessage */);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
@@ -2541,6 +2561,8 @@
* animation. This is ignored if {@code animationController} is not
* animating in the shade window.
* @param isLaunchForActivity whether the launch is for an activity.
+ *
+ * Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too.
*/
@Nullable
private ActivityLaunchAnimator.Controller wrapAnimationController(
@@ -2570,6 +2592,8 @@
mStatusBarKeyguardViewManager.readyForKeyguardDone();
}
+
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void executeRunnableDismissingKeyguard(final Runnable runnable,
final Runnable cancelAction,
@@ -2580,6 +2604,7 @@
deferred, false /* willAnimateOnKeyguard */, null /* customMessage */);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void executeRunnableDismissingKeyguard(final Runnable runnable,
final Runnable cancelAction,
@@ -2690,16 +2715,19 @@
afterKeyguardGone /* afterKeyguardGone */);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
boolean afterKeyguardGone) {
dismissKeyguardThenExecute(action, cancelAction, afterKeyguardGone, null);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
boolean afterKeyguardGone, String customMessage) {
@@ -2901,6 +2929,7 @@
| ((currentlyInsecure ? 1 : 0) << 12);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
mMainExecutor.execute(() -> {
@@ -2910,11 +2939,13 @@
});
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void postStartActivityDismissingKeyguard(PendingIntent intent) {
postStartActivityDismissingKeyguard(intent, null /* animationController */);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void postStartActivityDismissingKeyguard(final PendingIntent intent,
@Nullable ActivityLaunchAnimator.Controller animationController) {
@@ -2922,11 +2953,13 @@
null /* intentSentUiThreadCallback */, animationController));
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void postStartActivityDismissingKeyguard(final Intent intent, int delay) {
postStartActivityDismissingKeyguard(intent, delay, null /* animationController */);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void postStartActivityDismissingKeyguard(Intent intent, int delay,
@Nullable ActivityLaunchAnimator.Controller animationController) {
@@ -2934,6 +2967,7 @@
null /* customMessage */);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void postStartActivityDismissingKeyguard(Intent intent, int delay,
@Nullable ActivityLaunchAnimator.Controller animationController,
@@ -3640,9 +3674,6 @@
/* wakingUp= */ true,
mShouldDelayWakeUpAnimation);
- if (!mKeyguardBypassController.getBypassEnabled()) {
- mHeadsUpManager.releaseAllImmediately();
- }
updateVisibleToUser();
updateIsKeyguard();
mDozeServiceHost.stopDozing();
@@ -4084,11 +4115,13 @@
dismissKeyguardThenExecute(onDismissAction, afterKeyguardGone);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
startPendingIntentDismissingKeyguard(intent, null);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void startPendingIntentDismissingKeyguard(
final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback) {
@@ -4096,6 +4129,7 @@
(ActivityLaunchAnimator.Controller) null);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void startPendingIntentDismissingKeyguard(PendingIntent intent,
Runnable intentSentUiThreadCallback, View associatedView) {
@@ -4109,6 +4143,7 @@
animationController);
}
+ /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */
@Override
public void startPendingIntentDismissingKeyguard(
final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback,
@@ -4532,6 +4567,8 @@
* launched as user of the current process.
* @param intent
* @return UserHandle
+ *
+ * Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too.
*/
private UserHandle getActivityUserHandle(Intent intent) {
String[] packages = mContext.getResources().getStringArray(R.array.system_ui_packages);
@@ -4554,4 +4591,15 @@
&& mBiometricUnlockController.getMode()
!= BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
}
+
+ @Override
+ public void setIsLaunchingActivityOverLockscreen(boolean isLaunchingActivityOverLockscreen) {
+ mIsLaunchingActivityOverLockscreen = isLaunchingActivityOverLockscreen;
+ }
+
+ @Override
+ public ActivityLaunchAnimator.Controller getAnimatorControllerFromNotification(
+ ExpandableNotificationRow associatedView) {
+ return mNotificationAnimationProvider.getAnimatorController(associatedView);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index c1859b2..90a6d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -23,10 +23,10 @@
import android.content.res.Resources;
import android.util.MathUtils;
-import com.android.app.animation.Interpolators;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcherListView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index 61c1cc8..9d30cb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -30,9 +30,9 @@
import androidx.annotation.StyleRes;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.keyguard.KeyguardIndication;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 720eeba..13566ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -43,9 +43,9 @@
import androidx.annotation.VisibleForTesting;
-import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 5232fb6..e835c5ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -37,12 +37,12 @@
import androidx.core.animation.AnimatorListenerAdapter;
import androidx.core.animation.ValueAnimator;
-import com.android.app.animation.InterpolatorsAndroidX;
import com.android.keyguard.CarrierTextController;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.R;
+import com.android.systemui.animation.InterpolatorsAndroidX;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.log.LogLevel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 7bc4fc3..6bf5443 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -24,21 +24,21 @@
import android.util.MathUtils;
import android.util.TimeUtils;
-import com.android.app.animation.Interpolators;
import com.android.systemui.Dumpable;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
-import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-
/**
* Class to control all aspects about light bar changes.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 46a2457..cc4f901 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -31,9 +31,9 @@
import android.util.SparseArray;
import android.view.ViewTreeObserver.OnPreDrawListener;
-import com.android.app.animation.Interpolators;
import com.android.internal.graphics.ColorUtils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 560ea8a..55dc188 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -15,11 +15,11 @@
import androidx.annotation.VisibleForTesting;
import androidx.collection.ArrayMap;
-import com.android.app.animation.Interpolators;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ContrastColorUtil;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index bef422c..006a029d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -36,10 +36,10 @@
import androidx.annotation.VisibleForTesting;
import androidx.collection.ArrayMap;
-import com.android.app.animation.Interpolators;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.stack.AnimationFilter;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
index 07a6d0a..5e5317d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
@@ -29,7 +29,7 @@
import android.view.animation.AnimationUtils;
import android.widget.Button;
-import com.android.app.animation.Interpolators;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
public class SettingsButton extends AlphaOptimizedImageView {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index f7646d7..89dddbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -68,6 +68,7 @@
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.TaskbarDelegate;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
@@ -284,6 +285,7 @@
private boolean mIsBackAnimationEnabled;
private final boolean mUdfpsNewTouchDetectionEnabled;
private final UdfpsOverlayInteractor mUdfpsOverlayInteractor;
+ private final ActivityStarter mActivityStarter;
private OnDismissAction mAfterKeyguardGoneAction;
private Runnable mKeyguardGoneCancelAction;
@@ -339,7 +341,8 @@
PrimaryBouncerInteractor primaryBouncerInteractor,
BouncerView primaryBouncerView,
AlternateBouncerInteractor alternateBouncerInteractor,
- UdfpsOverlayInteractor udfpsOverlayInteractor
+ UdfpsOverlayInteractor udfpsOverlayInteractor,
+ ActivityStarter activityStarter
) {
mContext = context;
mViewMediatorCallback = callback;
@@ -367,6 +370,7 @@
featureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM);
mUdfpsNewTouchDetectionEnabled = featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION);
mUdfpsOverlayInteractor = udfpsOverlayInteractor;
+ mActivityStarter = activityStarter;
}
@Override
@@ -1006,7 +1010,13 @@
@Override
public void dismissAndCollapse() {
- mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, true, false, true);
+ mActivityStarter.executeRunnableDismissingKeyguard(
+ /* runnable= */ null,
+ /* cancelAction= */ null,
+ /* dismissShade= */ true,
+ /* afterKeyguardGone= */ false,
+ /* deferred= */ true
+ );
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index cdf6652..8fa803e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -15,7 +15,7 @@
import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF
import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
import com.android.systemui.DejankUtils
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 831d402..453dd1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -44,10 +44,10 @@
import androidx.annotation.VisibleForTesting;
import androidx.core.animation.Animator;
-import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
index e1ec94f..4dd63be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
@@ -24,9 +24,9 @@
import androidx.core.graphics.ColorUtils;
-import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardConstants;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.qs.tiles.UserDetailItemView;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 66b5256..928e011 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -31,7 +31,6 @@
import android.view.View;
import android.view.ViewGroup;
-import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardConstants;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -39,6 +38,7 @@
import com.android.keyguard.dagger.KeyguardUserSwitcherScope;
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
index 363b06a..850a4b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
@@ -21,11 +21,11 @@
import android.util.Log;
import android.view.View;
-import com.android.app.animation.Interpolators;
import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.keyguard.KeyguardConstants;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
+import com.android.systemui.animation.Interpolators;
/**
* The container for the user switcher on Keyguard.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index e311bad..403a7e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -73,7 +73,6 @@
import androidx.core.animation.ObjectAnimator;
import androidx.core.animation.ValueAnimator;
-import com.android.app.animation.InterpolatorsAndroidX;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.logging.UiEvent;
@@ -81,6 +80,7 @@
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.animation.InterpolatorsAndroidX;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
index 46954b5..1612388 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
@@ -18,7 +18,7 @@
import android.view.View
import android.view.ViewGroup
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.ViewHierarchyAnimator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.children
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
index 4fbbc89..e819f94 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
@@ -34,10 +34,10 @@
import androidx.annotation.DimenRes
import androidx.annotation.IdRes
import androidx.annotation.VisibleForTesting
-import com.android.app.animation.Interpolators
import com.android.internal.widget.CachingIconView
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
import com.android.systemui.common.shared.model.Text.Companion.loadText
diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
index 0dd5788..1f118d1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
@@ -109,6 +109,11 @@
}
}
+ /** Destroy ViewController, removing any listeners. */
+ public void destroy() {
+ mView.removeOnAttachStateChangeListener(mOnAttachStateListener);
+ }
+
/**
* Called when the view is attached and a call to {@link #init()} has been made in either order.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
index db4ab7e..5d80292 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
@@ -19,7 +19,7 @@
import android.animation.ValueAnimator
import android.graphics.PointF
import android.util.MathUtils
-import com.android.app.animation.Interpolators
+import com.android.systemui.animation.Interpolators
/**
* The fraction after which we start fading in when going from a gone widget to a visible one
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 91078dc..77210b7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -109,7 +109,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.app.animation.Interpolators;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -120,6 +119,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.Prefs;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.ActivityStarter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt
new file mode 100644
index 0000000..2c680be
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 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.systemui.animation
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import java.lang.reflect.Modifier
+import junit.framework.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class InterpolatorsAndroidXTest : SysuiTestCase() {
+
+ @Test
+ fun testInterpolatorsAndInterpolatorsAndroidXPublicMethodsAreEqual() {
+ assertEquals(
+ Interpolators::class.java.getPublicMethods(),
+ InterpolatorsAndroidX::class.java.getPublicMethods()
+ )
+ }
+
+ @Test
+ fun testInterpolatorsAndInterpolatorsAndroidXPublicFieldsAreEqual() {
+ assertEquals(
+ Interpolators::class.java.getPublicFields(),
+ InterpolatorsAndroidX::class.java.getPublicFields()
+ )
+ }
+
+ private fun <T> Class<T>.getPublicMethods() =
+ declaredMethods
+ .filter { Modifier.isPublic(it.modifiers) }
+ .map { it.toString().replace(name, "") }
+ .toSet()
+
+ private fun <T> Class<T>.getPublicFields() =
+ fields.filter { Modifier.isPublic(it.modifiers) }.map { it.name }.toSet()
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
index da9ceb4..6ab54a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
@@ -19,7 +19,6 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import com.android.app.animation.Interpolators
@SmallTest
@RunWith(AndroidTestingRunner::class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index f143c467..7b41605 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -376,6 +376,34 @@
}
}
+ @Test
+ public void testHomeControlsDoNotShowIfNotAvailable_featureEnabled() {
+ when(mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)).thenReturn(true);
+
+ final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ stateController.setShouldShowComplications(true);
+
+ final Complication homeControlsComplication = Mockito.mock(Complication.class);
+ when(homeControlsComplication.getRequiredTypeAvailability())
+ .thenReturn(Complication.COMPLICATION_TYPE_HOME_CONTROLS);
+
+ stateController.addComplication(homeControlsComplication);
+
+ final DreamOverlayStateController.Callback callback =
+ Mockito.mock(DreamOverlayStateController.Callback.class);
+
+ stateController.addCallback(callback);
+ mExecutor.runAllReady();
+
+ // No home controls since it is not available.
+ assertThat(stateController.getComplications()).doesNotContain(homeControlsComplication);
+
+ stateController.setAvailableComplicationTypes(Complication.COMPLICATION_TYPE_HOME_CONTROLS
+ | Complication.COMPLICATION_TYPE_WEATHER);
+ mExecutor.runAllReady();
+ assertThat(stateController.getComplications()).contains(homeControlsComplication);
+ }
+
private DreamOverlayStateController getDreamOverlayStateController(boolean overlayEnabled) {
return new DreamOverlayStateController(mExecutor, overlayEnabled, mFeatureFlags);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
index c3b0e5226..d934f76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
@@ -23,9 +23,11 @@
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
@@ -88,6 +90,54 @@
}
@Test
+ public void onViewDetached_removesStatusBarStateListener() {
+ mController.onViewDetached();
+ verify(mStatusBarStateController).removeCallback(mStatusBarStateListener);
+ }
+
+ @Test
+ public void onViewDetached_removesAllScheduledIndications() {
+ // GIVEN show next indication runnable is set
+ final KeyguardIndicationRotateTextViewController.ShowNextIndication mockShowNextIndication =
+ mock(KeyguardIndicationRotateTextViewController.ShowNextIndication.class);
+ mController.mShowNextIndicationRunnable = mockShowNextIndication;
+
+ // WHEN the view is detached
+ mController.onViewDetached();
+
+ // THEN delayed execution is cancelled & runnable set to null
+ verify(mockShowNextIndication).cancelDelayedExecution();
+ assertNull(mController.mShowNextIndicationRunnable);
+ }
+
+ @Test
+ public void destroy_removesStatusBarStateListener() {
+ mController.destroy();
+ verify(mStatusBarStateController).removeCallback(mStatusBarStateListener);
+ }
+
+ @Test
+ public void destroy_removesOnAttachStateChangeListener() {
+ mController.destroy();
+ verify(mView).removeOnAttachStateChangeListener(any());
+ }
+
+ @Test
+ public void destroy_removesAllScheduledIndications() {
+ // GIVEN show next indication runnable is set
+ final KeyguardIndicationRotateTextViewController.ShowNextIndication mockShowNextIndication =
+ mock(KeyguardIndicationRotateTextViewController.ShowNextIndication.class);
+ mController.mShowNextIndicationRunnable = mockShowNextIndication;
+
+ // WHEN the controller is destroyed
+ mController.destroy();
+
+ // THEN delayed execution is cancelled & runnable set to null
+ verify(mockShowNextIndication).cancelDelayedExecution();
+ assertNull(mController.mShowNextIndicationRunnable);
+ }
+
+ @Test
public void testInitialState_noIndication() {
assertFalse(mController.hasIndications());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index a17b596..f4d2843 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -23,9 +23,9 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
-import com.android.app.animation.Interpolators
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.Interpolators
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt
index 3efe382..a5b78b74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.keyguard.ui
import androidx.test.filters.SmallTest
-import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 0ab0e2b..87ca9df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -106,6 +106,7 @@
@Mock private QSSquishinessController mSquishinessController;
@Mock private FooterActionsViewModel mFooterActionsViewModel;
@Mock private FooterActionsViewModel.Factory mFooterActionsViewModelFactory;
+ @Mock private FooterActionsViewBinder mFooterActionsViewBinder;
@Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
@Mock private FeatureFlags mFeatureFlags;
private View mQsFragmentView;
@@ -558,6 +559,7 @@
mock(QSLogger.class),
mock(FooterActionsController.class),
mFooterActionsViewModelFactory,
+ mFooterActionsViewBinder,
mLargeScreenShadeInterpolator,
mFeatureFlags);
}
@@ -584,7 +586,7 @@
when(mQsFragmentView.findViewById(R.id.header)).thenReturn(mHeader);
when(mQsFragmentView.findViewById(android.R.id.edit)).thenReturn(new View(mContext));
when(mQsFragmentView.findViewById(R.id.qs_footer_actions)).thenAnswer(
- invocation -> FooterActionsViewBinder.create(mContext));
+ invocation -> new FooterActionsViewBinder().create(mContext));
}
private void setUpInflater() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
index 59f0d96..2cc6709 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
@@ -376,13 +376,13 @@
@Test
fun isVisible() {
val underTest = utils.footerActionsViewModel()
- assertThat(underTest.isVisible.value).isTrue()
-
- underTest.onVisibilityChangeRequested(visible = false)
assertThat(underTest.isVisible.value).isFalse()
underTest.onVisibilityChangeRequested(visible = true)
assertThat(underTest.isVisible.value).isTrue()
+
+ underTest.onVisibilityChangeRequested(visible = false)
+ assertThat(underTest.isVisible.value).isFalse()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java
index 7d58325..9ea30d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java
@@ -39,9 +39,9 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import org.junit.Before;
import org.junit.Test;
@@ -50,22 +50,20 @@
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
-import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class ActionProxyReceiverTest extends SysuiTestCase {
-
- @Mock
- private CentralSurfaces mMockCentralSurfaces;
@Mock
private ActivityManagerWrapper mMockActivityManagerWrapper;
@Mock
private ScreenshotSmartActions mMockScreenshotSmartActions;
@Mock
private PendingIntent mMockPendingIntent;
+ @Mock
+ private ActivityStarter mActivityStarter;
private Intent mIntent;
private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
@@ -78,32 +76,19 @@
}
@Test
- public void testPendingIntentSentWithoutStatusBar() throws PendingIntent.CanceledException {
- ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(false);
-
- actionProxyReceiver.onReceive(mContext, mIntent);
-
- verify(mMockActivityManagerWrapper).closeSystemWindows(SYSTEM_DIALOG_REASON_SCREENSHOT);
- verify(mMockCentralSurfaces, never()).executeRunnableDismissingKeyguard(
- any(Runnable.class), any(Runnable.class), anyBoolean(), anyBoolean(), anyBoolean());
- verify(mMockPendingIntent).send(
- eq(mContext), anyInt(), isNull(), isNull(), isNull(), isNull(), any(Bundle.class));
- }
-
- @Test
public void testPendingIntentSentWithStatusBar() throws PendingIntent.CanceledException {
- ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(true);
+ ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver();
// ensure that the pending intent call is passed through
doAnswer((Answer<Object>) invocation -> {
((Runnable) invocation.getArgument(0)).run();
return null;
- }).when(mMockCentralSurfaces).executeRunnableDismissingKeyguard(
+ }).when(mActivityStarter).executeRunnableDismissingKeyguard(
any(Runnable.class), isNull(), anyBoolean(), anyBoolean(), anyBoolean());
actionProxyReceiver.onReceive(mContext, mIntent);
verify(mMockActivityManagerWrapper).closeSystemWindows(SYSTEM_DIALOG_REASON_SCREENSHOT);
- verify(mMockCentralSurfaces).executeRunnableDismissingKeyguard(
+ verify(mActivityStarter).executeRunnableDismissingKeyguard(
any(Runnable.class), isNull(), eq(true), eq(true), eq(true));
verify(mMockPendingIntent).send(
eq(mContext), anyInt(), isNull(), isNull(), isNull(), isNull(), any(Bundle.class));
@@ -111,7 +96,7 @@
@Test
public void testSmartActionsNotNotifiedByDefault() {
- ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(true);
+ ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver();
actionProxyReceiver.onReceive(mContext, mIntent);
@@ -122,7 +107,7 @@
@Test
public void testSmartActionsNotifiedIfEnabled() {
- ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(true);
+ ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver();
mIntent.putExtra(EXTRA_SMART_ACTIONS_ENABLED, true);
String testId = "testID";
mIntent.putExtra(EXTRA_ID, testId);
@@ -133,15 +118,12 @@
testId, ACTION_TYPE_SHARE, false, null);
}
- private ActionProxyReceiver constructActionProxyReceiver(boolean withStatusBar) {
- if (withStatusBar) {
- return new ActionProxyReceiver(
- Optional.of(mMockCentralSurfaces), mMockActivityManagerWrapper,
- mMockScreenshotSmartActions, mDisplayTracker);
- } else {
- return new ActionProxyReceiver(
- Optional.empty(), mMockActivityManagerWrapper, mMockScreenshotSmartActions,
- mDisplayTracker);
- }
+ private ActionProxyReceiver constructActionProxyReceiver() {
+ return new ActionProxyReceiver(
+ mMockActivityManagerWrapper,
+ mMockScreenshotSmartActions,
+ mDisplayTracker,
+ mActivityStarter
+ );
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
index 20da8a6..9fe75ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
@@ -33,9 +33,9 @@
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
-import com.android.app.animation.Interpolators
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterViewController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 4438b98..f7fcab1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -325,6 +325,21 @@
}
@Test
+ public void createController_setIndicationAreaAgain_destroysPreviousRotateTextViewController() {
+ // GIVEN a controller with a mocked rotate text view controlller
+ final KeyguardIndicationRotateTextViewController mockedRotateTextViewController =
+ mock(KeyguardIndicationRotateTextViewController.class);
+ createController();
+ mController.mRotateTextViewController = mockedRotateTextViewController;
+
+ // WHEN a new indication area is set
+ mController.setIndicationArea(mIndicationArea);
+
+ // THEN the previous rotateTextViewController is destroyed
+ verify(mockedRotateTextViewController).destroy();
+ }
+
+ @Test
public void createController_addsAlignmentListener() {
createController();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index d017ffd..2106da8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -11,6 +11,7 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.media.controls.ui.MediaHierarchyManager
+import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QS
import com.android.systemui.shade.ShadeViewController
@@ -79,6 +80,7 @@
@Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller
@Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller
@Mock lateinit var qsTransitionController: LockscreenShadeQsTransitionController
+ @Mock lateinit var activityStarter: ActivityStarter
@Mock lateinit var transitionControllerCallback: LockscreenShadeTransitionController.Callback
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -124,6 +126,7 @@
dumpManager)
},
qsTransitionControllerFactory = { qsTransitionController },
+ activityStarter = activityStarter,
)
transitionController.addCallback(transitionControllerCallback)
whenever(nsslController.view).thenReturn(stackscroller)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
index f0abf2f..a1168f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
@@ -32,9 +32,9 @@
import android.view.View;
import android.view.animation.Interpolator;
-import com.android.app.animation.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.AnimationFilter;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ViewState;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 4bb2c87..3cefc99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -67,6 +67,7 @@
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserContextProvider;
@@ -80,7 +81,6 @@
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.wmshell.BubblesManager;
@@ -120,7 +120,6 @@
@Mock private NotificationListContainer mNotificationListContainer;
@Mock private OnSettingsClickListener mOnSettingsClickListener;
@Mock private DeviceProvisionedController mDeviceProvisionedController;
- @Mock private CentralSurfaces mCentralSurfaces;
@Mock private AccessibilityManager mAccessibilityManager;
@Mock private HighPriorityProvider mHighPriorityProvider;
@Mock private INotificationManager mINotificationManager;
@@ -136,6 +135,7 @@
@Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private HeadsUpManagerPhone mHeadsUpManagerPhone;
+ @Mock private ActivityStarter mActivityStarter;
@Before
public void setUp() {
@@ -145,8 +145,8 @@
mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this));
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
- mGutsManager = new NotificationGutsManager(mContext,
- () -> Optional.of(mCentralSurfaces), mHandler, mHandler, mAccessibilityManager,
+ mGutsManager = new NotificationGutsManager(mContext, mHandler, mHandler,
+ mAccessibilityManager,
mHighPriorityProvider, mINotificationManager,
mPeopleSpaceWidgetManager, mLauncherApps, mShortcutManager,
mChannelEditorDialogController, mContextTracker, mAssistantFeedbackController,
@@ -156,7 +156,7 @@
mStatusBarStateController,
mDeviceProvisionedController,
mMetricsLogger,
- mHeadsUpManagerPhone);
+ mHeadsUpManagerPhone, mActivityStarter);
mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,
mOnSettingsClickListener);
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 420c7ae..6a0e3c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -48,6 +48,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -143,6 +144,7 @@
@Mock private NotificationTargetsHelper mNotificationTargetsHelper;
@Mock private SecureSettings mSecureSettings;
@Mock private NotificationIconAreaController mIconAreaController;
+ @Mock private ActivityStarter mActivityStarter;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
@@ -491,7 +493,8 @@
mFeatureFlags,
mNotificationTargetsHelper,
mSecureSettings,
- mock(NotificationDismissibilityProvider.class)
+ mock(NotificationDismissibilityProvider.class),
+ mActivityStarter
);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 7153e59..f771606 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -801,6 +801,34 @@
}
@Test
+ public void onShadeClosesWithAnimationWillResetSwipeState() {
+ // GIVEN shade is expanded
+ mStackScroller.setIsExpanded(true);
+ clearInvocations(mNotificationSwipeHelper);
+
+ // WHEN closing the shade with the animations
+ mStackScroller.onExpansionStarted();
+ mStackScroller.setIsExpanded(false);
+ mStackScroller.onExpansionStopped();
+
+ // VERIFY swipe is reset
+ verify(mNotificationSwipeHelper).resetSwipeState();
+ }
+
+ @Test
+ public void onShadeClosesWithoutAnimationWillResetSwipeState() {
+ // GIVEN shade is expanded
+ mStackScroller.setIsExpanded(true);
+ clearInvocations(mNotificationSwipeHelper);
+
+ // WHEN closing the shade without the animation
+ mStackScroller.setIsExpanded(false);
+
+ // VERIFY swipe is reset
+ verify(mNotificationSwipeHelper).resetSwipeState();
+ }
+
+ @Test
public void testSplitShade_hasTopOverscroll() {
mTestableResources
.addOverride(R.bool.config_use_split_notification_shade, /* value= */ true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
new file mode 100644
index 0000000..b6b28c9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
@@ -0,0 +1,255 @@
+/*
+ * 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.systemui.statusbar.phone
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.os.RemoteException
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.ActivityIntentHelper
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.assist.AssistManager
+import com.android.systemui.keyguard.KeyguardViewMediator
+import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeController
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import dagger.Lazy
+import java.util.Optional
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class ActivityStarterImplTest : SysuiTestCase() {
+ @Mock private lateinit var centralSurfaces: CentralSurfaces
+ @Mock private lateinit var assistManager: AssistManager
+ @Mock private lateinit var dozeServiceHost: DozeServiceHost
+ @Mock private lateinit var biometricUnlockController: BiometricUnlockController
+ @Mock private lateinit var keyguardViewMediator: KeyguardViewMediator
+ @Mock private lateinit var shadeController: ShadeController
+ @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+ @Mock private lateinit var activityLaunchAnimator: ActivityLaunchAnimator
+ @Mock private lateinit var lockScreenUserManager: NotificationLockscreenUserManager
+ @Mock private lateinit var statusBarWindowController: StatusBarWindowController
+ @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
+ @Mock private lateinit var userTracker: UserTracker
+ @Mock private lateinit var activityIntentHelper: ActivityIntentHelper
+ private lateinit var underTest: ActivityStarterImpl
+ private val mainExecutor = FakeExecutor(FakeSystemClock())
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ underTest =
+ ActivityStarterImpl(
+ Lazy { Optional.of(centralSurfaces) },
+ Lazy { assistManager },
+ Lazy { dozeServiceHost },
+ Lazy { biometricUnlockController },
+ Lazy { keyguardViewMediator },
+ Lazy { shadeController },
+ Lazy { statusBarKeyguardViewManager },
+ activityLaunchAnimator,
+ context,
+ lockScreenUserManager,
+ statusBarWindowController,
+ wakefulnessLifecycle,
+ keyguardStateController,
+ statusBarStateController,
+ keyguardUpdateMonitor,
+ deviceProvisionedController,
+ userTracker,
+ activityIntentHelper,
+ mainExecutor,
+ )
+ }
+
+ @Test
+ fun startPendingIntentDismissingKeyguard_keyguardShowing_dismissWithAction() {
+ val pendingIntent = mock(PendingIntent::class.java)
+ whenever(keyguardStateController.isShowing).thenReturn(true)
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+
+ underTest.startPendingIntentDismissingKeyguard(pendingIntent)
+
+ verify(statusBarKeyguardViewManager)
+ .dismissWithAction(any(OnDismissAction::class.java), eq(null), anyBoolean(), eq(null))
+ }
+
+ @Test
+ fun startPendingIntentDismissingKeyguard_associatedView_getAnimatorController() {
+ val pendingIntent = mock(PendingIntent::class.java)
+ val associatedView = mock(ExpandableNotificationRow::class.java)
+
+ underTest.startPendingIntentDismissingKeyguard(
+ intent = pendingIntent,
+ intentSentUiThreadCallback = null,
+ associatedView = associatedView,
+ )
+
+ verify(centralSurfaces).getAnimatorControllerFromNotification(associatedView)
+ }
+
+ @Test
+ fun startActivity_noUserHandleProvided_getUserHandle() {
+ val intent = mock(Intent::class.java)
+
+ underTest.startActivity(intent, false)
+
+ verify(userTracker).userHandle
+ }
+
+ @Test
+ fun postStartActivityDismissingKeyguard_pendingIntent_postsOnMain() {
+ val intent = mock(PendingIntent::class.java)
+
+ underTest.postStartActivityDismissingKeyguard(intent)
+
+ assertThat(mainExecutor.numPending()).isEqualTo(1)
+ }
+
+ @Test
+ fun postStartActivityDismissingKeyguard_intent_postsOnMain() {
+ val intent = mock(Intent::class.java)
+
+ underTest.postStartActivityDismissingKeyguard(intent, 0)
+
+ assertThat(mainExecutor.numPending()).isEqualTo(1)
+ }
+
+ @Test
+ fun dismissKeyguardThenExecute_startWakeAndUnlock() {
+ whenever(wakefulnessLifecycle.wakefulness)
+ .thenReturn(WakefulnessLifecycle.WAKEFULNESS_ASLEEP)
+ whenever(keyguardStateController.canDismissLockScreen()).thenReturn(true)
+ whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false)
+ whenever(dozeServiceHost.isPulsing).thenReturn(true)
+
+ underTest.dismissKeyguardThenExecute({ true }, {}, false)
+
+ verify(biometricUnlockController)
+ .startWakeAndUnlock(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING)
+ }
+
+ @Test
+ fun dismissKeyguardThenExecute_keyguardIsShowing_dismissWithAction() {
+ val customMessage = "Enter your pin."
+ whenever(keyguardStateController.isShowing).thenReturn(true)
+
+ underTest.dismissKeyguardThenExecute({ true }, {}, false, customMessage)
+
+ verify(statusBarKeyguardViewManager)
+ .dismissWithAction(
+ any(OnDismissAction::class.java),
+ any(Runnable::class.java),
+ eq(false),
+ eq(customMessage)
+ )
+ }
+
+ @Test
+ fun dismissKeyguardThenExecute_awakeDreams() {
+ val customMessage = "Enter your pin."
+ var dismissActionExecuted = false
+ whenever(keyguardStateController.isShowing).thenReturn(false)
+ whenever(keyguardUpdateMonitor.isDreaming).thenReturn(true)
+
+ underTest.dismissKeyguardThenExecute(
+ {
+ dismissActionExecuted = true
+ true
+ },
+ {},
+ false,
+ customMessage
+ )
+
+ verify(centralSurfaces).awakenDreams()
+ assertThat(dismissActionExecuted).isTrue()
+ }
+
+ @Test
+ @Throws(RemoteException::class)
+ fun executeRunnableDismissingKeyguard_dreaming_notShowing_awakenDreams() {
+ whenever(keyguardStateController.isShowing).thenReturn(false)
+ whenever(keyguardStateController.isOccluded).thenReturn(false)
+ whenever(keyguardUpdateMonitor.isDreaming).thenReturn(true)
+
+ underTest.executeRunnableDismissingKeyguard(
+ runnable = {},
+ cancelAction = null,
+ dismissShade = false,
+ afterKeyguardGone = false,
+ deferred = false
+ )
+
+ verify(centralSurfaces, times(1)).awakenDreams()
+ }
+
+ @Test
+ @Throws(RemoteException::class)
+ fun executeRunnableDismissingKeyguard_notDreaming_notShowing_doNotAwakenDreams() {
+ whenever(keyguardStateController.isShowing).thenReturn(false)
+ whenever(keyguardStateController.isOccluded).thenReturn(false)
+ whenever(keyguardUpdateMonitor.isDreaming).thenReturn(false)
+
+ underTest.executeRunnableDismissingKeyguard(
+ runnable = {},
+ cancelAction = null,
+ dismissShade = false,
+ afterKeyguardGone = false,
+ deferred = false
+ )
+
+ verify(centralSurfaces, never()).awakenDreams()
+ }
+
+ @Test
+ fun postQSRunnableDismissingKeyguard_leaveOpenStatusBarState() {
+ underTest.postQSRunnableDismissingKeyguard {}
+
+ assertThat(mainExecutor.numPending()).isEqualTo(1)
+ mainExecutor.runAllReady()
+ verify(statusBarStateController).setLeaveOpenOnKeyguardHide(true)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index 872c560..3870d99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -43,6 +43,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSHost;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.CameraLauncher;
@@ -96,6 +97,7 @@
@Mock private Lazy<CameraLauncher> mCameraLauncherLazy;
@Mock private UserTracker mUserTracker;
@Mock private QSHost mQSHost;
+ @Mock private ActivityStarter mActivityStarter;
CentralSurfacesCommandQueueCallbacks mSbcqCallbacks;
@@ -131,7 +133,8 @@
mSystemBarAttributesListener,
mCameraLauncherLazy,
mUserTracker,
- mQSHost);
+ mQSHost,
+ mActivityStarter);
when(mUserTracker.getUserHandle()).thenReturn(
UserHandle.of(ActivityManager.getCurrentUser()));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 4ff225c..6be0e2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -72,6 +72,7 @@
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.TaskbarDelegate;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.ShadeController;
@@ -129,6 +130,7 @@
@Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private UdfpsOverlayInteractor mUdfpsOverlayInteractor;
+ @Mock private ActivityStarter mActivityStarter;
@Mock private BouncerView mBouncerView;
@Mock private BouncerViewDelegate mBouncerViewDelegate;
@Mock private OnBackAnimationCallback mBouncerViewDelegateBackCallback;
@@ -192,7 +194,8 @@
mPrimaryBouncerInteractor,
mBouncerView,
mAlternateBouncerInteractor,
- mUdfpsOverlayInteractor) {
+ mUdfpsOverlayInteractor,
+ mActivityStarter) {
@Override
public ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
@@ -680,7 +683,8 @@
mPrimaryBouncerInteractor,
mBouncerView,
mAlternateBouncerInteractor,
- mUdfpsOverlayInteractor) {
+ mUdfpsOverlayInteractor,
+ mActivityStarter) {
@Override
public ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt
index 0983041..5b431e7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt
@@ -14,8 +14,6 @@
package com.android.systemui.animation
-import com.android.app.animation.Interpolators
-
/** A [LaunchAnimator] to be used in tests. */
fun fakeLaunchAnimator(): LaunchAnimator {
return LaunchAnimator(TEST_TIMINGS, TEST_INTERPOLATORS)
diff --git a/services/core/java/com/android/server/SoundTriggerInternal.java b/services/core/java/com/android/server/SoundTriggerInternal.java
index e6c1750..f184574 100644
--- a/services/core/java/com/android/server/SoundTriggerInternal.java
+++ b/services/core/java/com/android/server/SoundTriggerInternal.java
@@ -52,11 +52,6 @@
// Enumerate possible STModules to attach to
List<ModuleProperties> listModuleProperties(Identity originatorIdentity);
- /**
- * Dumps service-wide information.
- */
- void dump(FileDescriptor fd, PrintWriter pw, String[] args);
-
interface Session {
/**
* Starts recognition for the given keyphraseId.
@@ -142,13 +137,14 @@
@ModelParams int modelParam);
/**
+ * Invalidates the sound trigger session and clears any associated resources. Subsequent
+ * calls to this object will throw IllegalStateException.
+ */
+ void detach();
+
+ /**
* Unloads (and stops if running) the given keyphraseId
*/
int unloadKeyphraseModel(int keyphaseId);
-
- /**
- * Dumps session-wide information.
- */
- void dump(FileDescriptor fd, PrintWriter pw, String[] args);
}
}
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index a57dd40..7cdea8d 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -87,10 +87,11 @@
private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
private static final int MSG_CONFIGURE_SAFE_MEDIA = SAFE_MEDIA_VOLUME_MSG_START + 1;
- private static final int MSG_PERSIST_SAFE_VOLUME_STATE = SAFE_MEDIA_VOLUME_MSG_START + 2;
- private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = SAFE_MEDIA_VOLUME_MSG_START + 3;
- private static final int MSG_PERSIST_CSD_VALUES = SAFE_MEDIA_VOLUME_MSG_START + 4;
- /*package*/ static final int MSG_CSD_UPDATE_ATTENUATION = SAFE_MEDIA_VOLUME_MSG_START + 5;
+ private static final int MSG_CONFIGURE_SAFE_MEDIA_FORCED = SAFE_MEDIA_VOLUME_MSG_START + 2;
+ private static final int MSG_PERSIST_SAFE_VOLUME_STATE = SAFE_MEDIA_VOLUME_MSG_START + 3;
+ private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = SAFE_MEDIA_VOLUME_MSG_START + 4;
+ private static final int MSG_PERSIST_CSD_VALUES = SAFE_MEDIA_VOLUME_MSG_START + 5;
+ /*package*/ static final int MSG_CSD_UPDATE_ATTENUATION = SAFE_MEDIA_VOLUME_MSG_START + 6;
private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
@@ -611,8 +612,7 @@
}
/*package*/ void configureSafeMedia(boolean forced, String caller) {
- int msg = MSG_CONFIGURE_SAFE_MEDIA;
-
+ int msg = forced ? MSG_CONFIGURE_SAFE_MEDIA_FORCED : MSG_CONFIGURE_SAFE_MEDIA;
mAudioHandler.removeMessages(msg);
long time = 0;
@@ -622,7 +622,7 @@
}
mAudioHandler.sendMessageAtTime(
- mAudioHandler.obtainMessage(msg, /*arg1=*/forced ? 1 : 0, /*arg2=*/0, caller),
+ mAudioHandler.obtainMessage(msg, /*arg1=*/0, /*arg2=*/0, caller),
time);
}
@@ -664,8 +664,10 @@
/*package*/ void handleMessage(Message msg) {
switch (msg.what) {
+ case MSG_CONFIGURE_SAFE_MEDIA_FORCED:
case MSG_CONFIGURE_SAFE_MEDIA:
- onConfigureSafeMedia((msg.arg1 == 1), (String) msg.obj);
+ onConfigureSafeMedia((msg.what == MSG_CONFIGURE_SAFE_MEDIA_FORCED),
+ (String) msg.obj);
break;
case MSG_PERSIST_SAFE_VOLUME_STATE:
onPersistSafeVolumeState(msg.arg1);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index dab00d8..0b6d1c8 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -181,6 +181,19 @@
*/
private String mThermalBrightnessThrottlingDataId;
+ /**
+ * Refresh rate range limitation based on the current device layout
+ */
+ @Nullable
+ private SurfaceControl.RefreshRateRange mLayoutLimitedRefreshRate;
+
+ /**
+ * RefreshRateRange limitation for @Temperature.ThrottlingStatus
+ */
+ @NonNull
+ private SparseArray<SurfaceControl.RefreshRateRange> mThermalRefreshRateThrottling =
+ new SparseArray<>();
+
public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
mDisplayId = displayId;
mLayerStack = layerStack;
@@ -339,24 +352,24 @@
*/
public void updateLayoutLimitedRefreshRateLocked(
@Nullable SurfaceControl.RefreshRateRange layoutLimitedRefreshRate) {
- if (!Objects.equals(layoutLimitedRefreshRate, mBaseDisplayInfo.layoutLimitedRefreshRate)) {
- mBaseDisplayInfo.layoutLimitedRefreshRate = layoutLimitedRefreshRate;
- mInfo.set(null);
+ if (!Objects.equals(layoutLimitedRefreshRate, mLayoutLimitedRefreshRate)) {
+ mLayoutLimitedRefreshRate = layoutLimitedRefreshRate;
+ mDirty = true;
}
}
/**
- * Updates refreshRateThermalThrottling
+ * Updates thermalRefreshRateThrottling
*
- * @param refreshRanges new refreshRateThermalThrottling ranges limited by layout or default
+ * @param refreshRanges new thermalRefreshRateThrottling ranges limited by layout or default
*/
public void updateThermalRefreshRateThrottling(
@Nullable SparseArray<SurfaceControl.RefreshRateRange> refreshRanges) {
if (refreshRanges == null) {
refreshRanges = new SparseArray<>();
}
- if (!mBaseDisplayInfo.refreshRateThermalThrottling.contentEquals(refreshRanges)) {
- mBaseDisplayInfo.refreshRateThermalThrottling = refreshRanges;
- mInfo.set(null);
+ if (!mThermalRefreshRateThrottling.contentEquals(refreshRanges)) {
+ mThermalRefreshRateThrottling = refreshRanges;
+ mDirty = true;
}
}
@@ -499,6 +512,9 @@
mBaseDisplayInfo.removeMode = Display.REMOVE_MODE_DESTROY_CONTENT;
}
+ mBaseDisplayInfo.layoutLimitedRefreshRate = mLayoutLimitedRefreshRate;
+ mBaseDisplayInfo.thermalRefreshRateThrottling = mThermalRefreshRateThrottling;
+
mPrimaryDisplayDeviceInfo = deviceInfo;
mInfo.set(null);
mDirty = false;
@@ -952,6 +968,8 @@
pw.println("mDisplayGroupName=" + mDisplayGroupName);
pw.println("mThermalBrightnessThrottlingDataId=" + mThermalBrightnessThrottlingDataId);
pw.println("mLeadDisplayId=" + mLeadDisplayId);
+ pw.println("mLayoutLimitedRefreshRate=" + mLayoutLimitedRefreshRate);
+ pw.println("mThermalRefreshRateThrottling=" + mThermalRefreshRateThrottling);
}
@Override
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 03b49f0..fd94be9 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -103,10 +103,6 @@
private static final int MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED = 7;
private static final int MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED = 8;
- // Special ID used to indicate that given vote is to be applied globally, rather than to a
- // specific display.
- private static final int GLOBAL_ID = -1;
-
private static final float FLOAT_TOLERANCE = RefreshRateRange.FLOAT_TOLERANCE;
private final Object mLock = new Object();
@@ -129,10 +125,6 @@
@Nullable
private DisplayDeviceConfig mDefaultDisplayDeviceConfig;
- // A map from the display ID to the collection of votes and their priority. The latter takes
- // the form of another map from the priority to the vote itself so that each priority is
- // guaranteed to have exactly one vote, which is also easily and efficiently replaceable.
- private SparseArray<SparseArray<Vote>> mVotesByDisplay;
// A map from the display ID to the supported modes on that display.
private SparseArray<Display.Mode[]> mSupportedModesByDisplay;
// A map from the display ID to the default mode of that display.
@@ -146,6 +138,8 @@
private final boolean mSupportsFrameRateOverride;
+ private final VotesStorage mVotesStorage;
+
/**
* The allowed refresh rate switching type. This is used by SurfaceFlinger.
*/
@@ -161,7 +155,6 @@
mContext = context;
mHandler = new DisplayModeDirectorHandler(handler.getLooper());
mInjector = injector;
- mVotesByDisplay = new SparseArray<>();
mSupportedModesByDisplay = new SparseArray<>();
mDefaultModeByDisplay = new SparseArray<>();
mAppRequestObserver = new AppRequestObserver();
@@ -171,15 +164,11 @@
mBrightnessObserver = new BrightnessObserver(context, handler, injector);
mDefaultDisplayDeviceConfig = null;
mUdfpsObserver = new UdfpsObserver();
- final BallotBox ballotBox = (displayId, priority, vote) -> {
- synchronized (mLock) {
- updateVoteLocked(displayId, priority, vote);
- }
- };
- mDisplayObserver = new DisplayObserver(context, handler, ballotBox);
- mSensorObserver = new SensorObserver(context, ballotBox, injector);
- mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox);
- mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler(),
+ mVotesStorage = new VotesStorage(this::notifyDesiredDisplayModeSpecsChangedLocked);
+ mDisplayObserver = new DisplayObserver(context, handler, mVotesStorage);
+ mSensorObserver = new SensorObserver(context, mVotesStorage, injector);
+ mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, mVotesStorage);
+ mHbmObserver = new HbmObserver(injector, mVotesStorage, BackgroundThread.getHandler(),
mDeviceConfigDisplaySettings);
mAlwaysRespectAppRequest = false;
mSupportsFrameRateOverride = injector.supportsFrameRateOverride();
@@ -226,29 +215,7 @@
mLoggingEnabled = loggingEnabled;
mBrightnessObserver.setLoggingEnabled(loggingEnabled);
mSkinThermalStatusObserver.setLoggingEnabled(loggingEnabled);
- }
-
- @NonNull
- private SparseArray<Vote> getVotesLocked(int displayId) {
- SparseArray<Vote> displayVotes = mVotesByDisplay.get(displayId);
- final SparseArray<Vote> votes;
- if (displayVotes != null) {
- votes = displayVotes.clone();
- } else {
- votes = new SparseArray<>();
- }
-
- SparseArray<Vote> globalVotes = mVotesByDisplay.get(GLOBAL_ID);
- if (globalVotes != null) {
- for (int i = 0; i < globalVotes.size(); i++) {
- int priority = globalVotes.keyAt(i);
- if (votes.indexOfKey(priority) < 0) {
- votes.put(priority, globalVotes.valueAt(i));
- }
- }
- }
-
- return votes;
+ mVotesStorage.setLoggingEnabled(loggingEnabled);
}
private static final class VoteSummary {
@@ -407,7 +374,7 @@
@NonNull
public DesiredDisplayModeSpecs getDesiredDisplayModeSpecs(int displayId) {
synchronized (mLock) {
- SparseArray<Vote> votes = getVotesLocked(displayId);
+ SparseArray<Vote> votes = mVotesStorage.getVotes(displayId);
Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId);
if (modes == null || defaultMode == null) {
@@ -780,10 +747,8 @@
@VisibleForTesting
@Nullable
Vote getVote(int displayId, int priority) {
- synchronized (mLock) {
- SparseArray<Vote> votes = getVotesLocked(displayId);
- return votes.get(priority);
- }
+ SparseArray<Vote> votes = mVotesStorage.getVotes(displayId);
+ return votes.get(priority);
}
/**
@@ -806,18 +771,6 @@
final Display.Mode mode = mDefaultModeByDisplay.valueAt(i);
pw.println(" " + id + " -> " + mode);
}
- pw.println(" mVotesByDisplay:");
- for (int i = 0; i < mVotesByDisplay.size(); i++) {
- pw.println(" " + mVotesByDisplay.keyAt(i) + ":");
- SparseArray<Vote> votes = mVotesByDisplay.valueAt(i);
- for (int p = Vote.MAX_PRIORITY; p >= Vote.MIN_PRIORITY; p--) {
- Vote vote = votes.get(p);
- if (vote == null) {
- continue;
- }
- pw.println(" " + Vote.priorityToString(p) + " -> " + vote);
- }
- }
pw.println(" mModeSwitchingType: " + switchingTypeToString(mModeSwitchingType));
pw.println(" mAlwaysRespectAppRequest: " + mAlwaysRespectAppRequest);
mSettingsObserver.dumpLocked(pw);
@@ -827,44 +780,10 @@
mHbmObserver.dumpLocked(pw);
mSkinThermalStatusObserver.dumpLocked(pw);
}
-
+ mVotesStorage.dump(pw);
mSensorObserver.dump(pw);
}
- private void updateVoteLocked(int priority, Vote vote) {
- updateVoteLocked(GLOBAL_ID, priority, vote);
- }
-
- private void updateVoteLocked(int displayId, int priority, Vote vote) {
- if (mLoggingEnabled) {
- Slog.i(TAG, "updateVoteLocked(displayId=" + displayId
- + ", priority=" + Vote.priorityToString(priority)
- + ", vote=" + vote + ")");
- }
- if (priority < Vote.MIN_PRIORITY || priority > Vote.MAX_PRIORITY) {
- Slog.w(TAG, "Received a vote with an invalid priority, ignoring:"
- + " priority=" + Vote.priorityToString(priority)
- + ", vote=" + vote, new Throwable());
- return;
- }
- final SparseArray<Vote> votes = getOrCreateVotesByDisplay(displayId);
-
- if (vote != null) {
- votes.put(priority, vote);
- } else {
- votes.remove(priority);
- }
-
- if (votes.size() == 0) {
- if (mLoggingEnabled) {
- Slog.i(TAG, "No votes left for display " + displayId + ", removing.");
- }
- mVotesByDisplay.remove(displayId);
- }
-
- notifyDesiredDisplayModeSpecsChangedLocked();
- }
-
@GuardedBy("mLock")
private float getMaxRefreshRateLocked(int displayId) {
Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
@@ -890,16 +809,6 @@
}
}
- private SparseArray<Vote> getOrCreateVotesByDisplay(int displayId) {
- if (mVotesByDisplay.indexOfKey(displayId) >= 0) {
- return mVotesByDisplay.get(displayId);
- } else {
- SparseArray<Vote> votes = new SparseArray<>();
- mVotesByDisplay.put(displayId, votes);
- return votes;
- }
- }
-
private static String switchingTypeToString(@DisplayManager.SwitchingType int type) {
switch (type) {
case DisplayManager.SWITCHING_TYPE_NONE:
@@ -927,7 +836,7 @@
@VisibleForTesting
void injectVotesByDisplay(SparseArray<SparseArray<Vote>> votesByDisplay) {
- mVotesByDisplay = votesByDisplay;
+ mVotesStorage.injectVotesByDisplay(votesByDisplay);
}
@VisibleForTesting
@@ -1157,225 +1066,6 @@
}
@VisibleForTesting
- static final class Vote {
- // DEFAULT_RENDER_FRAME_RATE votes for render frame rate [0, DEFAULT]. As the lowest
- // priority vote, it's overridden by all other considerations. It acts to set a default
- // frame rate for a device.
- public static final int PRIORITY_DEFAULT_RENDER_FRAME_RATE = 0;
-
- // PRIORITY_FLICKER_REFRESH_RATE votes for a single refresh rate like [60,60], [90,90] or
- // null. It is used to set a preferred refresh rate value in case the higher priority votes
- // result is a range.
- public static final int PRIORITY_FLICKER_REFRESH_RATE = 1;
-
- // High-brightness-mode may need a specific range of refresh-rates to function properly.
- public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 2;
-
- // SETTING_MIN_RENDER_FRAME_RATE is used to propose a lower bound of the render frame rate.
- // It votes [minRefreshRate, Float.POSITIVE_INFINITY]
- public static final int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3;
-
- // APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render
- // frame rate in certain cases, mostly to preserve power.
- // @see android.view.WindowManager.LayoutParams#preferredMinRefreshRate
- // @see android.view.WindowManager.LayoutParams#preferredMaxRefreshRate
- // It votes to [preferredMinRefreshRate, preferredMaxRefreshRate].
- public static final int PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE = 4;
-
- // We split the app request into different priorities in case we can satisfy one desire
- // without the other.
-
- // Application can specify preferred refresh rate with below attrs.
- // @see android.view.WindowManager.LayoutParams#preferredRefreshRate
- // @see android.view.WindowManager.LayoutParams#preferredDisplayModeId
- //
- // When the app specifies a LayoutParams#preferredDisplayModeId, in addition to the
- // refresh rate, it also chooses a preferred size (resolution) as part of the selected
- // mode id. The app preference is then translated to APP_REQUEST_BASE_MODE_REFRESH_RATE and
- // optionally to APP_REQUEST_SIZE as well, if a mode id was selected.
- // The system also forces some apps like denylisted app to run at a lower refresh rate.
- // @see android.R.array#config_highRefreshRateBlacklist
- //
- // When summarizing the votes and filtering the allowed display modes, these votes determine
- // which mode id should be the base mode id to be sent to SurfaceFlinger:
- // - APP_REQUEST_BASE_MODE_REFRESH_RATE is used to validate the vote summary. If a summary
- // includes a base mode refresh rate, but it is not in the refresh rate range, then the
- // summary is considered invalid so we could drop a lower priority vote and try again.
- // - APP_REQUEST_SIZE is used to filter out display modes of a different size.
- //
- // The preferred refresh rate is set on the main surface of the app outside of
- // DisplayModeDirector.
- // @see com.android.server.wm.WindowState#updateFrameRateSelectionPriorityIfNeeded
- public static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 5;
- public static final int PRIORITY_APP_REQUEST_SIZE = 6;
-
- // SETTING_PEAK_RENDER_FRAME_RATE has a high priority and will restrict the bounds of the
- // rest of low priority voters. It votes [0, max(PEAK, MIN)]
- public static final int PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE = 7;
-
- // To avoid delay in switching between 60HZ -> 90HZ when activating LHBM, set refresh
- // rate to max value (same as for PRIORITY_UDFPS) on lock screen
- public static final int PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE = 8;
-
- // For concurrent displays we want to limit refresh rate on all displays
- public static final int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 9;
-
- // LOW_POWER_MODE force the render frame rate to [0, 60HZ] if
- // Settings.Global.LOW_POWER_MODE is on.
- public static final int PRIORITY_LOW_POWER_MODE = 10;
-
- // PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the
- // higher priority voters' result is a range, it will fix the rate to a single choice.
- // It's used to avoid refresh rate switches in certain conditions which may result in the
- // user seeing the display flickering when the switches occur.
- public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 11;
-
- // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
- public static final int PRIORITY_SKIN_TEMPERATURE = 12;
-
- // The proximity sensor needs the refresh rate to be locked in order to function, so this is
- // set to a high priority.
- public static final int PRIORITY_PROXIMITY = 13;
-
- // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
- // to function, so this needs to be the highest priority of all votes.
- public static final int PRIORITY_UDFPS = 14;
-
- // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
- // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
-
- public static final int MIN_PRIORITY = PRIORITY_DEFAULT_RENDER_FRAME_RATE;
- public static final int MAX_PRIORITY = PRIORITY_UDFPS;
-
- // The cutoff for the app request refresh rate range. Votes with priorities lower than this
- // value will not be considered when constructing the app request refresh rate range.
- public static final int APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF =
- PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE;
-
- /**
- * A value signifying an invalid width or height in a vote.
- */
- public static final int INVALID_SIZE = -1;
-
- /**
- * The requested width of the display in pixels, or INVALID_SIZE;
- */
- public final int width;
- /**
- * The requested height of the display in pixels, or INVALID_SIZE;
- */
- public final int height;
- /**
- * Information about the refresh rate frame rate ranges DM would like to set the display to.
- */
- public final RefreshRateRanges refreshRateRanges;
-
- /**
- * Whether refresh rate switching should be disabled (i.e. the refresh rate range is
- * a single value).
- */
- public final boolean disableRefreshRateSwitching;
-
- /**
- * The preferred refresh rate selected by the app. It is used to validate that the summary
- * refresh rate ranges include this value, and are not restricted by a lower priority vote.
- */
- public final float appRequestBaseModeRefreshRate;
-
- public static Vote forPhysicalRefreshRates(float minRefreshRate, float maxRefreshRate) {
- return new Vote(INVALID_SIZE, INVALID_SIZE, minRefreshRate, maxRefreshRate, 0,
- Float.POSITIVE_INFINITY,
- minRefreshRate == maxRefreshRate, 0f);
- }
-
- public static Vote forRenderFrameRates(float minFrameRate, float maxFrameRate) {
- return new Vote(INVALID_SIZE, INVALID_SIZE, 0, Float.POSITIVE_INFINITY, minFrameRate,
- maxFrameRate,
- false, 0f);
- }
-
- public static Vote forSize(int width, int height) {
- return new Vote(width, height, 0, Float.POSITIVE_INFINITY, 0, Float.POSITIVE_INFINITY,
- false,
- 0f);
- }
-
- public static Vote forDisableRefreshRateSwitching() {
- return new Vote(INVALID_SIZE, INVALID_SIZE, 0, Float.POSITIVE_INFINITY, 0,
- Float.POSITIVE_INFINITY, true,
- 0f);
- }
-
- public static Vote forBaseModeRefreshRate(float baseModeRefreshRate) {
- return new Vote(INVALID_SIZE, INVALID_SIZE, 0, Float.POSITIVE_INFINITY, 0,
- Float.POSITIVE_INFINITY, false,
- baseModeRefreshRate);
- }
-
- private Vote(int width, int height,
- float minPhysicalRefreshRate,
- float maxPhysicalRefreshRate,
- float minRenderFrameRate,
- float maxRenderFrameRate,
- boolean disableRefreshRateSwitching,
- float baseModeRefreshRate) {
- this.width = width;
- this.height = height;
- this.refreshRateRanges = new RefreshRateRanges(
- new RefreshRateRange(minPhysicalRefreshRate, maxPhysicalRefreshRate),
- new RefreshRateRange(minRenderFrameRate, maxRenderFrameRate));
- this.disableRefreshRateSwitching = disableRefreshRateSwitching;
- this.appRequestBaseModeRefreshRate = baseModeRefreshRate;
- }
-
- public static String priorityToString(int priority) {
- switch (priority) {
- case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE:
- return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE";
- case PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE:
- return "PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE";
- case PRIORITY_APP_REQUEST_SIZE:
- return "PRIORITY_APP_REQUEST_SIZE";
- case PRIORITY_DEFAULT_RENDER_FRAME_RATE:
- return "PRIORITY_DEFAULT_REFRESH_RATE";
- case PRIORITY_FLICKER_REFRESH_RATE:
- return "PRIORITY_FLICKER_REFRESH_RATE";
- case PRIORITY_FLICKER_REFRESH_RATE_SWITCH:
- return "PRIORITY_FLICKER_REFRESH_RATE_SWITCH";
- case PRIORITY_HIGH_BRIGHTNESS_MODE:
- return "PRIORITY_HIGH_BRIGHTNESS_MODE";
- case PRIORITY_PROXIMITY:
- return "PRIORITY_PROXIMITY";
- case PRIORITY_LOW_POWER_MODE:
- return "PRIORITY_LOW_POWER_MODE";
- case PRIORITY_SKIN_TEMPERATURE:
- return "PRIORITY_SKIN_TEMPERATURE";
- case PRIORITY_UDFPS:
- return "PRIORITY_UDFPS";
- case PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE:
- return "PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE";
- case PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE:
- return "PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE";
- case PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE:
- return "PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE";
- case PRIORITY_LAYOUT_LIMITED_FRAME_RATE:
- return "PRIORITY_LAYOUT_LIMITED_FRAME_RATE";
- default:
- return Integer.toString(priority);
- }
- }
-
- @Override
- public String toString() {
- return "Vote{"
- + "width=" + width + ", height=" + height
- + ", refreshRateRanges=" + refreshRateRanges
- + ", disableRefreshRateSwitching=" + disableRefreshRateSwitching
- + ", appRequestBaseModeRefreshRate=" + appRequestBaseModeRefreshRate + "}";
- }
- }
-
- @VisibleForTesting
final class SettingsObserver extends ContentObserver {
private final Uri mSmoothDisplaySetting =
Settings.System.getUriFor(Settings.System.SMOOTH_DISPLAY);
@@ -1510,7 +1200,7 @@
} else {
vote = null;
}
- updateVoteLocked(Vote.PRIORITY_LOW_POWER_MODE, vote);
+ mVotesStorage.updateGlobalVote(Vote.PRIORITY_LOW_POWER_MODE, vote);
mBrightnessObserver.onLowPowerModeEnabledLocked(inLowPowerMode);
}
@@ -1529,13 +1219,14 @@
Vote peakVote = peakRefreshRate == 0f
? null
: Vote.forRenderFrameRates(0f, Math.max(minRefreshRate, peakRefreshRate));
- updateVoteLocked(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, peakVote);
- updateVoteLocked(Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
+ mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
+ peakVote);
+ mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
Vote.forRenderFrameRates(minRefreshRate, Float.POSITIVE_INFINITY));
Vote defaultVote =
defaultRefreshRate == 0f
? null : Vote.forRenderFrameRates(0f, defaultRefreshRate);
- updateVoteLocked(Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE, defaultVote);
+ mVotesStorage.updateGlobalVote(Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE, defaultVote);
float maxRefreshRate;
if (peakRefreshRate == 0f && defaultRefreshRate == 0f) {
@@ -1619,9 +1310,9 @@
sizeVote = null;
}
- updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
baseModeRefreshRateVote);
- updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote);
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote);
}
private void setAppPreferredRefreshRateRangeLocked(int displayId,
@@ -1652,11 +1343,8 @@
mAppPreferredRefreshRateRangeByDisplay.remove(displayId);
vote = null;
}
- synchronized (mLock) {
- updateVoteLocked(displayId,
- Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE,
- vote);
- }
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE,
+ vote);
}
private Display.Mode findModeByIdLocked(int displayId, int modeId) {
@@ -1696,23 +1384,22 @@
// calling into us already holding its own lock.
private final Context mContext;
private final Handler mHandler;
- private final BallotBox mBallotBox;
+ private final VotesStorage mVotesStorage;
- DisplayObserver(Context context, Handler handler, BallotBox ballotBox) {
+ DisplayObserver(Context context, Handler handler, VotesStorage votesStorage) {
mContext = context;
mHandler = handler;
- mBallotBox = ballotBox;
+ mVotesStorage = votesStorage;
}
public void observe() {
- DisplayManager dm = mContext.getSystemService(DisplayManager.class);
- dm.registerDisplayListener(this, mHandler);
+ mInjector.registerDisplayListener(this, mHandler);
// Populate existing displays
SparseArray<Display.Mode[]> modes = new SparseArray<>();
SparseArray<Display.Mode> defaultModes = new SparseArray<>();
DisplayInfo info = new DisplayInfo();
- Display[] displays = dm.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
+ Display[] displays = mInjector.getDisplays();
for (Display d : displays) {
final int displayId = d.getDisplayId();
d.getDisplayInfo(info);
@@ -1753,23 +1440,16 @@
@Nullable
private DisplayInfo getDisplayInfo(int displayId) {
- Display d = mContext.getSystemService(DisplayManager.class).getDisplay(displayId);
- if (d == null) {
- // We can occasionally get a display added or changed event for a display that was
- // subsequently removed, which means this returns null. Check this case and bail
- // out early; if it gets re-attached we'll eventually get another call back for it.
- return null;
- }
DisplayInfo info = new DisplayInfo();
- d.getDisplayInfo(info);
- return info;
+ // Display info might be invalid, in this case return null
+ return mInjector.getDisplayInfo(displayId, info) ? info : null;
}
private void updateLayoutLimitedFrameRate(int displayId, @Nullable DisplayInfo info) {
Vote vote = info != null && info.layoutLimitedRefreshRate != null
? Vote.forPhysicalRefreshRates(info.layoutLimitedRefreshRate.min,
info.layoutLimitedRefreshRate.max) : null;
- mBallotBox.vote(displayId, Vote.PRIORITY_LAYOUT_LIMITED_FRAME_RATE, vote);
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_LAYOUT_LIMITED_FRAME_RATE, vote);
}
private void updateDisplayModes(int displayId, @Nullable DisplayInfo info) {
@@ -2091,8 +1771,8 @@
updateSensorStatus();
if (!changeable) {
// Revoke previous vote from BrightnessObserver
- updateVoteLocked(Vote.PRIORITY_FLICKER_REFRESH_RATE, null);
- updateVoteLocked(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, null);
+ mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE, null);
+ mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, null);
}
}
}
@@ -2417,8 +2097,9 @@
Slog.d(TAG, "Display brightness " + mBrightness + ", ambient lux " + mAmbientLux
+ ", Vote " + refreshRateVote);
}
- updateVoteLocked(Vote.PRIORITY_FLICKER_REFRESH_RATE, refreshRateVote);
- updateVoteLocked(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, refreshRateSwitchingVote);
+ mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE, refreshRateVote);
+ mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH,
+ refreshRateSwitchingVote);
}
private boolean hasValidLowZone() {
@@ -2432,8 +2113,7 @@
}
private void updateDefaultDisplayState() {
- Display display = mContext.getSystemService(DisplayManager.class)
- .getDisplay(Display.DEFAULT_DISPLAY);
+ Display display = mInjector.getDisplay(Display.DEFAULT_DISPLAY);
if (display == null) {
return;
}
@@ -2687,7 +2367,7 @@
} else {
vote = null;
}
- DisplayModeDirector.this.updateVoteLocked(displayId, votePriority, vote);
+ mVotesStorage.updateVote(displayId, votePriority, vote);
}
void dumpLocked(PrintWriter pw) {
@@ -2713,7 +2393,7 @@
private final String mProximitySensorName = null;
private final String mProximitySensorType = Sensor.STRING_TYPE_PROXIMITY;
- private final BallotBox mBallotBox;
+ private final VotesStorage mVotesStorage;
private final Context mContext;
private final Injector mInjector;
@GuardedBy("mSensorObserverLock")
@@ -2725,9 +2405,9 @@
@GuardedBy("mSensorObserverLock")
private boolean mIsProxActive = false;
- SensorObserver(Context context, BallotBox ballotBox, Injector injector) {
+ SensorObserver(Context context, VotesStorage votesStorage, Injector injector) {
mContext = context;
- mBallotBox = ballotBox;
+ mVotesStorage = votesStorage;
mInjector = injector;
}
@@ -2750,8 +2430,7 @@
sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this);
synchronized (mSensorObserverLock) {
- for (Display d : mDisplayManager.getDisplays(
- DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) {
+ for (Display d : mInjector.getDisplays()) {
mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d));
}
}
@@ -2762,8 +2441,7 @@
}
private void recalculateVotesLocked() {
- final Display[] displays = mDisplayManager.getDisplays(
- DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
+ final Display[] displays = mInjector.getDisplays();
for (Display d : displays) {
int displayId = d.getDisplayId();
Vote vote = null;
@@ -2775,7 +2453,7 @@
vote = Vote.forPhysicalRefreshRates(rate.min, rate.max);
}
}
- mBallotBox.vote(displayId, Vote.PRIORITY_PROXIMITY, vote);
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_PROXIMITY, vote);
}
}
@@ -2794,7 +2472,7 @@
@Override
public void onDisplayAdded(int displayId) {
- boolean isDozeState = mInjector.isDozeState(mDisplayManager.getDisplay(displayId));
+ boolean isDozeState = mInjector.isDozeState(mInjector.getDisplay(displayId));
synchronized (mSensorObserverLock) {
mDozeStateByDisplay.put(displayId, isDozeState);
recalculateVotesLocked();
@@ -2806,7 +2484,7 @@
boolean wasDozeState = mDozeStateByDisplay.get(displayId);
synchronized (mSensorObserverLock) {
mDozeStateByDisplay.put(displayId,
- mInjector.isDozeState(mDisplayManager.getDisplay(displayId)));
+ mInjector.isDozeState(mInjector.getDisplay(displayId)));
if (wasDozeState != mDozeStateByDisplay.get(displayId)) {
recalculateVotesLocked();
}
@@ -2828,7 +2506,7 @@
* DisplayManagerInternal but originate in the display-device-config file.
*/
public class HbmObserver implements DisplayManager.DisplayListener {
- private final BallotBox mBallotBox;
+ private final VotesStorage mVotesStorage;
private final Handler mHandler;
private final SparseIntArray mHbmMode = new SparseIntArray();
private final SparseBooleanArray mHbmActive = new SparseBooleanArray();
@@ -2839,10 +2517,10 @@
private DisplayManagerInternal mDisplayManagerInternal;
- HbmObserver(Injector injector, BallotBox ballotBox, Handler handler,
+ HbmObserver(Injector injector, VotesStorage votesStorage, Handler handler,
DeviceConfigDisplaySettings displaySettings) {
mInjector = injector;
- mBallotBox = ballotBox;
+ mVotesStorage = votesStorage;
mHandler = handler;
mDeviceConfigDisplaySettings = displaySettings;
}
@@ -2912,7 +2590,7 @@
@Override
public void onDisplayRemoved(int displayId) {
- mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null);
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null);
mHbmMode.delete(displayId);
mHbmActive.delete(displayId);
}
@@ -2979,7 +2657,7 @@
}
}
- mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote);
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote);
}
void dumpLocked(PrintWriter pw) {
@@ -3176,8 +2854,13 @@
@NonNull ContentObserver observer);
void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
+ Handler handler);
+
+ void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
Handler handler, long flags);
+ Display getDisplay(int displayId);
+
Display[] getDisplays();
boolean getDisplayInfo(int displayId, DisplayInfo displayInfo);
@@ -3222,11 +2905,22 @@
@Override
public void registerDisplayListener(DisplayManager.DisplayListener listener,
+ Handler handler) {
+ getDisplayManager().registerDisplayListener(listener, handler);
+ }
+
+ @Override
+ public void registerDisplayListener(DisplayManager.DisplayListener listener,
Handler handler, long flags) {
getDisplayManager().registerDisplayListener(listener, handler, flags);
}
@Override
+ public Display getDisplay(int displayId) {
+ return getDisplayManager().getDisplay(displayId);
+ }
+
+ @Override
public Display[] getDisplays() {
return getDisplayManager().getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
}
@@ -3234,10 +2928,13 @@
@Override
public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
Display display = getDisplayManager().getDisplay(displayId);
- if (display != null) {
- return display.getDisplayInfo(displayInfo);
+ if (display == null) {
+ // We can occasionally get a display added or changed event for a display that was
+ // subsequently removed, which means this returns null. Check this case and bail
+ // out early; if it gets re-attached we'll eventually get another call back for it.
+ return false;
}
- return false;
+ return display.getDisplayInfo(displayInfo);
}
@Override
@@ -3291,8 +2988,4 @@
ServiceManager.getService(Context.THERMAL_SERVICE));
}
}
-
- interface BallotBox {
- void vote(int displayId, int priority, Vote vote);
- }
}
diff --git a/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java b/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java
index c04735d..58e1550 100644
--- a/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java
+++ b/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java
@@ -37,7 +37,7 @@
DisplayManager.DisplayListener {
private static final String TAG = "SkinThermalStatusObserver";
- private final DisplayModeDirector.BallotBox mBallotBox;
+ private final VotesStorage mVotesStorage;
private final DisplayModeDirector.Injector mInjector;
private boolean mLoggingEnabled;
@@ -52,15 +52,15 @@
mThermalThrottlingByDisplay = new SparseArray<>();
SkinThermalStatusObserver(DisplayModeDirector.Injector injector,
- DisplayModeDirector.BallotBox ballotBox) {
- this(injector, ballotBox, BackgroundThread.getHandler());
+ VotesStorage votesStorage) {
+ this(injector, votesStorage, BackgroundThread.getHandler());
}
@VisibleForTesting
SkinThermalStatusObserver(DisplayModeDirector.Injector injector,
- DisplayModeDirector.BallotBox ballotBox, Handler handler) {
+ VotesStorage votesStorage, Handler handler) {
mInjector = injector;
- mBallotBox = ballotBox;
+ mVotesStorage = votesStorage;
mHandler = handler;
}
@@ -112,8 +112,8 @@
public void onDisplayRemoved(int displayId) {
synchronized (mThermalObserverLock) {
mThermalThrottlingByDisplay.remove(displayId);
- mHandler.post(() -> mBallotBox.vote(displayId,
- DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE, null));
+ mHandler.post(() -> mVotesStorage.updateVote(displayId,
+ Vote.PRIORITY_SKIN_TEMPERATURE, null));
}
if (mLoggingEnabled) {
Slog.d(TAG, "Display removed and voted: displayId=" + displayId);
@@ -138,7 +138,7 @@
for (Display d : displays) {
final int displayId = d.getDisplayId();
d.getDisplayInfo(info);
- localMap.put(displayId, info.refreshRateThermalThrottling);
+ localMap.put(displayId, info.thermalRefreshRateThrottling);
}
synchronized (mThermalObserverLock) {
for (int i = 0; i < size; i++) {
@@ -154,7 +154,7 @@
DisplayInfo displayInfo = new DisplayInfo();
mInjector.getDisplayInfo(displayId, displayInfo);
SparseArray<SurfaceControl.RefreshRateRange> throttlingMap =
- displayInfo.refreshRateThermalThrottling;
+ displayInfo.thermalRefreshRateThrottling;
synchronized (mThermalObserverLock) {
mThermalThrottlingByDisplay.put(displayId, throttlingMap);
@@ -218,11 +218,11 @@
SurfaceControl.RefreshRateRange foundRange = findBestMatchingRefreshRateRange(currentStatus,
throttlingMap);
// if status <= currentStatus not found in the map reset vote
- DisplayModeDirector.Vote vote = null;
+ Vote vote = null;
if (foundRange != null) { // otherwise vote with found range
- vote = DisplayModeDirector.Vote.forRenderFrameRates(foundRange.min, foundRange.max);
+ vote = Vote.forRenderFrameRates(foundRange.min, foundRange.max);
}
- mBallotBox.vote(displayId, DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE, vote);
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_SKIN_TEMPERATURE, vote);
if (mLoggingEnabled) {
Slog.d(TAG, "Voted: vote=" + vote + ", display =" + displayId);
}
@@ -244,11 +244,11 @@
private void fallbackReportThrottlingIfNeeded(int displayId,
@Temperature.ThrottlingStatus int currentStatus) {
- DisplayModeDirector.Vote vote = null;
+ Vote vote = null;
if (currentStatus >= Temperature.THROTTLING_CRITICAL) {
- vote = DisplayModeDirector.Vote.forRenderFrameRates(0f, 60f);
+ vote = Vote.forRenderFrameRates(0f, 60f);
}
- mBallotBox.vote(displayId, DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE, vote);
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_SKIN_TEMPERATURE, vote);
if (mLoggingEnabled) {
Slog.d(TAG, "Voted(fallback): vote=" + vote + ", display =" + displayId);
}
diff --git a/services/core/java/com/android/server/display/mode/Vote.java b/services/core/java/com/android/server/display/mode/Vote.java
new file mode 100644
index 0000000..a42d8f2
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/Vote.java
@@ -0,0 +1,237 @@
+/*
+ * 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.mode;
+
+import android.view.SurfaceControl;
+
+final class Vote {
+ // DEFAULT_RENDER_FRAME_RATE votes for render frame rate [0, DEFAULT]. As the lowest
+ // priority vote, it's overridden by all other considerations. It acts to set a default
+ // frame rate for a device.
+ static final int PRIORITY_DEFAULT_RENDER_FRAME_RATE = 0;
+
+ // PRIORITY_FLICKER_REFRESH_RATE votes for a single refresh rate like [60,60], [90,90] or
+ // null. It is used to set a preferred refresh rate value in case the higher priority votes
+ // result is a range.
+ static final int PRIORITY_FLICKER_REFRESH_RATE = 1;
+
+ // High-brightness-mode may need a specific range of refresh-rates to function properly.
+ static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 2;
+
+ // SETTING_MIN_RENDER_FRAME_RATE is used to propose a lower bound of the render frame rate.
+ // It votes [minRefreshRate, Float.POSITIVE_INFINITY]
+ static final int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3;
+
+ // APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render
+ // frame rate in certain cases, mostly to preserve power.
+ // @see android.view.WindowManager.LayoutParams#preferredMinRefreshRate
+ // @see android.view.WindowManager.LayoutParams#preferredMaxRefreshRate
+ // It votes to [preferredMinRefreshRate, preferredMaxRefreshRate].
+ static final int PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE = 4;
+
+ // We split the app request into different priorities in case we can satisfy one desire
+ // without the other.
+
+ // Application can specify preferred refresh rate with below attrs.
+ // @see android.view.WindowManager.LayoutParams#preferredRefreshRate
+ // @see android.view.WindowManager.LayoutParams#preferredDisplayModeId
+ //
+ // When the app specifies a LayoutParams#preferredDisplayModeId, in addition to the
+ // refresh rate, it also chooses a preferred size (resolution) as part of the selected
+ // mode id. The app preference is then translated to APP_REQUEST_BASE_MODE_REFRESH_RATE and
+ // optionally to APP_REQUEST_SIZE as well, if a mode id was selected.
+ // The system also forces some apps like denylisted app to run at a lower refresh rate.
+ // @see android.R.array#config_highRefreshRateBlacklist
+ //
+ // When summarizing the votes and filtering the allowed display modes, these votes determine
+ // which mode id should be the base mode id to be sent to SurfaceFlinger:
+ // - APP_REQUEST_BASE_MODE_REFRESH_RATE is used to validate the vote summary. If a summary
+ // includes a base mode refresh rate, but it is not in the refresh rate range, then the
+ // summary is considered invalid so we could drop a lower priority vote and try again.
+ // - APP_REQUEST_SIZE is used to filter out display modes of a different size.
+ //
+ // The preferred refresh rate is set on the main surface of the app outside of
+ // DisplayModeDirector.
+ // @see com.android.server.wm.WindowState#updateFrameRateSelectionPriorityIfNeeded
+ static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 5;
+ static final int PRIORITY_APP_REQUEST_SIZE = 6;
+
+ // SETTING_PEAK_RENDER_FRAME_RATE has a high priority and will restrict the bounds of the
+ // rest of low priority voters. It votes [0, max(PEAK, MIN)]
+ static final int PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE = 7;
+
+ // To avoid delay in switching between 60HZ -> 90HZ when activating LHBM, set refresh
+ // rate to max value (same as for PRIORITY_UDFPS) on lock screen
+ static final int PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE = 8;
+
+ // For concurrent displays we want to limit refresh rate on all displays
+ static final int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 9;
+
+ // LOW_POWER_MODE force the render frame rate to [0, 60HZ] if
+ // Settings.Global.LOW_POWER_MODE is on.
+ static final int PRIORITY_LOW_POWER_MODE = 10;
+
+ // PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the
+ // higher priority voters' result is a range, it will fix the rate to a single choice.
+ // It's used to avoid refresh rate switches in certain conditions which may result in the
+ // user seeing the display flickering when the switches occur.
+ static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 11;
+
+ // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
+ static final int PRIORITY_SKIN_TEMPERATURE = 12;
+
+ // The proximity sensor needs the refresh rate to be locked in order to function, so this is
+ // set to a high priority.
+ static final int PRIORITY_PROXIMITY = 13;
+
+ // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
+ // to function, so this needs to be the highest priority of all votes.
+ static final int PRIORITY_UDFPS = 14;
+
+ // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
+ // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
+
+ static final int MIN_PRIORITY = PRIORITY_DEFAULT_RENDER_FRAME_RATE;
+ static final int MAX_PRIORITY = PRIORITY_UDFPS;
+
+ // The cutoff for the app request refresh rate range. Votes with priorities lower than this
+ // value will not be considered when constructing the app request refresh rate range.
+ static final int APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF =
+ PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE;
+
+ /**
+ * A value signifying an invalid width or height in a vote.
+ */
+ static final int INVALID_SIZE = -1;
+
+ /**
+ * The requested width of the display in pixels, or INVALID_SIZE;
+ */
+ public final int width;
+ /**
+ * The requested height of the display in pixels, or INVALID_SIZE;
+ */
+ public final int height;
+ /**
+ * Information about the refresh rate frame rate ranges DM would like to set the display to.
+ */
+ public final SurfaceControl.RefreshRateRanges refreshRateRanges;
+
+ /**
+ * Whether refresh rate switching should be disabled (i.e. the refresh rate range is
+ * a single value).
+ */
+ public final boolean disableRefreshRateSwitching;
+
+ /**
+ * The preferred refresh rate selected by the app. It is used to validate that the summary
+ * refresh rate ranges include this value, and are not restricted by a lower priority vote.
+ */
+ public final float appRequestBaseModeRefreshRate;
+
+ static Vote forPhysicalRefreshRates(float minRefreshRate, float maxRefreshRate) {
+ return new Vote(INVALID_SIZE, INVALID_SIZE, minRefreshRate, maxRefreshRate, 0,
+ Float.POSITIVE_INFINITY,
+ minRefreshRate == maxRefreshRate, 0f);
+ }
+
+ static Vote forRenderFrameRates(float minFrameRate, float maxFrameRate) {
+ return new Vote(INVALID_SIZE, INVALID_SIZE, 0, Float.POSITIVE_INFINITY, minFrameRate,
+ maxFrameRate,
+ false, 0f);
+ }
+
+ static Vote forSize(int width, int height) {
+ return new Vote(width, height, 0, Float.POSITIVE_INFINITY, 0, Float.POSITIVE_INFINITY,
+ false,
+ 0f);
+ }
+
+ static Vote forDisableRefreshRateSwitching() {
+ return new Vote(INVALID_SIZE, INVALID_SIZE, 0, Float.POSITIVE_INFINITY, 0,
+ Float.POSITIVE_INFINITY, true,
+ 0f);
+ }
+
+ static Vote forBaseModeRefreshRate(float baseModeRefreshRate) {
+ return new Vote(INVALID_SIZE, INVALID_SIZE, 0, Float.POSITIVE_INFINITY, 0,
+ Float.POSITIVE_INFINITY, false,
+ baseModeRefreshRate);
+ }
+
+ private Vote(int width, int height,
+ float minPhysicalRefreshRate,
+ float maxPhysicalRefreshRate,
+ float minRenderFrameRate,
+ float maxRenderFrameRate,
+ boolean disableRefreshRateSwitching,
+ float baseModeRefreshRate) {
+ this.width = width;
+ this.height = height;
+ this.refreshRateRanges = new SurfaceControl.RefreshRateRanges(
+ new SurfaceControl.RefreshRateRange(minPhysicalRefreshRate, maxPhysicalRefreshRate),
+ new SurfaceControl.RefreshRateRange(minRenderFrameRate, maxRenderFrameRate));
+ this.disableRefreshRateSwitching = disableRefreshRateSwitching;
+ this.appRequestBaseModeRefreshRate = baseModeRefreshRate;
+ }
+
+ static String priorityToString(int priority) {
+ switch (priority) {
+ case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE:
+ return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE";
+ case PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE:
+ return "PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE";
+ case PRIORITY_APP_REQUEST_SIZE:
+ return "PRIORITY_APP_REQUEST_SIZE";
+ case PRIORITY_DEFAULT_RENDER_FRAME_RATE:
+ return "PRIORITY_DEFAULT_REFRESH_RATE";
+ case PRIORITY_FLICKER_REFRESH_RATE:
+ return "PRIORITY_FLICKER_REFRESH_RATE";
+ case PRIORITY_FLICKER_REFRESH_RATE_SWITCH:
+ return "PRIORITY_FLICKER_REFRESH_RATE_SWITCH";
+ case PRIORITY_HIGH_BRIGHTNESS_MODE:
+ return "PRIORITY_HIGH_BRIGHTNESS_MODE";
+ case PRIORITY_PROXIMITY:
+ return "PRIORITY_PROXIMITY";
+ case PRIORITY_LOW_POWER_MODE:
+ return "PRIORITY_LOW_POWER_MODE";
+ case PRIORITY_SKIN_TEMPERATURE:
+ return "PRIORITY_SKIN_TEMPERATURE";
+ case PRIORITY_UDFPS:
+ return "PRIORITY_UDFPS";
+ case PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE:
+ return "PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE";
+ case PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE:
+ return "PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE";
+ case PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE:
+ return "PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE";
+ case PRIORITY_LAYOUT_LIMITED_FRAME_RATE:
+ return "PRIORITY_LAYOUT_LIMITED_FRAME_RATE";
+ default:
+ return Integer.toString(priority);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Vote: {"
+ + "width: " + width + ", height: " + height
+ + ", refreshRateRanges: " + refreshRateRanges
+ + ", disableRefreshRateSwitching: " + disableRefreshRateSwitching
+ + ", appRequestBaseModeRefreshRate: " + appRequestBaseModeRefreshRate + "}";
+ }
+}
diff --git a/services/core/java/com/android/server/display/mode/VotesStorage.java b/services/core/java/com/android/server/display/mode/VotesStorage.java
new file mode 100644
index 0000000..dadcebe
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/VotesStorage.java
@@ -0,0 +1,152 @@
+/*
+ * 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.mode;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+
+class VotesStorage {
+ private static final String TAG = "VotesStorage";
+ // Special ID used to indicate that given vote is to be applied globally, rather than to a
+ // specific display.
+ private static final int GLOBAL_ID = -1;
+
+ private boolean mLoggingEnabled;
+
+ private final Listener mListener;
+
+ private final Object mStorageLock = new Object();
+ // A map from the display ID to the collection of votes and their priority. The latter takes
+ // the form of another map from the priority to the vote itself so that each priority is
+ // guaranteed to have exactly one vote, which is also easily and efficiently replaceable.
+ @GuardedBy("mStorageLock")
+ private final SparseArray<SparseArray<Vote>> mVotesByDisplay = new SparseArray<>();
+
+ VotesStorage(@NonNull Listener listener) {
+ mListener = listener;
+ }
+ /** sets logging enabled/disabled for this class */
+ void setLoggingEnabled(boolean loggingEnabled) {
+ mLoggingEnabled = loggingEnabled;
+ }
+ /**
+ * gets all votes for specific display, note that global display votes are also added to result
+ */
+ @NonNull
+ SparseArray<Vote> getVotes(int displayId) {
+ SparseArray<Vote> votesLocal;
+ SparseArray<Vote> globalVotesLocal;
+ synchronized (mStorageLock) {
+ SparseArray<Vote> displayVotes = mVotesByDisplay.get(displayId);
+ votesLocal = displayVotes != null ? displayVotes.clone() : new SparseArray<>();
+ SparseArray<Vote> globalVotes = mVotesByDisplay.get(GLOBAL_ID);
+ globalVotesLocal = globalVotes != null ? globalVotes.clone() : new SparseArray<>();
+ }
+ for (int i = 0; i < globalVotesLocal.size(); i++) {
+ int priority = globalVotesLocal.keyAt(i);
+ if (!votesLocal.contains(priority)) {
+ votesLocal.put(priority, globalVotesLocal.valueAt(i));
+ }
+ }
+ return votesLocal;
+ }
+
+ /** updates vote storage for all displays */
+ void updateGlobalVote(int priority, @Nullable Vote vote) {
+ updateVote(GLOBAL_ID, priority, vote);
+ }
+
+ /** updates vote storage */
+ void updateVote(int displayId, int priority, @Nullable Vote vote) {
+ if (mLoggingEnabled) {
+ Slog.i(TAG, "updateVoteLocked(displayId=" + displayId
+ + ", priority=" + Vote.priorityToString(priority)
+ + ", vote=" + vote + ")");
+ }
+ if (priority < Vote.MIN_PRIORITY || priority > Vote.MAX_PRIORITY) {
+ Slog.w(TAG, "Received a vote with an invalid priority, ignoring:"
+ + " priority=" + Vote.priorityToString(priority)
+ + ", vote=" + vote);
+ return;
+ }
+ SparseArray<Vote> votes;
+ synchronized (mStorageLock) {
+ if (mVotesByDisplay.contains(displayId)) {
+ votes = mVotesByDisplay.get(displayId);
+ } else {
+ votes = new SparseArray<>();
+ mVotesByDisplay.put(displayId, votes);
+ }
+ if (vote != null) {
+ votes.put(priority, vote);
+ } else {
+ votes.remove(priority);
+ }
+ }
+ if (mLoggingEnabled) {
+ Slog.i(TAG, "Updated votes for display=" + displayId + " votes=" + votes);
+ }
+ mListener.onChanged();
+ }
+
+ /** dump class values, for debugging */
+ void dump(@NonNull PrintWriter pw) {
+ SparseArray<SparseArray<Vote>> votesByDisplayLocal = new SparseArray<>();
+ synchronized (mStorageLock) {
+ for (int i = 0; i < mVotesByDisplay.size(); i++) {
+ votesByDisplayLocal.put(mVotesByDisplay.keyAt(i),
+ mVotesByDisplay.valueAt(i).clone());
+ }
+ }
+ pw.println(" mVotesByDisplay:");
+ for (int i = 0; i < votesByDisplayLocal.size(); i++) {
+ SparseArray<Vote> votes = votesByDisplayLocal.valueAt(i);
+ if (votes.size() == 0) {
+ continue;
+ }
+ pw.println(" " + votesByDisplayLocal.keyAt(i) + ":");
+ for (int p = Vote.MAX_PRIORITY; p >= Vote.MIN_PRIORITY; p--) {
+ Vote vote = votes.get(p);
+ if (vote == null) {
+ continue;
+ }
+ pw.println(" " + Vote.priorityToString(p) + " -> " + vote);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ void injectVotesByDisplay(SparseArray<SparseArray<Vote>> votesByDisplay) {
+ synchronized (mStorageLock) {
+ mVotesByDisplay.clear();
+ for (int i = 0; i < votesByDisplay.size(); i++) {
+ mVotesByDisplay.put(votesByDisplay.keyAt(i), votesByDisplay.valueAt(i));
+ }
+ }
+ }
+
+ interface Listener {
+ void onChanged();
+ }
+}
diff --git a/services/core/java/com/android/server/input/KeyboardBacklightController.java b/services/core/java/com/android/server/input/KeyboardBacklightController.java
index 048308e..48c346a 100644
--- a/services/core/java/com/android/server/input/KeyboardBacklightController.java
+++ b/services/core/java/com/android/server/input/KeyboardBacklightController.java
@@ -199,8 +199,11 @@
}
if (brightness.isPresent()) {
int brightnessValue = Math.max(0, Math.min(MAX_BRIGHTNESS, brightness.getAsInt()));
- int brightnessLevel = Arrays.binarySearch(BRIGHTNESS_VALUE_FOR_LEVEL, brightnessValue);
- updateBacklightState(inputDevice.getId(), keyboardBacklight, brightnessLevel,
+ int index = Arrays.binarySearch(BRIGHTNESS_VALUE_FOR_LEVEL, brightnessValue);
+ if (index < 0) {
+ index = Math.min(NUM_BRIGHTNESS_CHANGE_STEPS, -(index + 1));
+ }
+ updateBacklightState(inputDevice.getId(), keyboardBacklight, index,
false /* isTriggeredByKeyPress */);
if (DEBUG) {
Slog.d(TAG, "Restoring brightness level " + brightness.getAsInt());
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 72c7dad..d8716b3 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -16,6 +16,8 @@
package com.android.server.input;
+import android.annotation.AnyThread;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -99,6 +101,7 @@
private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
+ private static final int MSG_CURRENT_IME_INFO_CHANGED = 5;
private final Context mContext;
private final NativeInputManagerService mNative;
@@ -108,16 +111,17 @@
private final Handler mHandler;
// Connected keyboards with associated keyboard layouts (either auto-detected or manually
- // selected layout). If the mapped value is null/empty, it means that no layout has been
- // configured for the keyboard and user might need to manually configure it from the Settings.
- private final SparseArray<Set<String>> mConfiguredKeyboards = new SparseArray<>();
+ // selected layout).
+ private final SparseArray<KeyboardConfiguration> mConfiguredKeyboards = new SparseArray<>();
private Toast mSwitchedKeyboardLayoutToast;
// This cache stores "best-matched" layouts so that we don't need to run the matching
// algorithm repeatedly.
@GuardedBy("mKeyboardLayoutCache")
private final Map<String, String> mKeyboardLayoutCache = new ArrayMap<>();
+ private final Object mImeInfoLock = new Object();
@Nullable
+ @GuardedBy("mImeInfoLock")
private ImeInfo mCurrentImeInfo;
KeyboardLayoutManager(Context context, NativeInputManagerService nativeService,
@@ -155,26 +159,32 @@
}
@Override
+ @MainThread
public void onInputDeviceAdded(int deviceId) {
onInputDeviceChanged(deviceId);
- if (useNewSettingsUi()) {
- // Force native callback to set up keyboard layout overlay for newly added keyboards
- reloadKeyboardLayouts();
- }
}
@Override
+ @MainThread
public void onInputDeviceRemoved(int deviceId) {
mConfiguredKeyboards.remove(deviceId);
maybeUpdateNotification();
}
@Override
+ @MainThread
public void onInputDeviceChanged(int deviceId) {
final InputDevice inputDevice = getInputDevice(deviceId);
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
return;
}
+ KeyboardConfiguration config = mConfiguredKeyboards.get(deviceId);
+ if (config == null) {
+ config = new KeyboardConfiguration();
+ mConfiguredKeyboards.put(deviceId, config);
+ }
+
+ boolean needToShowNotification = false;
if (!useNewSettingsUi()) {
synchronized (mDataStore) {
String layout = getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
@@ -182,54 +192,66 @@
layout = getDefaultKeyboardLayout(inputDevice);
if (layout != null) {
setCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier(), layout);
- } else {
- mConfiguredKeyboards.put(inputDevice.getId(), new HashSet<>());
}
}
+ config.setCurrentLayout(layout);
+ if (layout == null) {
+ // In old settings show notification always until user manually selects a
+ // layout in the settings.
+ needToShowNotification = true;
+ }
}
} else {
final InputDeviceIdentifier identifier = inputDevice.getIdentifier();
final String key = getLayoutDescriptor(identifier);
Set<String> selectedLayouts = new HashSet<>();
- boolean needToShowMissingLayoutNotification = false;
for (ImeInfo imeInfo : getImeInfoListForLayoutMapping()) {
// Check if the layout has been previously configured
String layout = getKeyboardLayoutForInputDeviceInternal(identifier,
new ImeInfo(imeInfo.mUserId, imeInfo.mImeSubtypeHandle,
imeInfo.mImeSubtype));
if (layout == null) {
- needToShowMissingLayoutNotification = true;
- continue;
+ // If even one layout not configured properly, we need to ask user to configure
+ // the keyboard properly from the Settings.
+ selectedLayouts.clear();
+ break;
}
selectedLayouts.add(layout);
}
- if (needToShowMissingLayoutNotification) {
- // If even one layout not configured properly we will show configuration
- // notification allowing user to set the keyboard layout.
- selectedLayouts.clear();
- }
-
if (DEBUG) {
Slog.d(TAG,
"Layouts selected for input device: " + identifier + " -> selectedLayouts: "
+ selectedLayouts);
}
- mConfiguredKeyboards.set(inputDevice.getId(), selectedLayouts);
+
+ config.setConfiguredLayouts(selectedLayouts);
+
+ // Update current layout: If there is a change then need to reload.
+ synchronized (mImeInfoLock) {
+ String layout = getKeyboardLayoutForInputDeviceInternal(
+ inputDevice.getIdentifier(), mCurrentImeInfo);
+ if (!Objects.equals(layout, config.getCurrentLayout())) {
+ config.setCurrentLayout(layout);
+ mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
+ }
+ }
synchronized (mDataStore) {
try {
- if (!mDataStore.setSelectedKeyboardLayouts(key, selectedLayouts)) {
- // No need to show the notification only if layout selection didn't change
+ if (mDataStore.setSelectedKeyboardLayouts(key, selectedLayouts)) {
+ // Need to show the notification only if layout selection changed
// from the previous configuration
- return;
+ needToShowNotification = true;
}
} finally {
mDataStore.saveIfNeeded();
}
}
}
- maybeUpdateNotification();
+ if (needToShowNotification) {
+ maybeUpdateNotification();
+ }
}
private String getDefaultKeyboardLayout(final InputDevice inputDevice) {
@@ -323,12 +345,14 @@
reloadKeyboardLayouts();
}
+ @AnyThread
public KeyboardLayout[] getKeyboardLayouts() {
final ArrayList<KeyboardLayout> list = new ArrayList<>();
visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> list.add(layout));
return list.toArray(new KeyboardLayout[0]);
}
+ @AnyThread
public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
final InputDeviceIdentifier identifier) {
if (useNewSettingsUi()) {
@@ -375,6 +399,7 @@
KeyboardLayout[]::new);
}
+ @AnyThread
@Nullable
public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
Objects.requireNonNull(keyboardLayoutDescriptor,
@@ -543,6 +568,7 @@
return key.toString();
}
+ @AnyThread
@Nullable
public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
if (useNewSettingsUi()) {
@@ -566,6 +592,7 @@
}
}
+ @AnyThread
public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor) {
if (useNewSettingsUi()) {
@@ -592,6 +619,7 @@
}
}
+ @AnyThread
public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
if (useNewSettingsUi()) {
Slog.e(TAG, "getEnabledKeyboardLayoutsForInputDevice API not supported");
@@ -608,6 +636,7 @@
}
}
+ @AnyThread
public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor) {
if (useNewSettingsUi()) {
@@ -635,6 +664,7 @@
}
}
+ @AnyThread
public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor) {
if (useNewSettingsUi()) {
@@ -667,6 +697,7 @@
}
}
+ @AnyThread
public void switchKeyboardLayout(int deviceId, int direction) {
if (useNewSettingsUi()) {
Slog.e(TAG, "switchKeyboardLayout API not supported");
@@ -675,7 +706,7 @@
mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
}
- // Must be called on handler.
+ @MainThread
private void handleSwitchKeyboardLayout(int deviceId, int direction) {
final InputDevice device = getInputDevice(deviceId);
if (device != null) {
@@ -713,23 +744,14 @@
}
@Nullable
+ @AnyThread
public String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
String keyboardLayoutDescriptor;
if (useNewSettingsUi()) {
- InputDevice inputDevice = getInputDevice(identifier);
- if (inputDevice == null) {
- // getKeyboardLayoutOverlay() called before input device added completely. Need
- // to wait till the device is added which will call reloadKeyboardLayouts()
- return null;
+ synchronized (mImeInfoLock) {
+ keyboardLayoutDescriptor = getKeyboardLayoutForInputDeviceInternal(identifier,
+ mCurrentImeInfo);
}
- if (mCurrentImeInfo == null) {
- // Haven't received onInputMethodSubtypeChanged() callback from IMMS. Will reload
- // keyboard layouts once we receive the callback.
- return null;
- }
-
- keyboardLayoutDescriptor = getKeyboardLayoutForInputDeviceInternal(identifier,
- mCurrentImeInfo);
} else {
keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
}
@@ -755,6 +777,7 @@
return result;
}
+ @AnyThread
@Nullable
public String getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
@@ -773,6 +796,7 @@
return layout;
}
+ @AnyThread
public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
@Nullable InputMethodSubtype imeSubtype,
@@ -783,8 +807,8 @@
}
Objects.requireNonNull(keyboardLayoutDescriptor,
"keyboardLayoutDescriptor must not be null");
- String key = createLayoutKey(identifier, userId,
- InputMethodSubtypeHandle.of(imeInfo, imeSubtype));
+ String key = createLayoutKey(identifier,
+ new ImeInfo(userId, InputMethodSubtypeHandle.of(imeInfo, imeSubtype), imeSubtype));
synchronized (mDataStore) {
try {
// Key for storing into data store = <device descriptor>,<userId>,<subtypeHandle>
@@ -803,6 +827,7 @@
}
}
+ @AnyThread
public KeyboardLayout[] getKeyboardLayoutListForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
@Nullable InputMethodSubtype imeSubtype) {
@@ -815,8 +840,8 @@
}
private KeyboardLayout[] getKeyboardLayoutListForInputDeviceInternal(
- InputDeviceIdentifier identifier, ImeInfo imeInfo) {
- String key = createLayoutKey(identifier, imeInfo.mUserId, imeInfo.mImeSubtypeHandle);
+ InputDeviceIdentifier identifier, @Nullable ImeInfo imeInfo) {
+ String key = createLayoutKey(identifier, imeInfo);
// Fetch user selected layout and always include it in layout list.
String userSelectedLayout;
@@ -826,7 +851,7 @@
final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<>();
String imeLanguageTag;
- if (imeInfo.mImeSubtype == null) {
+ if (imeInfo == null || imeInfo.mImeSubtype == null) {
imeLanguageTag = "";
} else {
ULocale imeLocale = imeInfo.mImeSubtype.getPhysicalKeyboardHintLanguageTag();
@@ -866,6 +891,7 @@
return potentialLayouts.toArray(new KeyboardLayout[0]);
}
+ @AnyThread
public void onInputMethodSubtypeChanged(@UserIdInt int userId,
@Nullable InputMethodSubtypeHandle subtypeHandle,
@Nullable InputMethodSubtype subtype) {
@@ -879,25 +905,45 @@
}
return;
}
- if (mCurrentImeInfo == null || !subtypeHandle.equals(mCurrentImeInfo.mImeSubtypeHandle)
- || mCurrentImeInfo.mUserId != userId) {
- mCurrentImeInfo = new ImeInfo(userId, subtypeHandle, subtype);
- mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
- if (DEBUG) {
- Slog.d(TAG, "InputMethodSubtype changed: userId=" + userId
- + " subtypeHandle=" + subtypeHandle);
+ synchronized (mImeInfoLock) {
+ if (mCurrentImeInfo == null || !subtypeHandle.equals(mCurrentImeInfo.mImeSubtypeHandle)
+ || mCurrentImeInfo.mUserId != userId) {
+ mCurrentImeInfo = new ImeInfo(userId, subtypeHandle, subtype);
+ mHandler.sendEmptyMessage(MSG_CURRENT_IME_INFO_CHANGED);
+ if (DEBUG) {
+ Slog.d(TAG, "InputMethodSubtype changed: userId=" + userId
+ + " subtypeHandle=" + subtypeHandle);
+ }
+ }
+ }
+ }
+
+ @MainThread
+ private void onCurrentImeInfoChanged() {
+ synchronized (mImeInfoLock) {
+ for (int i = 0; i < mConfiguredKeyboards.size(); i++) {
+ InputDevice inputDevice = Objects.requireNonNull(
+ getInputDevice(mConfiguredKeyboards.keyAt(i)));
+ String layout = getKeyboardLayoutForInputDeviceInternal(inputDevice.getIdentifier(),
+ mCurrentImeInfo);
+ KeyboardConfiguration config = mConfiguredKeyboards.valueAt(i);
+ if (!Objects.equals(layout, config.getCurrentLayout())) {
+ config.setCurrentLayout(layout);
+ mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
+ return;
+ }
}
}
}
@Nullable
private String getKeyboardLayoutForInputDeviceInternal(InputDeviceIdentifier identifier,
- ImeInfo imeInfo) {
+ @Nullable ImeInfo imeInfo) {
InputDevice inputDevice = getInputDevice(identifier);
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
return null;
}
- String key = createLayoutKey(identifier, imeInfo.mUserId, imeInfo.mImeSubtypeHandle);
+ String key = createLayoutKey(identifier, imeInfo);
String layout;
synchronized (mDataStore) {
layout = mDataStore.getKeyboardLayout(getLayoutDescriptor(identifier), key);
@@ -923,11 +969,7 @@
@Nullable
private static String getDefaultKeyboardLayoutBasedOnImeInfo(InputDevice inputDevice,
- ImeInfo imeInfo, KeyboardLayout[] layoutList) {
- if (imeInfo.mImeSubtypeHandle == null) {
- return null;
- }
-
+ @Nullable ImeInfo imeInfo, KeyboardLayout[] layoutList) {
Arrays.sort(layoutList);
// Check <VendorID, ProductID> matching for explicitly declared custom KCM files.
@@ -961,12 +1003,12 @@
}
}
- InputMethodSubtype subtype = imeInfo.mImeSubtype;
- // Can't auto select layout based on IME if subtype or language tag is null
- if (subtype == null) {
+ if (imeInfo == null || imeInfo.mImeSubtypeHandle == null || imeInfo.mImeSubtype == null) {
+ // Can't auto select layout based on IME info is null
return null;
}
+ InputMethodSubtype subtype = imeInfo.mImeSubtype;
// Check layout type, language tag information from IME for matching
ULocale pkLocale = subtype.getPhysicalKeyboardHintLanguageTag();
String pkLanguageTag =
@@ -1043,6 +1085,7 @@
mNative.reloadKeyboardLayouts();
}
+ @MainThread
private void maybeUpdateNotification() {
if (mConfiguredKeyboards.size() == 0) {
hideKeyboardLayoutNotification();
@@ -1051,7 +1094,7 @@
for (int i = 0; i < mConfiguredKeyboards.size(); i++) {
// If we have a keyboard with no selected layouts, we should always show missing
// layout notification even if there are other keyboards that are configured properly.
- if (mConfiguredKeyboards.valueAt(i).isEmpty()) {
+ if (!mConfiguredKeyboards.valueAt(i).hasConfiguredLayouts()) {
showMissingKeyboardLayoutNotification();
return;
}
@@ -1059,7 +1102,7 @@
showConfiguredKeyboardLayoutNotification();
}
- // Must be called on handler.
+ @MainThread
private void showMissingKeyboardLayoutNotification() {
final Resources r = mContext.getResources();
final String missingKeyboardLayoutNotificationContent = r.getString(
@@ -1084,6 +1127,7 @@
}
}
+ @MainThread
private void showKeyboardLayoutNotification(@NonNull String intentTitle,
@NonNull String intentContent, @Nullable InputDevice targetDevice) {
final NotificationManager notificationManager = mContext.getSystemService(
@@ -1119,7 +1163,7 @@
notification, UserHandle.ALL);
}
- // Must be called on handler.
+ @MainThread
private void hideKeyboardLayoutNotification() {
NotificationManager notificationManager = mContext.getSystemService(
NotificationManager.class);
@@ -1132,6 +1176,7 @@
UserHandle.ALL);
}
+ @MainThread
private void showConfiguredKeyboardLayoutNotification() {
final Resources r = mContext.getResources();
@@ -1144,8 +1189,8 @@
}
final InputDevice inputDevice = getInputDevice(mConfiguredKeyboards.keyAt(0));
- final Set<String> selectedLayouts = mConfiguredKeyboards.valueAt(0);
- if (inputDevice == null || selectedLayouts == null || selectedLayouts.isEmpty()) {
+ final KeyboardConfiguration config = mConfiguredKeyboards.valueAt(0);
+ if (inputDevice == null || !config.hasConfiguredLayouts()) {
return;
}
@@ -1153,10 +1198,11 @@
r.getString(
R.string.keyboard_layout_notification_selected_title,
inputDevice.getName()),
- createConfiguredNotificationText(mContext, selectedLayouts),
+ createConfiguredNotificationText(mContext, config.getConfiguredLayouts()),
inputDevice);
}
+ @MainThread
private String createConfiguredNotificationText(@NonNull Context context,
@NonNull Set<String> selectedLayouts) {
final Resources r = context.getResources();
@@ -1199,6 +1245,9 @@
case MSG_UPDATE_KEYBOARD_LAYOUTS:
updateKeyboardLayouts();
return true;
+ case MSG_CURRENT_IME_INFO_CHANGED:
+ onCurrentImeInfoChanged();
+ return true;
default:
return false;
}
@@ -1252,17 +1301,19 @@
return imeInfoList;
}
- private String createLayoutKey(InputDeviceIdentifier identifier, int userId,
- @NonNull InputMethodSubtypeHandle subtypeHandle) {
- Objects.requireNonNull(subtypeHandle, "subtypeHandle must not be null");
- return "layoutDescriptor:" + getLayoutDescriptor(identifier) + ",userId:" + userId
- + ",subtypeHandle:" + subtypeHandle.toStringHandle();
+ private String createLayoutKey(InputDeviceIdentifier identifier, @Nullable ImeInfo imeInfo) {
+ if (imeInfo == null) {
+ return getLayoutDescriptor(identifier);
+ }
+ Objects.requireNonNull(imeInfo.mImeSubtypeHandle, "subtypeHandle must not be null");
+ return "layoutDescriptor:" + getLayoutDescriptor(identifier) + ",userId:" + imeInfo.mUserId
+ + ",subtypeHandle:" + imeInfo.mImeSubtypeHandle.toStringHandle();
}
private static boolean isLayoutCompatibleWithLanguageTag(KeyboardLayout layout,
@NonNull String languageTag) {
LocaleList layoutLocales = layout.getLocales();
- if (layoutLocales.isEmpty()) {
+ if (layoutLocales.isEmpty() || TextUtils.isEmpty(languageTag)) {
// KCM file doesn't have an associated language tag. This can be from
// a 3rd party app so need to include it as a potential layout.
return true;
@@ -1350,6 +1401,39 @@
}
}
+ private static class KeyboardConfiguration {
+ // If null or empty, it means no layout is configured for the device. And user needs to
+ // manually set up the device.
+ @Nullable
+ private Set<String> mConfiguredLayouts;
+
+ // If null, it means no layout is selected for the device.
+ @Nullable
+ private String mCurrentLayout;
+
+ private boolean hasConfiguredLayouts() {
+ return mConfiguredLayouts != null && !mConfiguredLayouts.isEmpty();
+ }
+
+ @Nullable
+ private Set<String> getConfiguredLayouts() {
+ return mConfiguredLayouts;
+ }
+
+ private void setConfiguredLayouts(Set<String> configuredLayouts) {
+ mConfiguredLayouts = configuredLayouts;
+ }
+
+ @Nullable
+ private String getCurrentLayout() {
+ return mCurrentLayout;
+ }
+
+ private void setCurrentLayout(String currentLayout) {
+ mCurrentLayout = currentLayout;
+ }
+ }
+
private interface KeyboardLayoutVisitor {
void visitKeyboardLayout(Resources resources,
int keyboardLayoutResId, KeyboardLayout layout);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index a3d89e7..b708269 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -28,6 +28,7 @@
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ActivityManager.isProcStateConsideredInteraction;
+import static android.app.ActivityManager.printCapabilitiesSummary;
import static android.app.ActivityManager.procStateToString;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
@@ -1133,6 +1134,7 @@
if (!callbackInfo.isPending) {
mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo)
.sendToTarget();
+ callbackInfo.isPending = true;
}
}
}
@@ -1156,6 +1158,19 @@
this.procStateSeq = procStateSeq;
this.capability = capability;
}
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("{");
+ sb.append("uid=").append(uid).append(",");
+ sb.append("proc_state=").append(procStateToString(procState)).append(",");
+ sb.append("seq=").append(procStateSeq).append(",");
+ sb.append("cap="); printCapabilitiesSummary(sb, capability); sb.append(",");
+ sb.append("pending=").append(isPending);
+ sb.append("}");
+ return sb.toString();
+ }
}
final private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() {
@@ -3982,31 +3997,31 @@
synchronized (mUidBlockedState) {
collectKeys(mUidBlockedState, knownUids);
}
+ synchronized (mUidStateCallbackInfos) {
+ collectKeys(mUidStateCallbackInfos, knownUids);
+ }
fout.println("Status for all known UIDs:");
fout.increaseIndent();
size = knownUids.size();
for (int i = 0; i < size; i++) {
final int uid = knownUids.keyAt(i);
- fout.print("UID=");
- fout.print(uid);
+ fout.print("UID", uid);
final UidState uidState = mUidState.get(uid);
- if (uidState == null) {
- fout.print(" state={null}");
- } else {
- fout.print(" state=");
- fout.print(uidState.toString());
- }
+ fout.print("state", uidState);
synchronized (mUidBlockedState) {
final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (uidBlockedState == null) {
- fout.print(" blocked_state={null}");
- } else {
- fout.print(" blocked_state=");
- fout.print(uidBlockedState);
- }
+ fout.print("blocked_state", uidBlockedState);
+ }
+
+ synchronized (mUidStateCallbackInfos) {
+ final UidStateCallbackInfo callbackInfo = mUidStateCallbackInfos.get(uid);
+ fout.println();
+ fout.increaseIndent();
+ fout.print("callback_info", callbackInfo);
+ fout.decreaseIndent();
}
fout.println();
}
@@ -4052,27 +4067,49 @@
}
@VisibleForTesting
- boolean isUidForeground(int uid) {
- synchronized (mUidRulesFirstLock) {
- return isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid));
+ @GuardedBy("mUidRulesFirstLock")
+ boolean isUidForegroundOnRestrictBackgroundUL(int uid) {
+ final UidState uidState = mUidState.get(uid);
+ if (isProcStateAllowedWhileOnRestrictBackground(uidState)) {
+ return true;
}
+ // Check if there is any pending state change.
+ synchronized (mUidStateCallbackInfos) {
+ final UidStateCallbackInfo callbackInfo = mUidStateCallbackInfos.get(uid);
+ final long prevProcStateSeq = uidState != null ? uidState.procStateSeq : -1;
+ if (callbackInfo != null && callbackInfo.isPending
+ && callbackInfo.procStateSeq >= prevProcStateSeq) {
+ return isProcStateAllowedWhileOnRestrictBackground(callbackInfo.procState,
+ callbackInfo.capability);
+ }
+ }
+ return false;
}
+ @VisibleForTesting
@GuardedBy("mUidRulesFirstLock")
- private boolean isUidForegroundOnRestrictBackgroundUL(int uid) {
+ boolean isUidForegroundOnRestrictPowerUL(int uid) {
final UidState uidState = mUidState.get(uid);
- return isProcStateAllowedWhileOnRestrictBackground(uidState);
- }
-
- @GuardedBy("mUidRulesFirstLock")
- private boolean isUidForegroundOnRestrictPowerUL(int uid) {
- final UidState uidState = mUidState.get(uid);
- return isProcStateAllowedWhileIdleOrPowerSaveMode(uidState);
+ if (isProcStateAllowedWhileIdleOrPowerSaveMode(uidState)) {
+ return true;
+ }
+ // Check if there is any pending state change.
+ synchronized (mUidStateCallbackInfos) {
+ final UidStateCallbackInfo callbackInfo = mUidStateCallbackInfos.get(uid);
+ final long prevProcStateSeq = uidState != null ? uidState.procStateSeq : -1;
+ if (callbackInfo != null && callbackInfo.isPending
+ && callbackInfo.procStateSeq >= prevProcStateSeq) {
+ return isProcStateAllowedWhileIdleOrPowerSaveMode(callbackInfo.procState,
+ callbackInfo.capability);
+ }
+ }
+ return false;
}
@GuardedBy("mUidRulesFirstLock")
private boolean isUidTop(int uid) {
final UidState uidState = mUidState.get(uid);
+ // TODO: Consider taking pending uid state change into account.
return isProcStateAllowedWhileInLowPowerStandby(uidState);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0532a79..247a5c0 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2987,6 +2987,7 @@
}
break;
case KeyEvent.KEYCODE_H:
+ case KeyEvent.KEYCODE_ENTER:
if (event.isMetaPressed()) {
return handleHomeShortcuts(displayId, focusedToken, event);
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 8bbcd27..c40d72c 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -807,11 +807,8 @@
if (under != null) {
under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null;
}
- // Create a transition if the activity is playing in case the current activity
- // didn't commit invisible. That's because if this activity has changed its
- // visibility while playing transition, there won't able to commit visibility until
- // the running transition finish.
- final Transition transition = r.mTransitionController.inPlayingTransition(r)
+ // Create a transition to make sure the activity change is collected.
+ final Transition transition = r.mTransitionController.isShellTransitionsEnabled()
&& !r.mTransitionController.isCollecting()
? r.mTransitionController.createTransition(TRANSIT_TO_FRONT) : null;
final boolean changed = r.setOccludesParent(false);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f478e9b..8bfa426 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2267,6 +2267,12 @@
if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
return WmDisplayCutout.NO_CUTOUT;
}
+ if (displayWidth == displayHeight) {
+ Slog.w(TAG, "Ignore cutout because display size is square: " + displayWidth);
+ // Avoid UnsupportedOperationException because DisplayCutout#computeSafeInsets doesn't
+ // support square size.
+ return WmDisplayCutout.NO_CUTOUT;
+ }
if (rotation == ROTATION_0) {
return WmDisplayCutout.computeSafeInsets(
cutout, displayWidth, displayHeight);
@@ -3087,13 +3093,9 @@
mIsSizeForced = mInitialDisplayWidth != width || mInitialDisplayHeight != height;
if (mIsSizeForced) {
- // Set some sort of reasonable bounds on the size of the display that we will try
- // to emulate.
- final int minSize = 200;
- final int maxScale = 3;
- final int maxSize = Math.max(mInitialDisplayWidth, mInitialDisplayHeight) * maxScale;
- width = Math.min(Math.max(width, minSize), maxSize);
- height = Math.min(Math.max(height, minSize), maxSize);
+ final Point size = getValidForcedSize(width, height);
+ width = size.x;
+ height = size.y;
}
Slog.i(TAG_WM, "Using new display size: " + width + "x" + height);
@@ -3108,6 +3110,16 @@
mWmService.mDisplayWindowSettings.setForcedSize(this, width, height);
}
+ /** Returns a reasonable size for setting forced display size. */
+ Point getValidForcedSize(int w, int h) {
+ final int minSize = 200;
+ final int maxScale = 3;
+ final int maxSize = Math.max(mInitialDisplayWidth, mInitialDisplayHeight) * maxScale;
+ w = Math.min(Math.max(w, minSize), maxSize);
+ h = Math.min(Math.max(h, minSize), maxSize);
+ return new Point(w, h);
+ }
+
DisplayCutout loadDisplayCutout(int displayWidth, int displayHeight) {
if (mDisplayPolicy == null || mInitialDisplayCutout == null) {
return null;
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 20048ce..a5e652c 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -946,6 +946,10 @@
}
void freezeRotation(int rotation) {
+ if (mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()) {
+ rotation = RotationUtils.reverseRotationDirectionAroundZAxis(rotation);
+ }
+
rotation = (rotation == -1) ? mRotation : rotation;
setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation);
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index b314ed1..54dfdd9 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -107,6 +107,11 @@
* Represents a logical transition. This keeps track of all the changes associated with a logical
* WM state -> state transition.
* @see TransitionController
+ *
+ * In addition to tracking individual container changes, this also tracks ordering-changes (just
+ * on-top for now). However, since order is a "global" property, the mechanics of order-change
+ * detection/reporting is non-trivial when transitions are collecting in parallel. See
+ * {@link #collectOrderChanges} for more details.
*/
class Transition implements BLASTSyncEngine.TransactionReadyListener {
private static final String TAG = "Transition";
@@ -192,6 +197,12 @@
private final ArrayList<Task> mOnTopTasksStart = new ArrayList<>();
/**
+ * The (non alwaysOnTop) tasks which were on-top of their display when this transition became
+ * ready (via setReady, not animation-ready).
+ */
+ private final ArrayList<Task> mOnTopTasksAtReady = new ArrayList<>();
+
+ /**
* Set of participating windowtokens (activity/wallpaper) which are visible at the end of
* the transition animation.
*/
@@ -244,6 +255,36 @@
*/
boolean mIsPlayerEnabled = true;
+ /** This transition doesn't run in parallel. */
+ static final int PARALLEL_TYPE_NONE = 0;
+
+ /** Any 2 transitions of this type can run in parallel with each other. Used for testing. */
+ static final int PARALLEL_TYPE_MUTUAL = 1;
+
+ @IntDef(prefix = { "PARALLEL_TYPE_" }, value = {
+ PARALLEL_TYPE_NONE,
+ PARALLEL_TYPE_MUTUAL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface ParallelType {}
+
+ /**
+ * What category of parallel-collect support this transition has. The value of this is used
+ * by {@link TransitionController} to determine which transitions can collect in parallel. If
+ * a transition can collect in parallel, it means that it will start collecting as soon as the
+ * prior collecting transition is {@link #isPopulated}. This is a shortcut for supporting
+ * a couple specific situations before we have full-fledged support for parallel transitions.
+ */
+ @ParallelType int mParallelCollectType = PARALLEL_TYPE_NONE;
+
+ /**
+ * A "Track" is a set of animations which must cooperate with each other to play smoothly. If
+ * animations can play independently of each other, then they can be in different tracks. If
+ * a transition must cooperate with transitions in >1 other track, then it must be marked
+ * FLAG_SYNC and it will end-up flushing all animations before it starts.
+ */
+ int mAnimationTrack = 0;
+
Transition(@TransitionType int type, @TransitionFlags int flags,
TransitionController controller, BLASTSyncEngine syncEngine) {
mType = type;
@@ -447,7 +488,8 @@
throw new IllegalStateException("Attempting to re-use a transition");
}
mState = STATE_COLLECTING;
- mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG, false /* parallel */);
+ mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG,
+ mParallelCollectType != PARALLEL_TYPE_NONE);
mSyncEngine.setSyncMethod(mSyncId, TransitionController.SYNC_METHOD);
mLogger.mSyncId = mSyncId;
@@ -718,8 +760,15 @@
final boolean ready = mReadyTracker.allReady();
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
"Set transition ready=%b %d", ready, mSyncId);
- mSyncEngine.setReady(mSyncId, ready);
- if (ready) mLogger.mReadyTimeNs = SystemClock.elapsedRealtimeNanos();
+ boolean changed = mSyncEngine.setReady(mSyncId, ready);
+ if (changed && ready) {
+ mLogger.mReadyTimeNs = SystemClock.elapsedRealtimeNanos();
+ mOnTopTasksAtReady.clear();
+ for (int i = 0; i < mTargetDisplays.size(); ++i) {
+ addOnTopTasks(mTargetDisplays.get(i), mOnTopTasksAtReady);
+ }
+ mController.onTransitionPopulated(this);
+ }
}
/**
@@ -737,6 +786,11 @@
return mReadyTracker.allReady();
}
+ /** This transition has all of its expected participants. */
+ boolean isPopulated() {
+ return mState >= STATE_STARTED && mReadyTracker.allReady();
+ }
+
/**
* Build a transaction that "resets" all the re-parenting and layer changes. This is
* intended to be applied at the end of the transition but before the finish callback. This
@@ -1211,7 +1265,7 @@
: mController.mAtm.mRootWindowContainer.getDefaultDisplay();
if (mState == STATE_ABORT) {
- mController.abort(this);
+ mController.onAbort(this);
primaryDisplay.getPendingTransaction().merge(transaction);
mSyncId = -1;
mOverrideOptions = null;
@@ -1222,13 +1276,15 @@
mState = STATE_PLAYING;
mStartTransaction = transaction;
mFinishTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get();
- mController.moveToPlaying(this);
// Flags must be assigned before calculateTransitionInfo. Otherwise it won't take effect.
if (primaryDisplay.isKeyguardLocked()) {
mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED;
}
- collectOrderChanges();
+
+ // This is the only (or last) transition that is collecting, so we need to report any
+ // leftover order changes.
+ collectOrderChanges(mController.mWaitingTransitions.isEmpty());
// Resolve the animating targets from the participants.
mTargets = calculateTargets(mParticipants, mChanges);
@@ -1236,6 +1292,9 @@
mController.mAtm.mBackNavigationController.onTransactionReady(this, mTargets);
final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction);
info.setDebugId(mSyncId);
+ mController.assignTrack(this, info);
+
+ mController.moveToPlaying(this);
// Repopulate the displays based on the resolved targets.
mTargetDisplays.clear();
@@ -1383,24 +1442,70 @@
info.releaseAnimSurfaces();
}
- /** Collect tasks which moved-to-top but didn't change otherwise. */
+ /**
+ * Collect tasks which moved-to-top as part of this transition. This also updates the
+ * controller's latest-reported when relevant.
+ *
+ * This is a non-trivial operation because transition can collect in parallel; however, it can
+ * be made tenable by acknowledging that the "setup" part of collection (phase 1) is still
+ * globally serial; so, we can build some reasonable rules around it.
+ *
+ * First, we record the "start" on-top state (to compare against). Then, when this becomes
+ * ready (via allReady, NOT onTransactionReady), we also record the "onReady" on-top state
+ * -- the idea here is that upon "allReady", all the actual WM changes should be done and we
+ * are now just waiting for window content to become ready (finish drawing).
+ *
+ * Then, in this function (during onTransactionReady), we compare the two orders and include
+ * any changes to the order in the reported transition-info. Unfortunately, because of parallel
+ * collection, the order can change in unexpected ways by now. To resolve this, we ALSO keep a
+ * global "latest reported order" in TransitionController and use that to make decisions.
+ */
@VisibleForTesting
- void collectOrderChanges() {
+ void collectOrderChanges(boolean reportCurrent) {
if (mOnTopTasksStart.isEmpty()) return;
- final ArrayList<Task> onTopTasksEnd = new ArrayList<>();
- for (int i = 0; i < mTargetDisplays.size(); ++i) {
- addOnTopTasks(mTargetDisplays.get(i), onTopTasksEnd);
- }
- for (int i = 0; i < onTopTasksEnd.size(); ++i) {
- final Task task = onTopTasksEnd.get(i);
+ boolean includesOrderChange = false;
+ for (int i = 0; i < mOnTopTasksAtReady.size(); ++i) {
+ final Task task = mOnTopTasksAtReady.get(i);
if (mOnTopTasksStart.contains(task)) continue;
- mParticipants.add(task);
- int changeIdx = mChanges.indexOfKey(task);
- if (changeIdx < 0) {
- mChanges.put(task, new ChangeInfo(task));
- changeIdx = mChanges.indexOfKey(task);
+ includesOrderChange = true;
+ break;
+ }
+ if (!includesOrderChange && !reportCurrent) {
+ // This transition doesn't include an order change, so if it isn't required to report
+ // the current focus (eg. it's the last of a cluster of transitions), then don't
+ // report.
+ return;
+ }
+ // The transition included an order change, but it may not be up-to-date, so grab the
+ // latest state and compare with the last reported state (or our start state if no
+ // reported state exists).
+ ArrayList<Task> onTopTasksEnd = new ArrayList<>();
+ for (int d = 0; d < mTargetDisplays.size(); ++d) {
+ addOnTopTasks(mTargetDisplays.get(d), onTopTasksEnd);
+ final int displayId = mTargetDisplays.get(d).mDisplayId;
+ ArrayList<Task> reportedOnTop = mController.mLatestOnTopTasksReported.get(displayId);
+ for (int i = onTopTasksEnd.size() - 1; i >= 0; --i) {
+ final Task task = onTopTasksEnd.get(i);
+ if (task.getDisplayId() != displayId) continue;
+ // If it didn't change since last report, don't report
+ if (reportedOnTop == null) {
+ if (mOnTopTasksStart.contains(task)) continue;
+ } else if (reportedOnTop.contains(task)) {
+ continue;
+ }
+ // Need to report it.
+ mParticipants.add(task);
+ int changeIdx = mChanges.indexOfKey(task);
+ if (changeIdx < 0) {
+ mChanges.put(task, new ChangeInfo(task));
+ changeIdx = mChanges.indexOfKey(task);
+ }
+ mChanges.valueAt(changeIdx).mFlags |= ChangeInfo.FLAG_CHANGE_MOVED_TO_TOP;
}
- mChanges.valueAt(changeIdx).mFlags |= ChangeInfo.FLAG_CHANGE_MOVED_TO_TOP;
+ // Swap in the latest on-top tasks.
+ mController.mLatestOnTopTasksReported.put(displayId, onTopTasksEnd);
+ onTopTasksEnd = reportedOnTop != null ? reportedOnTop : new ArrayList<>();
+ onTopTasksEnd.clear();
}
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index e8e4792..8af037b 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -39,6 +39,7 @@
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
@@ -60,7 +61,34 @@
import java.util.function.LongConsumer;
/**
- * Handles all the aspects of recording and synchronizing transitions.
+ * Handles all the aspects of recording (collecting) and synchronizing transitions. This is only
+ * concerned with the WM changes. The actual animations are handled by the Player.
+ *
+ * Currently, only 1 transition can be the primary "collector" at a time. This is because WM changes
+ * are still performed in a "global" manner. However, collecting can actually be broken into
+ * two phases:
+ * 1. Actually making WM changes and recording the participating containers.
+ * 2. Waiting for the participating containers to become ready (eg. redrawing content).
+ * Because (2) takes most of the time AND doesn't change WM, we can actually have multiple
+ * transitions in phase (2) concurrently with one in phase (1). We refer to this arrangement as
+ * "parallel" collection even though there is still only ever 1 transition actually able to gain
+ * participants.
+ *
+ * Parallel collection happens when the "primary collector" has finished "setup" (phase 1) and is
+ * just waiting. At this point, another transition can start collecting. When this happens, the
+ * first transition is moved to a "waiting" list and the new transition becomes the "primary
+ * collector". If at any time, the "primary collector" moves to playing before one of the waiting
+ * transitions, then the first waiting transition will move back to being the "primary collector".
+ * This maintains the "global"-like abstraction that the rest of WM currently expects.
+ *
+ * When a transition move-to-playing, we check it against all other playing transitions. If it
+ * doesn't overlap with them, it can also animate in parallel. In this case it will be assigned a
+ * new "track". "tracks" are a way to communicate to the player about which transitions need to be
+ * played serially with each-other. So, if we find that a transition overlaps with other transitions
+ * in one track, the transition will be assigned to that track. If, however, the transition overlaps
+ * with transition in >1 track, we will actually just mark it as SYNC meaning it can't actually
+ * play until all prior transition animations finish. This is heavy-handed because it is a fallback
+ * situation and supporting something fancier would be unnecessarily complicated.
*/
class TransitionController {
private static final String TAG = "TransitionController";
@@ -109,6 +137,7 @@
* removed from this list.
*/
private final ArrayList<Transition> mPlayingTransitions = new ArrayList<>();
+ int mTrackCount = 0;
/** The currently finishing transition. */
Transition mFinishingTransition;
@@ -143,10 +172,26 @@
private final ArrayList<QueuedTransition> mQueuedTransitions = new ArrayList<>();
- /** The transition currently being constructed (collecting participants). */
+ /**
+ * The transition currently being constructed (collecting participants). Unless interrupted,
+ * all WM changes will go into this.
+ */
private Transition mCollectingTransition = null;
/**
+ * The transitions that are complete but still waiting for participants to become ready
+ */
+ final ArrayList<Transition> mWaitingTransitions = new ArrayList<>();
+
+ /**
+ * The (non alwaysOnTop) tasks which were reported as on-top of their display most recently
+ * within a cluster of simultaneous transitions. If tasks are nested, all the tasks that are
+ * parents of the on-top task are also included. This is used to decide which transitions
+ * report which on-top changes.
+ */
+ final SparseArray<ArrayList<Task>> mLatestOnTopTasksReported = new SparseArray<>();
+
+ /**
* `true` when building surface layer order for the finish transaction. We want to prevent
* wm from touching z-order of surfaces during transitions, but we still need to be able to
* calculate the layers for the finishTransaction. So, when assigning layers into the finish
@@ -199,6 +244,11 @@
mPlayingTransitions.get(i).cleanUpOnFailure();
}
mPlayingTransitions.clear();
+ // Clean up waiting transitions first since they technically started first.
+ for (int i = 0; i < mWaitingTransitions.size(); ++i) {
+ mWaitingTransitions.get(i).abort();
+ }
+ mWaitingTransitions.clear();
if (mCollectingTransition != null) {
mCollectingTransition.abort();
}
@@ -223,8 +273,9 @@
throw new IllegalStateException("Shell Transitions not enabled");
}
if (mCollectingTransition != null) {
- throw new IllegalStateException("Simultaneous transition collection not supported"
- + " yet. Use {@link #createPendingTransition} for explicit queueing.");
+ throw new IllegalStateException("Trying to directly start transition collection while "
+ + " collection is already ongoing. Use {@link #startCollectOrQueue} if"
+ + " possible.");
}
Transition transit = new Transition(type, flags, this, mSyncEngine);
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Creating Transition: %s", transit);
@@ -318,7 +369,12 @@
* This is {@code false} once a transition is playing.
*/
boolean isCollecting(@NonNull WindowContainer wc) {
- return mCollectingTransition != null && mCollectingTransition.mParticipants.contains(wc);
+ if (mCollectingTransition == null) return false;
+ if (mCollectingTransition.mParticipants.contains(wc)) return true;
+ for (int i = 0; i < mWaitingTransitions.size(); ++i) {
+ if (mWaitingTransitions.get(i).mParticipants.contains(wc)) return true;
+ }
+ return false;
}
/**
@@ -327,7 +383,11 @@
*/
boolean inCollectingTransition(@NonNull WindowContainer wc) {
if (!isCollecting()) return false;
- return mCollectingTransition.isInTransition(wc);
+ if (mCollectingTransition.isInTransition(wc)) return true;
+ for (int i = 0; i < mWaitingTransitions.size(); ++i) {
+ if (mWaitingTransitions.get(i).isInTransition(wc)) return true;
+ }
+ return false;
}
/**
@@ -369,6 +429,9 @@
if (mCollectingTransition != null && mCollectingTransition.isOnDisplay(dc)) {
return true;
}
+ for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) {
+ if (mWaitingTransitions.get(i).isOnDisplay(dc)) return true;
+ }
for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
if (mPlayingTransitions.get(i).isOnDisplay(dc)) return true;
}
@@ -379,6 +442,9 @@
if (mCollectingTransition != null && mCollectingTransition.isInTransientHide(task)) {
return true;
}
+ for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) {
+ if (mWaitingTransitions.get(i).isInTransientHide(task)) return true;
+ }
for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
if (mPlayingTransitions.get(i).isInTransientHide(task)) return true;
}
@@ -754,6 +820,8 @@
mRunningLock.doNotifyLocked();
// Run state-validation checks when no transitions are active anymore.
if (!inTransition()) {
+ // Can reset track-count now that everything is idle.
+ mTrackCount = 0;
validateStates();
}
}
@@ -771,12 +839,39 @@
mStateValidators.clear();
}
+ /**
+ * Called when the transition has a complete set of participants for its operation. In other
+ * words, it is when the transition is "ready" but is still waiting for participants to draw.
+ */
+ void onTransitionPopulated(Transition transition) {
+ tryStartCollectFromQueue();
+ }
+
+ private boolean canStartCollectingNow(Transition queued) {
+ if (mCollectingTransition == null) return true;
+ // Population (collect until ready) is still serialized, so always wait for that.
+ if (!mCollectingTransition.isPopulated()) return false;
+ // Check if queued *can* be independent with all collecting/waiting transitions.
+ if (!getCanBeIndependent(mCollectingTransition, queued)) return false;
+ for (int i = 0; i < mWaitingTransitions.size(); ++i) {
+ if (!getCanBeIndependent(mWaitingTransitions.get(i), queued)) return false;
+ }
+ return true;
+ }
+
void tryStartCollectFromQueue() {
if (mQueuedTransitions.isEmpty()) return;
// Only need to try the next one since, even when transition can collect in parallel,
// they still need to serialize on readiness.
final QueuedTransition queued = mQueuedTransitions.get(0);
- if (mCollectingTransition != null || mSyncEngine.hasActiveSync()) {
+ if (mCollectingTransition != null) {
+ // If it's a legacy sync, then it needs to wait until there is no collecting transition.
+ if (queued.mTransition == null) return;
+ if (!canStartCollectingNow(queued.mTransition)) return;
+ mWaitingTransitions.add(mCollectingTransition);
+ mCollectingTransition = null;
+ } else if (mSyncEngine.hasActiveSync()) {
+ // A legacy transition is on-going, so we must wait.
return;
}
mQueuedTransitions.remove(0);
@@ -797,16 +892,81 @@
}
void moveToPlaying(Transition transition) {
- if (transition != mCollectingTransition) {
- throw new IllegalStateException("Trying to move non-collecting transition to playing");
+ if (transition == mCollectingTransition) {
+ mCollectingTransition = null;
+ if (!mWaitingTransitions.isEmpty()) {
+ mCollectingTransition = mWaitingTransitions.remove(0);
+ }
+ if (mCollectingTransition == null) {
+ // nothing collecting anymore, so clear order records.
+ mLatestOnTopTasksReported.clear();
+ }
+ } else {
+ if (!mWaitingTransitions.remove(transition)) {
+ throw new IllegalStateException("Trying to move non-collecting transition to"
+ + "playing " + transition.getSyncId());
+ }
}
- mCollectingTransition = null;
mPlayingTransitions.add(transition);
updateRunningRemoteAnimation(transition, true /* isPlaying */);
mTransitionTracer.logState(transition);
// Sync engine should become idle after this, so the idle listener will check the queue.
}
+ /**
+ * Checks if the `queued` transition has the potential to run independently of the
+ * `collecting` transition. It may still ultimately block in sync-engine or become dependent
+ * in {@link #getIsIndependent} later.
+ */
+ boolean getCanBeIndependent(Transition collecting, Transition queued) {
+ if (queued.mParallelCollectType == Transition.PARALLEL_TYPE_MUTUAL
+ && collecting.mParallelCollectType == Transition.PARALLEL_TYPE_MUTUAL) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Checks if `incoming` transition can run independently of `running` transition assuming that
+ * `running` is playing based on its current state.
+ */
+ static boolean getIsIndependent(Transition running, Transition incoming) {
+ if (running.mParallelCollectType == Transition.PARALLEL_TYPE_MUTUAL
+ && incoming.mParallelCollectType == Transition.PARALLEL_TYPE_MUTUAL) {
+ return true;
+ }
+ return false;
+ }
+
+ void assignTrack(Transition transition, TransitionInfo info) {
+ int track = -1;
+ boolean sync = false;
+ for (int i = 0; i < mPlayingTransitions.size(); ++i) {
+ // ignore ourself obviously
+ if (mPlayingTransitions.get(i) == transition) continue;
+ if (getIsIndependent(mPlayingTransitions.get(i), transition)) continue;
+ if (track >= 0) {
+ // At this point, transition overlaps with multiple tracks, so just wait for
+ // everything
+ sync = true;
+ break;
+ }
+ track = mPlayingTransitions.get(i).mAnimationTrack;
+ }
+ if (sync) {
+ track = 0;
+ }
+ if (track < 0) {
+ // Didn't overlap with anything, so give it its own track
+ track = mTrackCount;
+ }
+ if (sync) {
+ info.setFlags(info.getFlags() | TransitionInfo.FLAG_SYNC);
+ }
+ info.setTrack(track);
+ mTrackCount = Math.max(mTrackCount, track + 1);
+ }
+
void updateAnimatingState(SurfaceControl.Transaction t) {
final boolean animatingState = !mPlayingTransitions.isEmpty()
|| (mCollectingTransition != null && mCollectingTransition.isStarted());
@@ -842,14 +1002,27 @@
mRemotePlayer.update(delegate, isPlaying, true /* predict */);
}
- void abort(Transition transition) {
+ /** Called when a transition is aborted. This should only be called by {@link Transition} */
+ void onAbort(Transition transition) {
if (transition != mCollectingTransition) {
- throw new IllegalStateException("Too late to abort.");
+ int waitingIdx = mWaitingTransitions.indexOf(transition);
+ if (waitingIdx < 0) {
+ throw new IllegalStateException("Too late for abort.");
+ }
+ mWaitingTransitions.remove(waitingIdx);
+ } else {
+ mCollectingTransition = null;
+ if (!mWaitingTransitions.isEmpty()) {
+ mCollectingTransition = mWaitingTransitions.remove(0);
+ }
+ if (mCollectingTransition == null) {
+ // nothing collecting anymore, so clear order records.
+ mLatestOnTopTasksReported.clear();
+ }
}
- transition.abort();
- mCollectingTransition = null;
mTransitionTracer.logState(transition);
- // abort will call through the normal finish paths and thus check the queue.
+ // This is called during Transition.abort whose codepath will eventually check the queue
+ // via sync-engine idle.
}
/**
@@ -956,7 +1129,17 @@
return false;
}
if (mSyncEngine.hasActiveSync()) {
- if (!isCollecting()) {
+ if (isCollecting()) {
+ // Check if we can run in parallel here.
+ if (canStartCollectingNow(transit)) {
+ // start running in parallel.
+ mWaitingTransitions.add(mCollectingTransition);
+ mCollectingTransition = null;
+ moveToCollecting(transit);
+ onStartCollect.onCollectStarted(false /* deferred */);
+ return true;
+ }
+ } else {
Slog.w(TAG, "Ongoing Sync outside of transition.");
}
queueTransition(transit, onStartCollect);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8822193..40b8274 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5780,10 +5780,12 @@
if (sizeStr != null && sizeStr.length() > 0) {
final int pos = sizeStr.indexOf(',');
if (pos > 0 && sizeStr.lastIndexOf(',') == pos) {
- int width, height;
try {
- width = Integer.parseInt(sizeStr.substring(0, pos));
- height = Integer.parseInt(sizeStr.substring(pos + 1));
+ final Point size = displayContent.getValidForcedSize(
+ Integer.parseInt(sizeStr.substring(0, pos)),
+ Integer.parseInt(sizeStr.substring(pos + 1)));
+ final int width = size.x;
+ final int height = size.y;
if (displayContent.mBaseDisplayWidth != width
|| displayContent.mBaseDisplayHeight != height) {
ProtoLog.i(WM_ERROR, "FORCED DISPLAY SIZE: %dx%d", width, height);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f6bc93a..40024f1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3575,7 +3575,9 @@
void handleStartUser(int userId) {
synchronized (getLockObject()) {
pushScreenCapturePolicy(userId);
- pushUserControlDisabledPackagesLocked(userId);
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
+ pushUserControlDisabledPackagesLocked(userId);
+ }
}
pushUserRestrictions(userId);
// When system user is started (device boot), load cache for all users.
@@ -6038,7 +6040,7 @@
@Override
public void lockNow(int flags, String callerPackageName, boolean parent) {
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(callerPackageName);
} else {
caller = getCallerIdentity();
@@ -6050,7 +6052,7 @@
ActiveAdmin admin;
// Make sure the caller has any active admin with the right policy or
// the required permission.
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
admin = enforcePermissionAndGetEnforcingAdmin(
/* admin= */ null,
/* permission= */ MANAGE_DEVICE_POLICY_LOCK,
@@ -7513,6 +7515,7 @@
boolean success = false;
try {
if (getCurrentForegroundUserId() == userId) {
+ // TODO: We need to special case headless here as we can't switch to the system user
mInjector.getIActivityManager().switchUser(UserHandle.USER_SYSTEM);
}
@@ -7520,7 +7523,8 @@
if (!success) {
Slogf.w(LOG_TAG, "Couldn't remove user " + userId);
} else if (isManagedProfile(userId) && !wipeSilently) {
- sendWipeProfileNotification(wipeReasonForUser);
+ sendWipeProfileNotification(wipeReasonForUser,
+ UserHandle.of(getProfileParentId(userId)));
}
} catch (RemoteException re) {
// Shouldn't happen
@@ -7868,7 +7872,7 @@
});
}
- private void sendWipeProfileNotification(String wipeReasonForUser) {
+ private void sendWipeProfileNotification(String wipeReasonForUser, UserHandle user) {
Notification notification =
new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
.setSmallIcon(android.R.drawable.stat_sys_warning)
@@ -7877,7 +7881,8 @@
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setStyle(new Notification.BigTextStyle().bigText(wipeReasonForUser))
.build();
- mInjector.getNotificationManager().notify(SystemMessage.NOTE_PROFILE_WIPED, notification);
+ mInjector.getNotificationManager().notifyAsUser(
+ /* tag= */ null, SystemMessage.NOTE_PROFILE_WIPED, notification, user);
}
private String getWorkProfileDeletedTitle() {
@@ -8901,13 +8906,13 @@
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
// The effect of this policy is device-wide.
enforcePermission(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
} else {
@@ -8935,13 +8940,13 @@
return false;
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
enforceCanQuery(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
} else {
Objects.requireNonNull(who, "ComponentName is null");
@@ -8970,7 +8975,7 @@
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
// The effect of this policy is device-wide.
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
@@ -9010,13 +9015,13 @@
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
// The effect of this policy is device-wide.
enforceCanQuery(SET_TIME_ZONE, caller.getPackageName(), UserHandle.USER_ALL);
} else {
@@ -9319,7 +9324,7 @@
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
@@ -9329,7 +9334,7 @@
final int userHandle = caller.getUserId();
int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
synchronized (getLockObject()) {
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
// SUPPORT USES_POLICY_DISABLE_KEYGUARD_FEATURES
EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(
who, MANAGE_DEVICE_POLICY_KEYGUARD, caller.getPackageName(),
@@ -9408,7 +9413,7 @@
synchronized (getLockObject()) {
if (who != null) {
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin admin = getEnforcingAdminForCaller(
who, who.getPackageName());
Integer features = mDevicePolicyEngine.getLocalPolicySetByAdmin(
@@ -9422,7 +9427,7 @@
}
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
Integer features = mDevicePolicyEngine.getResolvedPolicy(
PolicyDefinition.KEYGUARD_DISABLED_FEATURES,
affectedUserId);
@@ -10062,7 +10067,9 @@
setNetworkLoggingActiveInternal(false);
deleteTransferOwnershipBundleLocked(userId);
toggleBackupServiceActive(UserHandle.USER_SYSTEM, true);
- pushUserControlDisabledPackagesLocked(userId);
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
+ pushUserControlDisabledPackagesLocked(userId);
+ }
setGlobalSettingDeviceOwnerType(DEVICE_OWNER_TYPE_DEFAULT);
if (isPolicyEngineForFinanceFlagEnabled() || isPermissionCheckFlagEnabled()) {
@@ -11617,7 +11624,7 @@
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_APPLICATION_RESTRICTIONS);
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
@@ -12993,7 +13000,7 @@
String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
@@ -13063,7 +13070,7 @@
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
ActiveAdmin admin;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_PACKAGE_STATE,
@@ -13160,7 +13167,7 @@
public boolean isPackageSuspended(ComponentName who, String callerPackage, String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
enforcePermission(
MANAGE_DEVICE_POLICY_PACKAGE_STATE,
caller.getPackageName(),
@@ -13376,7 +13383,7 @@
throw new IllegalStateException("Feature flag is not enabled.");
}
if (isDeviceOwner(caller) || isProfileOwner(caller)) {
- throw new IllegalStateException("Admins are not allowed to call this API.");
+ throw new SecurityException("Admins are not allowed to call this API.");
}
if (!mInjector.isChangeEnabled(
ENABLE_COEXISTENCE_CHANGE, callerPackage, caller.getUserId())) {
@@ -13766,7 +13773,7 @@
boolean hidden, boolean parent) {
CallerIdentity caller = getCallerIdentity(who, callerPackage);
final int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
// TODO: We need to ensure the delegate with DELEGATION_PACKAGE_ACCESS can do this
enforcePermission(MANAGE_DEVICE_POLICY_PACKAGE_STATE, caller.getPackageName(), userId);
} else {
@@ -13785,7 +13792,7 @@
boolean result;
synchronized (getLockObject()) {
if (parent) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(
caller.getUserId()) && isManagedProfile(caller.getUserId()));
@@ -13802,7 +13809,7 @@
Slogf.v(LOG_TAG, "calling pm.setApplicationHiddenSettingAsUser(%s, %b, %d)",
packageName, hidden, userId);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin admin = getEnforcingAdminForCaller(who, callerPackage);
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.APPLICATION_HIDDEN(packageName),
@@ -13841,7 +13848,7 @@
String packageName, boolean parent) {
CallerIdentity caller = getCallerIdentity(who, callerPackage);
int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
// TODO: Also support DELEGATION_PACKAGE_ACCESS
enforcePermission(MANAGE_DEVICE_POLICY_PACKAGE_STATE, caller.getPackageName(), userId);
} else {
@@ -13853,7 +13860,7 @@
synchronized (getLockObject()) {
if (parent) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId())
&& isManagedProfile(caller.getUserId()));
@@ -14042,13 +14049,13 @@
return;
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
synchronized (getLockObject()) {
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
int affectedUser = getAffectedUser(parent);
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
@@ -14111,7 +14118,7 @@
CallerIdentity caller;
Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
final ArraySet<String> resultSet = new ArraySet<>();
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
int affectedUser = parent ? getProfileParentId(userId) : userId;
caller = getCallerIdentity(callerPackageName);
if (!hasPermission(MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
@@ -14744,24 +14751,24 @@
synchronized (getLockObject()) {
enforcingAdmin = enforceCanCallLockTaskLocked(who, caller.getPackageName());
}
- if (packages.length == 0) {
+ LockTaskPolicy currentPolicy = mDevicePolicyEngine.getLocalPolicySetByAdmin(
+ PolicyDefinition.LOCK_TASK,
+ enforcingAdmin,
+ caller.getUserId());
+ LockTaskPolicy policy;
+ if (currentPolicy == null) {
+ policy = new LockTaskPolicy(Set.of(packages));
+ } else {
+ policy = new LockTaskPolicy(currentPolicy);
+ policy.setPackages(Set.of(packages));
+ }
+ if (policy.getPackages().isEmpty()
+ && policy.getFlags() == DevicePolicyManager.LOCK_TASK_FEATURE_NONE) {
mDevicePolicyEngine.removeLocalPolicy(
PolicyDefinition.LOCK_TASK,
enforcingAdmin,
caller.getUserId());
} else {
- LockTaskPolicy currentPolicy = mDevicePolicyEngine.getLocalPolicySetByAdmin(
- PolicyDefinition.LOCK_TASK,
- enforcingAdmin,
- caller.getUserId());
- LockTaskPolicy policy;
- if (currentPolicy == null) {
- policy = new LockTaskPolicy(Set.of(packages));
- } else {
- policy = new LockTaskPolicy(currentPolicy);
- policy.setPackages(Set.of(packages));
- }
-
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.LOCK_TASK,
enforcingAdmin,
@@ -14876,18 +14883,26 @@
PolicyDefinition.LOCK_TASK,
enforcingAdmin,
caller.getUserId());
+ LockTaskPolicy policy;
if (currentPolicy == null) {
- throw new IllegalArgumentException("Can't set a lock task flags without setting "
- + "lock task packages first.");
+ policy = new LockTaskPolicy(flags);
+ } else {
+ policy = new LockTaskPolicy(currentPolicy);
+ policy.setFlags(flags);
}
- LockTaskPolicy policy = new LockTaskPolicy(currentPolicy);
- policy.setFlags(flags);
-
- mDevicePolicyEngine.setLocalPolicy(
- PolicyDefinition.LOCK_TASK,
- enforcingAdmin,
- policy,
- caller.getUserId());
+ if (policy.getPackages().isEmpty()
+ && policy.getFlags() == DevicePolicyManager.LOCK_TASK_FEATURE_NONE) {
+ mDevicePolicyEngine.removeLocalPolicy(
+ PolicyDefinition.LOCK_TASK,
+ enforcingAdmin,
+ caller.getUserId());
+ } else {
+ mDevicePolicyEngine.setLocalPolicy(
+ PolicyDefinition.LOCK_TASK,
+ enforcingAdmin,
+ policy,
+ caller.getUserId());
+ }
} else {
Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
@@ -14945,18 +14960,34 @@
continue;
}
- final List<String> lockTaskPackages = getUserData(userId).mLockTaskPackages;
- // TODO(b/278438525): handle in the policy engine
- if (!lockTaskPackages.isEmpty()) {
- Slogf.d(LOG_TAG,
- "User id " + userId + " not affiliated. Clearing lock task packages");
- setLockTaskPackagesLocked(userId, Collections.<String>emptyList());
- }
- final int lockTaskFeatures = getUserData(userId).mLockTaskFeatures;
- if (lockTaskFeatures != DevicePolicyManager.LOCK_TASK_FEATURE_NONE){
- Slogf.d(LOG_TAG,
- "User id " + userId + " not affiliated. Clearing lock task features");
- setLockTaskFeaturesLocked(userId, DevicePolicyManager.LOCK_TASK_FEATURE_NONE);
+ if (isPolicyEngineForFinanceFlagEnabled()) {
+ Map<EnforcingAdmin, PolicyValue<LockTaskPolicy>> policies =
+ mDevicePolicyEngine.getLocalPoliciesSetByAdmins(
+ PolicyDefinition.LOCK_TASK, userId);
+ Set<EnforcingAdmin> admins = new HashSet<>(policies.keySet());
+ for (EnforcingAdmin admin : admins) {
+ if (admin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) {
+ mDevicePolicyEngine.removeLocalPolicy(
+ PolicyDefinition.LOCK_TASK, admin, userId);
+ }
+ }
+ } else {
+ final List<String> lockTaskPackages = getUserData(userId).mLockTaskPackages;
+ // TODO(b/278438525): handle in the policy engine
+ if (!lockTaskPackages.isEmpty()) {
+ Slogf.d(LOG_TAG,
+ "User id " + userId
+ + " not affiliated. Clearing lock task packages");
+ setLockTaskPackagesLocked(userId, Collections.<String>emptyList());
+ }
+ final int lockTaskFeatures = getUserData(userId).mLockTaskFeatures;
+ if (lockTaskFeatures != DevicePolicyManager.LOCK_TASK_FEATURE_NONE) {
+ Slogf.d(LOG_TAG,
+ "User id " + userId
+ + " not affiliated. Clearing lock task features");
+ setLockTaskFeaturesLocked(userId,
+ DevicePolicyManager.LOCK_TASK_FEATURE_NONE);
+ }
}
}
});
@@ -15454,12 +15485,12 @@
public boolean setStatusBarDisabled(ComponentName who, String callerPackageName,
boolean disabled) {
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
enforcePermission(MANAGE_DEVICE_POLICY_STATUS_BAR, caller.getPackageName(),
UserHandle.USER_ALL);
} else {
@@ -15470,7 +15501,7 @@
int userId = caller.getUserId();
synchronized (getLockObject()) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
"Admin " + who + " is neither the device owner or affiliated "
+ "user's profile owner.");
@@ -15529,7 +15560,7 @@
@Override
public boolean isStatusBarDisabled(String callerPackage) {
final CallerIdentity caller = getCallerIdentity(callerPackage);
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
enforceCanQuery(
MANAGE_DEVICE_POLICY_STATUS_BAR, caller.getPackageName(), caller.getUserId());
} else {
@@ -15539,7 +15570,7 @@
int userId = caller.getUserId();
synchronized (getLockObject()) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
"Admin " + callerPackage
+ " is neither the device owner or affiliated user's profile owner.");
@@ -16191,17 +16222,13 @@
deviceOwner.second);
return result;
}
- } else if (DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction)
- || DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction)) {
+ } else if (DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction)) {
synchronized (getLockObject()) {
final DevicePolicyData policy = getUserData(userId);
final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
final ActiveAdmin admin = policy.mAdminList.get(i);
- if ((admin.disableCamera &&
- DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction))
- || (admin.disableScreenCapture && DevicePolicyManager
- .POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction))) {
+ if (admin.disableScreenCapture) {
result = new Bundle();
result.putInt(Intent.EXTRA_USER_ID, userId);
result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
@@ -16209,17 +16236,44 @@
return result;
}
}
- // For the camera, a device owner on a different user can disable it globally,
- // so we need an additional check.
- if (result == null
- && DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction)) {
- final ActiveAdmin admin = getDeviceOwnerAdminLocked();
- if (admin != null && admin.disableCamera) {
- result = new Bundle();
- result.putInt(Intent.EXTRA_USER_ID, mOwners.getDeviceOwnerUserId());
- result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
- admin.info.getComponent());
- return result;
+ }
+ } else if (DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction)) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
+ PolicyDefinition<Boolean> policyDefinition =
+ PolicyDefinition.getPolicyDefinitionForUserRestriction(
+ UserManager.DISALLOW_CAMERA);
+ Boolean value = mDevicePolicyEngine.getResolvedPolicy(policyDefinition, userId);
+ if (value != null && value) {
+ result = new Bundle();
+ result.putInt(Intent.EXTRA_USER_ID, userId);
+ return result;
+ }
+ } else {
+ synchronized (getLockObject()) {
+ final DevicePolicyData policy = getUserData(userId);
+ final int N = policy.mAdminList.size();
+ for (int i = 0; i < N; i++) {
+ final ActiveAdmin admin = policy.mAdminList.get(i);
+ if (admin.disableCamera) {
+ result = new Bundle();
+ result.putInt(Intent.EXTRA_USER_ID, userId);
+ result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
+ admin.info.getComponent());
+ return result;
+ }
+ }
+ // For the camera, a device owner on a different user can disable it globally,
+ // so we need an additional check.
+ if (result == null
+ && DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction)) {
+ final ActiveAdmin admin = getDeviceOwnerAdminLocked();
+ if (admin != null && admin.disableCamera) {
+ result = new Bundle();
+ result.putInt(Intent.EXTRA_USER_ID, mOwners.getDeviceOwnerUserId());
+ result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
+ admin.info.getComponent());
+ return result;
+ }
}
}
}
@@ -16676,7 +16730,7 @@
}
}
EnforcingAdmin enforcingAdmin;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
@@ -16847,7 +16901,7 @@
public int getPermissionGrantState(ComponentName admin, String callerPackage,
String packageName, String permission) throws RemoteException {
final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
enforceCanQuery(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, caller.getPackageName(),
caller.getUserId());
} else {
@@ -16895,6 +16949,7 @@
} else {
granted = PackageManager.PERMISSION_GRANTED;
}
+
}
}
}
@@ -18978,14 +19033,14 @@
throw new IllegalArgumentException("token must be at least 32-byte long");
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
}
final int userId = caller.getUserId();
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19041,7 +19096,7 @@
return false;
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
@@ -19049,7 +19104,7 @@
final int userId = caller.getUserId();
boolean result = false;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19088,14 +19143,14 @@
return false;
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
}
int userId = caller.getUserId();
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19998,6 +20053,7 @@
if (!mHasFeature) {
return;
}
+
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(packageNames, "Package names is null");
final CallerIdentity caller = getCallerIdentity(who);
@@ -20014,9 +20070,12 @@
saveSettingsLocked(caller.getUserId());
}
logSetCrossProfilePackages(who, packageNames);
- final CrossProfileApps crossProfileApps = mContext.getSystemService(CrossProfileApps.class);
+ final CrossProfileApps crossProfileApps =
+ mContext.createContextAsUser(
+ caller.getUserHandle(), /* flags= */ 0)
+ .getSystemService(CrossProfileApps.class);
mInjector.binderWithCleanCallingIdentity(
- () -> crossProfileApps.resetInteractAcrossProfilesAppOps(
+ () -> crossProfileApps.resetInteractAcrossProfilesAppOps(
previousCrossProfilePackages, new HashSet<>(packageNames)));
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java
index 0f6f3c5..20bd2d7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java
@@ -42,10 +42,6 @@
void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer,
@NonNull LockTaskPolicy value) throws IOException {
Objects.requireNonNull(value);
- if (value.getPackages() == null || value.getPackages().isEmpty()) {
- throw new IllegalArgumentException("Error saving LockTaskPolicy to file, lock task "
- + "packages must be present");
- }
serializer.attribute(
/* namespace= */ null,
ATTR_PACKAGES,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 12a8a75..289098e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -26,6 +26,7 @@
import android.app.admin.PackagePolicyKey;
import android.app.admin.PolicyKey;
import android.app.admin.UserRestrictionPolicyKey;
+import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
import android.content.Context;
import android.content.IntentFilter;
@@ -38,6 +39,7 @@
import android.permission.AdminPermissionControlParams;
import android.permission.PermissionControllerManager;
import android.provider.Settings;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.server.LocalServices;
@@ -151,11 +153,15 @@
static boolean setUserControlDisabledPackages(
@Nullable Set<String> packages, int userId) {
- Binder.withCleanCallingIdentity(() ->
- LocalServices.getService(PackageManagerInternal.class)
- .setOwnerProtectedPackages(
- userId,
- packages == null ? null : packages.stream().toList()));
+ Binder.withCleanCallingIdentity(() -> {
+ LocalServices.getService(PackageManagerInternal.class)
+ .setOwnerProtectedPackages(
+ userId,
+ packages == null ? null : packages.stream().toList());
+ LocalServices.getService(UsageStatsManagerInternal.class)
+ .setAdminProtectedPackages(
+ packages == null ? null : new ArraySet(packages), userId);
+ });
return true;
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
index 16406bc..4167c7e 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
@@ -23,8 +23,9 @@
import android.app.ActivityManagerInternal;
import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
-import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Before;
@@ -39,13 +40,14 @@
* Build/Install/Run:
* atest FrameworksServicesTests:ActivityManagerInternalTest
*/
+@Presubmit
+@SmallTest
public class ActivityManagerInternalTest {
private static final int TEST_UID1 = 111;
private static final int TEST_UID2 = 112;
private static final long TEST_PROC_STATE_SEQ1 = 1111;
private static final long TEST_PROC_STATE_SEQ2 = 1112;
- private static final long TEST_PROC_STATE_SEQ3 = 1113;
@Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
@@ -68,7 +70,6 @@
mAmi = mAms.new LocalService();
}
- @MediumTest
@Test
public void testNotifyNetworkPolicyRulesUpdated() throws Exception {
// Check there is no crash when there are no active uid records.
@@ -89,14 +90,6 @@
TEST_PROC_STATE_SEQ1, // lastNetworkUpdateProcStateSeq
TEST_PROC_STATE_SEQ1, // procStateSeq to notify
false); // expectNotify
-
- // Notify that network policy rules are updated for TEST_UID1 with procStateSeq older
- // than it's UidRecord.curProcStateSeq and verify that there is no notify call.
- verifyNetworkUpdatedProcStateSeq(
- TEST_PROC_STATE_SEQ3, // curProcStateSeq
- TEST_PROC_STATE_SEQ1, // lastNetworkUpdateProcStateSeq
- TEST_PROC_STATE_SEQ2, // procStateSeq to notify
- false); // expectNotify
}
private void verifyNetworkUpdatedProcStateSeq(long curProcStateSeq,
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index d85db64b..34b88b0 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1511,6 +1511,7 @@
* Validates that when the device owner is removed, the reset password token is cleared
*/
@Test
+ @Ignore("b/277916462")
public void testClearDeviceOwner_clearResetPasswordToken() throws Exception {
mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
@@ -2601,6 +2602,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetApplicationHiddenWithDO() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -2626,6 +2628,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetApplicationHiddenWithPOOfOrganizationOwnedDevice() throws Exception {
final int MANAGED_PROFILE_USER_ID = CALLER_USER_HANDLE;
final int MANAGED_PROFILE_ADMIN_UID =
@@ -4372,6 +4375,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledModifiesSetting() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -4383,6 +4387,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledWithPOOnUser0() throws Exception {
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
setupProfileOwnerOnUser0();
@@ -4394,6 +4399,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledFailWithPONotOnUser0() throws Exception {
setupProfileOwner();
assertExpectException(SecurityException.class, null,
@@ -4403,6 +4409,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
@@ -5376,6 +5383,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testResetPasswordWithToken() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -5410,6 +5418,7 @@
}
@Test
+ @Ignore("b/277916462")
public void resetPasswordWithToken_NumericPin() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -5430,6 +5439,7 @@
}
@Test
+ @Ignore("b/277916462")
public void resetPasswordWithToken_EmptyPassword() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -7250,6 +7260,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testCanProfileOwnerResetPasswordWhenLocked() throws Exception {
setDeviceEncryptionPerUser();
setupProfileOwner();
@@ -7313,6 +7324,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetAccountTypesWithManagementDisabledOnManagedProfile() throws Exception {
setupProfileOwner();
@@ -7332,6 +7344,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetAccountTypesWithManagementDisabledOnOrgOwnedManagedProfile()
throws Exception {
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
index ff89be7..5ea3029 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
@@ -17,6 +17,8 @@
package com.android.server.display;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -26,6 +28,7 @@
import android.app.PropertyInvalidatedCache;
import android.graphics.Point;
+import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
@@ -47,6 +50,7 @@
private static final int LAYER_STACK = 0;
private static final int DISPLAY_WIDTH = 100;
private static final int DISPLAY_HEIGHT = 200;
+ private static final int MODE_ID = 1;
private LogicalDisplay mLogicalDisplay;
private DisplayDevice mDisplayDevice;
@@ -65,6 +69,9 @@
mDisplayDeviceInfo.height = DISPLAY_HEIGHT;
mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
+ mDisplayDeviceInfo.modeId = MODE_ID;
+ mDisplayDeviceInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, /* refreshRate= */ 60)};
when(mDisplayDevice.getDisplayDeviceInfoLocked()).thenReturn(mDisplayDeviceInfo);
// Disable binder caches in this process.
@@ -168,14 +175,34 @@
}
@Test
- public void testLayoutLimitedRefreshRateNotClearedAfterUpdate() {
- SurfaceControl.RefreshRateRange refreshRateRange = new SurfaceControl.RefreshRateRange(1,
- 2);
- mLogicalDisplay.updateLayoutLimitedRefreshRateLocked(refreshRateRange);
- mLogicalDisplay.updateDisplayGroupIdLocked(1);
+ public void testUpdateLayoutLimitedRefreshRate() {
+ SurfaceControl.RefreshRateRange layoutLimitedRefreshRate =
+ new SurfaceControl.RefreshRateRange(0, 120);
+ DisplayInfo info1 = mLogicalDisplay.getDisplayInfoLocked();
+ mLogicalDisplay.updateLayoutLimitedRefreshRateLocked(layoutLimitedRefreshRate);
+ DisplayInfo info2 = mLogicalDisplay.getDisplayInfoLocked();
+ // Display info should only be updated when updateLocked is called
+ assertEquals(info2, info1);
- DisplayInfo result = mLogicalDisplay.getDisplayInfoLocked();
+ mLogicalDisplay.updateLocked(mDeviceRepo);
+ DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked();
+ assertNotEquals(info3, info2);
+ assertEquals(layoutLimitedRefreshRate, info3.layoutLimitedRefreshRate);
+ }
- assertEquals(refreshRateRange, result.layoutLimitedRefreshRate);
+ @Test
+ public void testUpdateRefreshRateThermalThrottling() {
+ SparseArray<SurfaceControl.RefreshRateRange> refreshRanges = new SparseArray<>();
+ refreshRanges.put(0, new SurfaceControl.RefreshRateRange(0, 120));
+ DisplayInfo info1 = mLogicalDisplay.getDisplayInfoLocked();
+ mLogicalDisplay.updateThermalRefreshRateThrottling(refreshRanges);
+ DisplayInfo info2 = mLogicalDisplay.getDisplayInfoLocked();
+ // Display info should only be updated when updateLocked is called
+ assertEquals(info2, info1);
+
+ mLogicalDisplay.updateLocked(mDeviceRepo);
+ DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked();
+ assertNotEquals(info3, info2);
+ assertTrue(refreshRanges.contentEquals(info3.thermalRefreshRateThrottling));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index 42c1fd9..e492252 100644
--- a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -27,7 +27,7 @@
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
-import static com.android.server.display.mode.DisplayModeDirector.Vote.INVALID_SIZE;
+import static com.android.server.display.mode.Vote.INVALID_SIZE;
import static com.google.common.truth.Truth.assertThat;
@@ -94,7 +94,6 @@
import com.android.server.display.TestUtils;
import com.android.server.display.mode.DisplayModeDirector.BrightnessObserver;
import com.android.server.display.mode.DisplayModeDirector.DesiredDisplayModeSpecs;
-import com.android.server.display.mode.DisplayModeDirector.Vote;
import com.android.server.sensors.SensorManagerInternal;
import com.android.server.sensors.SensorManagerInternal.ProximityActiveListener;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -127,7 +126,8 @@
private static final String TAG = "DisplayModeDirectorTest";
private static final boolean DEBUG = false;
private static final float FLOAT_TOLERANCE = 0.01f;
- private static final int DISPLAY_ID = 0;
+ private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY;
+ private static final int MODE_ID = 1;
private static final float TRANSITION_POINT = 0.763f;
private static final float HBM_TRANSITION_POINT_INVALID = Float.POSITIVE_INFINITY;
@@ -223,8 +223,7 @@
assertThat(modeSpecs.appRequest.render.min).isEqualTo(0f);
assertThat(modeSpecs.appRequest.render.max).isEqualTo(Float.POSITIVE_INFINITY);
- int numPriorities =
- DisplayModeDirector.Vote.MAX_PRIORITY - DisplayModeDirector.Vote.MIN_PRIORITY + 1;
+ int numPriorities = Vote.MAX_PRIORITY - Vote.MIN_PRIORITY + 1;
// Ensure vote priority works as expected. As we add new votes with higher priority, they
// should take precedence over lower priority votes.
@@ -2644,6 +2643,53 @@
assertNull(vote);
}
+ @Test
+ public void testUpdateLayoutLimitedRefreshRate_validDisplayInfo() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[]{60.0f, 90.0f}, 0);
+ director.start(createMockSensorManager());
+
+ ArgumentCaptor<DisplayListener> displayListenerCaptor =
+ ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
+ any(Handler.class));
+ DisplayListener displayListener = displayListenerCaptor.getValue();
+
+ float refreshRate = 60;
+ mInjector.mDisplayInfo.layoutLimitedRefreshRate =
+ new RefreshRateRange(refreshRate, refreshRate);
+ displayListener.onDisplayChanged(DISPLAY_ID);
+
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_LAYOUT_LIMITED_FRAME_RATE);
+ assertVoteForPhysicalRefreshRate(vote, /* refreshRate= */ refreshRate);
+
+ mInjector.mDisplayInfo.layoutLimitedRefreshRate = null;
+ displayListener.onDisplayChanged(DISPLAY_ID);
+
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_LAYOUT_LIMITED_FRAME_RATE);
+ assertNull(vote);
+ }
+
+ @Test
+ public void testUpdateLayoutLimitedRefreshRate_invalidDisplayInfo() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[]{60.0f, 90.0f}, 0);
+ director.start(createMockSensorManager());
+
+ ArgumentCaptor<DisplayListener> displayListenerCaptor =
+ ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
+ any(Handler.class));
+ DisplayListener displayListener = displayListenerCaptor.getValue();
+
+ mInjector.mDisplayInfo.layoutLimitedRefreshRate = new RefreshRateRange(10, 10);
+ mInjector.mDisplayInfoValid = false;
+ displayListener.onDisplayChanged(DISPLAY_ID);
+
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_LAYOUT_LIMITED_FRAME_RATE);
+ assertNull(vote);
+ }
+
private Temperature getSkinTemp(@Temperature.ThrottlingStatus int status) {
return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status);
}
@@ -2850,12 +2896,20 @@
public static class FakesInjector implements DisplayModeDirector.Injector {
private final FakeDeviceConfig mDeviceConfig;
+ private final DisplayInfo mDisplayInfo;
+ private final Display mDisplay;
+ private boolean mDisplayInfoValid = true;
private ContentObserver mBrightnessObserver;
private ContentObserver mSmoothDisplaySettingObserver;
private ContentObserver mForcePeakRefreshRateSettingObserver;
FakesInjector() {
mDeviceConfig = new FakeDeviceConfig();
+ mDisplayInfo = new DisplayInfo();
+ mDisplayInfo.defaultModeId = MODE_ID;
+ mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
+ 800, 600, /* refreshRate= */ 60)};
+ mDisplay = createDisplay(DISPLAY_ID);
}
@NonNull
@@ -2876,16 +2930,25 @@
}
@Override
+ public void registerDisplayListener(DisplayListener listener, Handler handler) {}
+
+ @Override
public void registerDisplayListener(DisplayListener listener, Handler handler, long flag) {}
@Override
+ public Display getDisplay(int displayId) {
+ return mDisplay;
+ }
+
+ @Override
public Display[] getDisplays() {
- return new Display[] { createDisplay(DISPLAY_ID) };
+ return new Display[] { mDisplay };
}
@Override
public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
- return false;
+ displayInfo.copyFrom(mDisplayInfo);
+ return mDisplayInfoValid;
}
@Override
@@ -2909,7 +2972,7 @@
}
protected Display createDisplay(int id) {
- return new Display(DisplayManagerGlobal.getInstance(), id, new DisplayInfo(),
+ return new Display(DisplayManagerGlobal.getInstance(), id, mDisplayInfo,
ApplicationProvider.getApplicationContext().getResources());
}
diff --git a/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java b/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
index fd1889c..9ab6ee5 100644
--- a/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
@@ -18,7 +18,6 @@
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import android.hardware.display.DisplayManager;
@@ -57,7 +56,7 @@
private RegisteringFakesInjector mInjector = new RegisteringFakesInjector();
private final TestHandler mHandler = new TestHandler(null);
- private final FakeVoteStorage mStorage = new FakeVoteStorage();
+ private final VotesStorage mStorage = new VotesStorage(() -> {});
@Before
public void setUp() {
@@ -92,28 +91,26 @@
public void testNotifyWithDefaultVotesForCritical() {
// GIVEN 2 displays with no thermalThrottling config
mObserver.observe();
- assertEquals(0, mStorage.mVoteRegistry.size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID).size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID_OTHER).size());
// WHEN thermal sensor notifies CRITICAL
mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_CRITICAL));
mHandler.flush();
// THEN 2 votes are added to storage with (0,60) render refresh rate(default behaviour)
- assertEquals(2, mStorage.mVoteRegistry.size());
-
- SparseArray<DisplayModeDirector.Vote> displayVotes = mStorage.mVoteRegistry.get(DISPLAY_ID);
+ SparseArray<Vote> displayVotes = mStorage.getVotes(DISPLAY_ID);
assertEquals(1, displayVotes.size());
- DisplayModeDirector.Vote vote = displayVotes.get(
- DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE);
+ Vote vote = displayVotes.get(
+ Vote.PRIORITY_SKIN_TEMPERATURE);
assertEquals(0, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE);
assertEquals(60, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE);
- SparseArray<DisplayModeDirector.Vote> otherDisplayVotes = mStorage.mVoteRegistry.get(
- DISPLAY_ID_OTHER);
+ SparseArray<Vote> otherDisplayVotes = mStorage.getVotes(DISPLAY_ID_OTHER);
assertEquals(1, otherDisplayVotes.size());
- vote = otherDisplayVotes.get(DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE);
+ vote = otherDisplayVotes.get(Vote.PRIORITY_SKIN_TEMPERATURE);
assertEquals(0, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE);
assertEquals(60, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE);
}
@@ -122,25 +119,29 @@
public void testNotifyWithDefaultVotesChangeFromCriticalToSevere() {
// GIVEN 2 displays with no thermalThrottling config AND temperature level CRITICAL
mObserver.observe();
- assertEquals(0, mStorage.mVoteRegistry.size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID).size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID_OTHER).size());
mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_CRITICAL));
// WHEN thermal sensor notifies SEVERE
mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_SEVERE));
mHandler.flush();
// THEN all votes with PRIORITY_SKIN_TEMPERATURE are removed from the storage
- assertEquals(0, mStorage.mVoteRegistry.size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID).size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID_OTHER).size());
}
@Test
public void testNotifyWithDefaultVotesForSevere() {
// GIVEN 2 displays with no thermalThrottling config
mObserver.observe();
- assertEquals(0, mStorage.mVoteRegistry.size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID).size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID_OTHER).size());
// WHEN thermal sensor notifies CRITICAL
mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_SEVERE));
mHandler.flush();
// THEN nothing is added to the storage
- assertEquals(0, mStorage.mVoteRegistry.size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID).size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID_OTHER).size());
}
@Test
@@ -155,18 +156,20 @@
mObserver = new SkinThermalStatusObserver(mInjector, mStorage, mHandler);
mObserver.observe();
mObserver.onDisplayChanged(DISPLAY_ID);
- assertEquals(0, mStorage.mVoteRegistry.size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID).size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID_OTHER).size());
// WHEN thermal sensor notifies temperature above configured
mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_SEVERE));
mHandler.flush();
// THEN vote with refreshRate from config is added to the storage
- assertEquals(1, mStorage.mVoteRegistry.size());
- SparseArray<DisplayModeDirector.Vote> displayVotes = mStorage.mVoteRegistry.get(DISPLAY_ID);
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID_OTHER).size());
+
+ SparseArray<Vote> displayVotes = mStorage.getVotes(DISPLAY_ID);
assertEquals(1, displayVotes.size());
- DisplayModeDirector.Vote vote = displayVotes.get(
- DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE);
+ Vote vote = displayVotes.get(Vote.PRIORITY_SKIN_TEMPERATURE);
assertEquals(90, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE);
assertEquals(120, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE);
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID_OTHER).size());
}
@Test
@@ -178,14 +181,13 @@
mObserver.onDisplayAdded(DISPLAY_ID_ADDED);
mHandler.flush();
// THEN 3rd vote is added to storage with (0,60) render refresh rate(default behaviour)
- assertEquals(3, mStorage.mVoteRegistry.size());
+ assertEquals(1, mStorage.getVotes(DISPLAY_ID).size());
+ assertEquals(1, mStorage.getVotes(DISPLAY_ID_OTHER).size());
+ assertEquals(1, mStorage.getVotes(DISPLAY_ID_ADDED).size());
- SparseArray<DisplayModeDirector.Vote> displayVotes = mStorage.mVoteRegistry.get(
- DISPLAY_ID_ADDED);
- assertEquals(1, displayVotes.size());
+ SparseArray<Vote> displayVotes = mStorage.getVotes(DISPLAY_ID_ADDED);
- DisplayModeDirector.Vote vote = displayVotes.get(
- DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE);
+ Vote vote = displayVotes.get(Vote.PRIORITY_SKIN_TEMPERATURE);
assertEquals(0, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE);
assertEquals(60, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE);
}
@@ -200,9 +202,9 @@
mObserver.onDisplayRemoved(DISPLAY_ID_ADDED);
mHandler.flush();
// THEN there are 2 votes in registry
- assertEquals(2, mStorage.mVoteRegistry.size());
- assertNotNull(mStorage.mVoteRegistry.get(DISPLAY_ID));
- assertNotNull(mStorage.mVoteRegistry.get(DISPLAY_ID_OTHER));
+ assertEquals(1, mStorage.getVotes(DISPLAY_ID).size());
+ assertEquals(1, mStorage.getVotes(DISPLAY_ID_OTHER).size());
+ assertEquals(0, mStorage.getVotes(DISPLAY_ID_ADDED).size());
}
private static Temperature createTemperature(@Temperature.ThrottlingStatus int status) {
@@ -253,33 +255,10 @@
public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
SparseArray<SurfaceControl.RefreshRateRange> config = mOverriddenConfig.get(displayId);
if (config != null) {
- displayInfo.refreshRateThermalThrottling = config;
+ displayInfo.thermalRefreshRateThrottling = config;
return true;
}
return false;
}
}
-
-
- private static class FakeVoteStorage implements DisplayModeDirector.BallotBox {
- private final SparseArray<SparseArray<DisplayModeDirector.Vote>> mVoteRegistry =
- new SparseArray<>();
-
- @Override
- public void vote(int displayId, int priority, DisplayModeDirector.Vote vote) {
- SparseArray<DisplayModeDirector.Vote> votesPerDisplay = mVoteRegistry.get(displayId);
- if (votesPerDisplay == null) {
- votesPerDisplay = new SparseArray<>();
- mVoteRegistry.put(displayId, votesPerDisplay);
- }
- if (vote == null) {
- votesPerDisplay.remove(priority);
- } else {
- votesPerDisplay.put(priority, vote);
- }
- if (votesPerDisplay.size() == 0) {
- mVoteRegistry.remove(displayId);
- }
- }
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/display/mode/VotesStorageTest.java b/services/tests/servicestests/src/com/android/server/display/mode/VotesStorageTest.java
new file mode 100644
index 0000000..287fdd5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/mode/VotesStorageTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.mode;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.util.SparseArray;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class VotesStorageTest {
+ private static final int DISPLAY_ID = 100;
+ private static final int PRIORITY = Vote.PRIORITY_APP_REQUEST_SIZE;
+ private static final Vote VOTE = Vote.forDisableRefreshRateSwitching();
+ private static final int DISPLAY_ID_OTHER = 101;
+ private static final int PRIORITY_OTHER = Vote.PRIORITY_FLICKER_REFRESH_RATE;
+ private static final Vote VOTE_OTHER = Vote.forBaseModeRefreshRate(10f);
+
+ @Mock
+ public VotesStorage.Listener mVotesListener;
+
+ private VotesStorage mVotesStorage;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mVotesStorage = new VotesStorage(mVotesListener);
+ }
+
+ @Test
+ public void addsVoteToStorage() {
+ // WHEN updateVote is called
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY, VOTE);
+ // THEN vote is added to the storage
+ SparseArray<Vote> votes = mVotesStorage.getVotes(DISPLAY_ID);
+ assertThat(votes.size()).isEqualTo(1);
+ assertThat(votes.get(PRIORITY)).isEqualTo(VOTE);
+ assertThat(mVotesStorage.getVotes(DISPLAY_ID_OTHER).size()).isEqualTo(0);
+ }
+
+ @Test
+ public void notifiesVoteListenerIfVoteAdded() {
+ // WHEN updateVote is called
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY, VOTE);
+ // THEN listener is notified
+ verify(mVotesListener).onChanged();
+ }
+
+ @Test
+ public void addsAnotherVoteToStorageWithDifferentPriority() {
+ // GIVEN vote storage with one vote
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY, VOTE);
+ // WHEN updateVote is called with other priority
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY_OTHER, VOTE_OTHER);
+ // THEN another vote is added to storage
+ SparseArray<Vote> votes = mVotesStorage.getVotes(DISPLAY_ID);
+ assertThat(votes.size()).isEqualTo(2);
+ assertThat(votes.get(PRIORITY)).isEqualTo(VOTE);
+ assertThat(votes.get(PRIORITY_OTHER)).isEqualTo(VOTE_OTHER);
+ assertThat(mVotesStorage.getVotes(DISPLAY_ID_OTHER).size()).isEqualTo(0);
+ }
+
+ @Test
+ public void replacesVoteInStorageForSamePriority() {
+ // GIVEN vote storage with one vote
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY, VOTE);
+ // WHEN updateVote is called with same priority
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY, VOTE_OTHER);
+ // THEN vote is replaced by other vote
+ SparseArray<Vote> votes = mVotesStorage.getVotes(DISPLAY_ID);
+ assertThat(votes.size()).isEqualTo(1);
+ assertThat(votes.get(PRIORITY)).isEqualTo(VOTE_OTHER);
+ assertThat(mVotesStorage.getVotes(DISPLAY_ID_OTHER).size()).isEqualTo(0);
+ }
+
+ @Test
+ public void removesVoteInStorageForSamePriority() {
+ // GIVEN vote storage with one vote
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY, VOTE);
+ // WHEN update is called with same priority and null vote
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY, null);
+ // THEN vote removed from the storage
+ assertThat(mVotesStorage.getVotes(DISPLAY_ID).size()).isEqualTo(0);
+ assertThat(mVotesStorage.getVotes(DISPLAY_ID_OTHER).size()).isEqualTo(0);
+ }
+
+ @Test
+ public void addsGlobalDisplayVoteToStorage() {
+ // WHEN updateGlobalVote is called
+ mVotesStorage.updateGlobalVote(PRIORITY, VOTE);
+ // THEN it is added to the storage for every display
+ SparseArray<Vote> votes = mVotesStorage.getVotes(DISPLAY_ID);
+ assertThat(votes.size()).isEqualTo(1);
+ assertThat(votes.get(PRIORITY)).isEqualTo(VOTE);
+ votes = mVotesStorage.getVotes(DISPLAY_ID_OTHER);
+ assertThat(votes.size()).isEqualTo(1);
+ assertThat(votes.get(PRIORITY)).isEqualTo(VOTE);
+ }
+
+ @Test
+ public void ignoresVotesWithLowerThanMinPriority() {
+ // WHEN updateVote is called with invalid (lower than min) priority
+ mVotesStorage.updateVote(DISPLAY_ID, Vote.MIN_PRIORITY - 1, VOTE);
+ // THEN vote is not added to the storage AND listener not notified
+ assertThat(mVotesStorage.getVotes(DISPLAY_ID).size()).isEqualTo(0);
+ verify(mVotesListener, never()).onChanged();
+ }
+
+ @Test
+ public void ignoresVotesWithGreaterThanMaxPriority() {
+ // WHEN updateVote is called with invalid (greater than max) priority
+ mVotesStorage.updateVote(DISPLAY_ID, Vote.MAX_PRIORITY + 1, VOTE);
+ // THEN vote is not added to the storage AND listener not notified
+ assertThat(mVotesStorage.getVotes(DISPLAY_ID).size()).isEqualTo(0);
+ verify(mVotesListener, never()).onChanged();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt
index 0f4d4e8..64c05dc 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt
@@ -250,20 +250,24 @@
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
`when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
- dataStore.setKeyboardBacklightBrightness(
- keyboardWithBacklight.descriptor,
- LIGHT_ID,
- MAX_BRIGHTNESS
- )
+ for (level in 1 until BRIGHTNESS_VALUE_FOR_LEVEL.size) {
+ dataStore.setKeyboardBacklightBrightness(
+ keyboardWithBacklight.descriptor,
+ LIGHT_ID,
+ BRIGHTNESS_VALUE_FOR_LEVEL[level] - 1
+ )
- keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
- keyboardBacklightController.notifyUserActivity()
- testLooper.dispatchNext()
- assertEquals(
- "Keyboard backlight level should be restored to the level saved in the data store",
- Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
- lightColorMap[LIGHT_ID]
- )
+ keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
+ keyboardBacklightController.notifyUserActivity()
+ testLooper.dispatchNext()
+ assertEquals(
+ "Keyboard backlight level should be restored to the level saved in the data " +
+ "store",
+ Color.argb(BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0),
+ lightColorMap[LIGHT_ID]
+ )
+ keyboardBacklightController.onInputDeviceRemoved(DEVICE_ID)
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
index ea3f3bc..d0d28c3 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
@@ -633,6 +633,30 @@
0,
keyboardLayouts.size
)
+
+ // If IME doesn't have a corresponding language tag, then should show all available
+ // layouts no matter the script code.
+ keyboardLayouts =
+ keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo, null
+ )
+ assertNotEquals(
+ "New UI: getKeyboardLayoutListForInputDevice API should return all layouts if" +
+ "language tag or subtype not provided",
+ 0,
+ keyboardLayouts.size
+ )
+ assertTrue("New UI: getKeyboardLayoutListForInputDevice API should contain Latin " +
+ "layouts if language tag or subtype not provided",
+ containsLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
+ )
+ assertTrue("New UI: getKeyboardLayoutListForInputDevice API should contain Cyrillic " +
+ "layouts if language tag or subtype not provided",
+ containsLayout(
+ keyboardLayouts,
+ createLayoutDescriptor("keyboard_layout_russian")
+ )
+ )
}
}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index b7f90d4..c04df30 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -18,6 +18,12 @@
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.NETWORK_STACK;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
+import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
@@ -396,6 +402,26 @@
}
}
+ // TODO: Use TestLooperManager instead.
+ /**
+ * Helper that leverages try-with-resources to pause dispatch of
+ * {@link #mHandlerThread} until released.
+ */
+ static class SyncBarrier implements AutoCloseable {
+ private final int mToken;
+ private Handler mHandler;
+
+ SyncBarrier(Handler handler) {
+ mHandler = handler;
+ mToken = mHandler.getLooper().getQueue().postSyncBarrier();
+ }
+
+ @Override
+ public void close() throws Exception {
+ mHandler.getLooper().getQueue().removeSyncBarrier(mToken);
+ }
+ }
+
@Before
public void callSystemReady() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -1018,25 +1044,113 @@
// don't check for side-effects (like calls to NetworkManagementService) neither cover all
// different modes (Data Saver, Battery Saver, Doze, App idle, etc...).
// These scenarios are extensively tested on CTS' HostsideRestrictBackgroundNetworkTests.
+ @SuppressWarnings("GuardedBy")
@Test
public void testUidForeground() throws Exception {
// push all uids into background
long procStateSeq = 0;
- callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++);
- callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++);
- assertFalse(mService.isUidForeground(UID_A));
- assertFalse(mService.isUidForeground(UID_B));
+ callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++);
+ callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE, procStateSeq++);
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));
// push one of the uids into foreground
- callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, procStateSeq++);
- assertTrue(mService.isUidForeground(UID_A));
- assertFalse(mService.isUidForeground(UID_B));
+ callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, procStateSeq++);
+ assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A));
+ assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));
// and swap another uid into foreground
- callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++);
- callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP, procStateSeq++);
- assertFalse(mService.isUidForeground(UID_A));
- assertTrue(mService.isUidForeground(UID_B));
+ callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++);
+ callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_TOP, procStateSeq++);
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
+ assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_B));
+ assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));
+
+ // change capability of an uid to allow access to power restricted network
+ callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++,
+ PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK);
+ callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE, procStateSeq++,
+ PROCESS_CAPABILITY_NONE);
+ assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));
+
+ // change capability of an uid to allow access to user restricted network
+ callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_IMPORTANT_FOREGROUND, procStateSeq++,
+ PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK);
+ callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE, procStateSeq++,
+ PROCESS_CAPABILITY_NONE);
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A));
+ assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testUidForeground_withPendingState() throws Exception {
+ long procStateSeq = 0;
+ callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE,
+ procStateSeq++, PROCESS_CAPABILITY_NONE);
+ callAndWaitOnUidStateChanged(UID_B, PROCESS_STATE_SERVICE,
+ procStateSeq++, PROCESS_CAPABILITY_NONE);
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));
+
+ try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+ // Verify that a callback with an old procStateSeq is ignored.
+ callOnUidStatechanged(UID_A, PROCESS_STATE_TOP, 0,
+ PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK);
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));
+
+ callOnUidStatechanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++,
+ PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK);
+ assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));
+
+ callOnUidStatechanged(UID_A, PROCESS_STATE_IMPORTANT_FOREGROUND, procStateSeq++,
+ PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK);
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_A));
+ assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));
+
+ callOnUidStatechanged(UID_A, PROCESS_STATE_TOP, procStateSeq++,
+ PROCESS_CAPABILITY_NONE);
+ assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A));
+ assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));
+ }
+ waitForUidEventHandlerIdle();
+
+ assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A));
+ assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));
+
+ try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+ callOnUidStatechanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq++,
+ PROCESS_CAPABILITY_NONE);
+ assertTrue(mService.isUidForegroundOnRestrictPowerUL(UID_A));
+ assertTrue(mService.isUidForegroundOnRestrictBackgroundUL(UID_A));
+ assertFalse(mService.isUidForegroundOnRestrictPowerUL(UID_B));
+ assertFalse(mService.isUidForegroundOnRestrictBackgroundUL(UID_B));
+ }
+ waitForUidEventHandlerIdle();
}
@Test
@@ -1417,14 +1531,28 @@
@Test
public void testOnUidStateChanged_notifyAMS() throws Exception {
final long procStateSeq = 222;
- callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq);
+ callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_SERVICE, procStateSeq);
verify(mActivityManagerInternal).notifyNetworkPolicyRulesUpdated(UID_A, procStateSeq);
}
- private void callOnUidStateChanged(int uid, int procState, long procStateSeq)
+ private void callAndWaitOnUidStateChanged(int uid, int procState, long procStateSeq)
throws Exception {
- mUidObserver.onUidStateChanged(uid, procState, procStateSeq,
- ActivityManager.PROCESS_CAPABILITY_NONE);
+ callAndWaitOnUidStateChanged(uid, procState, procStateSeq,
+ PROCESS_CAPABILITY_NONE);
+ }
+
+ private void callAndWaitOnUidStateChanged(int uid, int procState, long procStateSeq,
+ int capability) throws Exception {
+ callOnUidStatechanged(uid, procState, procStateSeq, capability);
+ waitForUidEventHandlerIdle();
+ }
+
+ private void callOnUidStatechanged(int uid, int procState, long procStateSeq, int capability)
+ throws Exception {
+ mUidObserver.onUidStateChanged(uid, procState, procStateSeq, capability);
+ }
+
+ private void waitForUidEventHandlerIdle() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mService.mUidEventHandler.post(() -> {
latch.countDown();
@@ -1927,9 +2055,9 @@
@Test
public void testLowPowerStandbyAllowlist() throws Exception {
- callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, 0);
- callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
- callOnUidStateChanged(UID_C, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+ callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, 0);
+ callAndWaitOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+ callAndWaitOnUidStateChanged(UID_C, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
expectHasInternetPermission(UID_A, true);
expectHasInternetPermission(UID_B, true);
expectHasInternetPermission(UID_C, true);
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/SoundTriggerEventTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/SoundTriggerEventTest.java
new file mode 100644
index 0000000..1c89506
--- /dev/null
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/SoundTriggerEventTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.soundtrigger;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.soundtrigger.SoundTriggerEvent.ServiceEvent;
+import com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.UUID;
+
+@RunWith(AndroidJUnit4.class)
+public final class SoundTriggerEventTest {
+ private static final ServiceEvent.Type serviceEventType = ServiceEvent.Type.ATTACH;
+ private static final SessionEvent.Type sessionEventType = SessionEvent.Type.DETACH;
+
+ @Test
+ public void serviceEventNoPackageNoError_getStringContainsType() {
+ final var event = new ServiceEvent(serviceEventType);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(serviceEventType.name());
+ assertThat(stringRep).ignoringCase().doesNotContain("error");
+ }
+
+ @Test
+ public void serviceEventPackageNoError_getStringContainsTypeAndPackage() {
+ final var packageName = "com.android.package.name";
+ final var event = new ServiceEvent(serviceEventType, packageName);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(serviceEventType.name());
+ assertThat(stringRep).contains(packageName);
+ assertThat(stringRep).ignoringCase().doesNotContain("error");
+ }
+
+ @Test
+ public void serviceEventPackageError_getStringContainsTypeAndPackageAndErrorAndMessage() {
+ final var packageName = "com.android.package.name";
+ final var errorString = "oh no an ERROR occurred";
+ final var event = new ServiceEvent(serviceEventType, packageName, errorString);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(serviceEventType.name());
+ assertThat(stringRep).contains(packageName);
+ assertThat(stringRep).contains(errorString);
+ assertThat(stringRep).ignoringCase().contains("error");
+ }
+
+ @Test
+ public void sessionEventUUIDNoError_getStringContainsUUID() {
+ final var uuid = new UUID(5, -7);
+ final var event = new SessionEvent(sessionEventType, uuid);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(sessionEventType.name());
+ assertThat(stringRep).contains(uuid.toString());
+ assertThat(stringRep).ignoringCase().doesNotContain("error");
+ }
+
+ @Test
+ public void sessionEventUUIDError_getStringContainsUUIDAndError() {
+ final var uuid = new UUID(5, -7);
+ final var errorString = "oh no an ERROR occurred";
+ final var event = new SessionEvent(sessionEventType, uuid, errorString);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(sessionEventType.name());
+ assertThat(stringRep).contains(uuid.toString());
+ assertThat(stringRep).ignoringCase().contains("error");
+ assertThat(stringRep).contains(errorString);
+ }
+}
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java
index 4d3c26f..eb117d1 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java
@@ -16,6 +16,8 @@
package com.android.server.soundtrigger_middleware;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.ServiceEvent;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent;
import static com.android.internal.util.LatencyTracker.ACTION_SHOW_VOICE_INTERACTION;
import static com.google.common.truth.Truth.assertThat;
@@ -55,6 +57,9 @@
@RunWith(JUnit4.class)
public class SoundTriggerMiddlewareLoggingTest {
+ private static final ServiceEvent.Type SERVICE_TYPE = ServiceEvent.Type.ATTACH;
+ private static final SessionEvent.Type SESSION_TYPE = SessionEvent.Type.LOAD_MODEL;
+
private FakeLatencyTracker mLatencyTracker;
@Mock
private BatteryStatsInternal mBatteryStatsInternal;
@@ -184,4 +189,138 @@
callback.onPhraseRecognition(0 /* modelHandle */, successEventWithKeyphraseId,
0 /* captureSession */);
}
+
+ @Test
+ public void serviceEventException_getStringContainsInfo() {
+ String packageName = "com.android.test";
+ Exception exception = new Exception("test");
+ Object param1 = new Object();
+ Object param2 = new Object();
+ final var event = ServiceEvent.createForException(
+ SERVICE_TYPE, packageName, exception, param1, param2);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(SERVICE_TYPE.name());
+ assertThat(stringRep).contains(packageName);
+ assertThat(stringRep).contains(exception.toString());
+ assertThat(stringRep).contains(param1.toString());
+ assertThat(stringRep).contains(param2.toString());
+ assertThat(stringRep).ignoringCase().contains("error");
+ }
+
+ @Test
+ public void serviceEventExceptionNoArgs_getStringContainsInfo() {
+ String packageName = "com.android.test";
+ Exception exception = new Exception("test");
+ final var event = ServiceEvent.createForException(
+ SERVICE_TYPE, packageName, exception);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(SERVICE_TYPE.name());
+ assertThat(stringRep).contains(packageName);
+ assertThat(stringRep).contains(exception.toString());
+ assertThat(stringRep).ignoringCase().contains("error");
+ }
+
+ @Test
+ public void serviceEventReturn_getStringContainsInfo() {
+ String packageName = "com.android.test";
+ Object param1 = new Object();
+ Object param2 = new Object();
+ Object retValue = new Object();
+ final var event = ServiceEvent.createForReturn(
+ SERVICE_TYPE, packageName, retValue, param1, param2);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(SERVICE_TYPE.name());
+ assertThat(stringRep).contains(packageName);
+ assertThat(stringRep).contains(retValue.toString());
+ assertThat(stringRep).contains(param1.toString());
+ assertThat(stringRep).contains(param2.toString());
+ assertThat(stringRep).ignoringCase().doesNotContain("error");
+ }
+
+ @Test
+ public void serviceEventReturnNoArgs_getStringContainsInfo() {
+ String packageName = "com.android.test";
+ Object retValue = new Object();
+ final var event = ServiceEvent.createForReturn(
+ SERVICE_TYPE, packageName, retValue);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(SERVICE_TYPE.name());
+ assertThat(stringRep).contains(packageName);
+ assertThat(stringRep).contains(retValue.toString());
+ assertThat(stringRep).ignoringCase().doesNotContain("error");
+ }
+
+ @Test
+ public void sessionEventException_getStringContainsInfo() {
+ Object param1 = new Object();
+ Object param2 = new Object();
+ Exception exception = new Exception("test");
+ final var event = SessionEvent.createForException(
+ SESSION_TYPE, exception, param1, param2);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(SESSION_TYPE.name());
+ assertThat(stringRep).contains(exception.toString());
+ assertThat(stringRep).contains(param1.toString());
+ assertThat(stringRep).contains(param2.toString());
+ assertThat(stringRep).ignoringCase().contains("error");
+ }
+
+ @Test
+ public void sessionEventExceptionNoArgs_getStringContainsInfo() {
+ Exception exception = new Exception("test");
+ final var event = SessionEvent.createForException(
+ SESSION_TYPE, exception);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(SESSION_TYPE.name());
+ assertThat(stringRep).contains(exception.toString());
+ assertThat(stringRep).ignoringCase().contains("error");
+ }
+
+ @Test
+ public void sessionEventReturn_getStringContainsInfo() {
+ Object param1 = new Object();
+ Object param2 = new Object();
+ Object retValue = new Object();
+ final var event = SessionEvent.createForReturn(
+ SESSION_TYPE, retValue, param1, param2);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(SESSION_TYPE.name());
+ assertThat(stringRep).contains(retValue.toString());
+ assertThat(stringRep).contains(param1.toString());
+ assertThat(stringRep).contains(param2.toString());
+ assertThat(stringRep).ignoringCase().doesNotContain("error");
+ }
+
+ @Test
+ public void sessionEventReturnNoArgs_getStringContainsInfo() {
+ Object retValue = new Object();
+ final var event = SessionEvent.createForReturn(
+ SESSION_TYPE, retValue);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(SESSION_TYPE.name());
+ assertThat(stringRep).contains(retValue.toString());
+ assertThat(stringRep).ignoringCase().doesNotContain("error");
+ }
+
+ @Test
+ public void sessionEventVoid_getStringContainsInfo() {
+ Object param1 = new Object();
+ Object param2 = new Object();
+ final var event = SessionEvent.createForVoid(
+ SESSION_TYPE, param1, param2);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(SESSION_TYPE.name());
+ assertThat(stringRep).contains(param1.toString());
+ assertThat(stringRep).contains(param2.toString());
+ assertThat(stringRep).ignoringCase().doesNotContain("error");
+ }
+
+ @Test
+ public void sessionEventVoidNoArgs_getStringContainsInfo() {
+ final var event = SessionEvent.createForVoid(
+ SESSION_TYPE);
+ final var stringRep = event.eventToString();
+ assertThat(stringRep).contains(SESSION_TYPE.name());
+ assertThat(stringRep).ignoringCase().doesNotContain("error");
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
index 8f0a5e6..bf6901e 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
@@ -21,6 +21,8 @@
import static android.view.KeyEvent.KEYCODE_C;
import static android.view.KeyEvent.KEYCODE_CTRL_LEFT;
import static android.view.KeyEvent.KEYCODE_E;
+import static android.view.KeyEvent.KEYCODE_ENTER;
+import static android.view.KeyEvent.KEYCODE_H;
import static android.view.KeyEvent.KEYCODE_K;
import static android.view.KeyEvent.KEYCODE_M;
import static android.view.KeyEvent.KEYCODE_META_LEFT;
@@ -164,4 +166,24 @@
sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_ALT_LEFT}, 0);
mPhoneWindowManager.assertToggleCapsLock();
}
+
+ /**
+ * META + H to go to homescreen
+ */
+ @Test
+ public void testMetaH() {
+ mPhoneWindowManager.overrideLaunchHome();
+ sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_H}, 0);
+ mPhoneWindowManager.assertGoToHomescreen();
+ }
+
+ /**
+ * META + ENTER to go to homescreen
+ */
+ @Test
+ public void testMetaEnter() {
+ mPhoneWindowManager.overrideLaunchHome();
+ sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_ENTER}, 0);
+ mPhoneWindowManager.assertGoToHomescreen();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index 6368f47..676bfb0 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -117,9 +117,9 @@
throw new RuntimeException(e);
}
- for (KeyEvent event: events) {
+ for (int i = count - 1; i >= 0; i--) {
final long eventTime = SystemClock.uptimeMillis();
- final int keyCode = event.getKeyCode();
+ final int keyCode = keyCodes[i];
final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode,
0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
InputDevice.SOURCE_KEYBOARD);
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index a2ee8a4..2665e19 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -353,6 +353,10 @@
() -> LocalServices.getService(eq(StatusBarManagerInternal.class)));
}
+ void overrideLaunchHome() {
+ doNothing().when(mPhoneWindowManager).launchHomeFromHotKey(anyInt());
+ }
+
/**
* Below functions will check the policy behavior could be invoked.
*/
@@ -480,4 +484,9 @@
transitionCaptor.getValue().onAppTransitionFinishedLocked(any());
verify(mPhoneWindowManager).lockNow(null);
}
+
+ void assertGoToHomescreen() {
+ waitForIdle();
+ verify(mPhoneWindowManager).launchHomeFromHotKey(anyInt());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 4b2d107..8e80485 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -541,6 +541,24 @@
SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_180));
}
+ @Test
+ public void testFreezeRotation_reverseRotationDirectionAroundZAxis_yes() throws Exception {
+ mBuilder.build();
+ when(mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()).thenReturn(true);
+
+ freezeRotation(Surface.ROTATION_90);
+ assertEquals(Surface.ROTATION_270, mTarget.getUserRotation());
+ }
+
+ @Test
+ public void testFreezeRotation_reverseRotationDirectionAroundZAxis_no() throws Exception {
+ mBuilder.build();
+ when(mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()).thenReturn(false);
+
+ freezeRotation(Surface.ROTATION_90);
+ assertEquals(Surface.ROTATION_90, mTarget.getUserRotation());
+ }
+
private boolean waitForUiHandler() {
final CountDownLatch latch = new CountDownLatch(1);
UiThread.getHandler().post(latch::countDown);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index fb4f2ee..1cec0ef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -41,8 +41,9 @@
import android.annotation.NonNull;
import android.app.WindowConfiguration;
-import android.content.res.Configuration;
+import android.content.ContentResolver;
import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
@@ -439,6 +440,7 @@
public void testDisplayWindowSettingsAppliedOnDisplayReady() {
// Set forced densities for two displays in DisplayWindowSettings
final DisplayContent dc = createMockSimulatedDisplay();
+ final ContentResolver contentResolver = useFakeSettingsProvider();
mDisplayWindowSettings.setForcedDensity(mPrimaryDisplay.getDisplayInfo(), 123,
0 /* userId */);
mDisplayWindowSettings.setForcedDensity(dc.getDisplayInfo(), 456, 0 /* userId */);
@@ -450,15 +452,21 @@
assertFalse(mPrimaryDisplay.mWaitingForConfig);
assertFalse(dc.mWaitingForConfig);
+ final int invalidW = Integer.MAX_VALUE;
+ final int invalidH = Integer.MAX_VALUE;
+ // Verify that applyForcedPropertiesForDefaultDisplay() handles invalid size request.
+ Settings.Global.putString(contentResolver, Settings.Global.DISPLAY_SIZE_FORCED,
+ invalidW + "," + invalidH);
// Notify WM that the displays are ready and check that they are reconfigured.
mWm.displayReady();
waitUntilHandlersIdle();
- final Configuration config = new Configuration();
- mPrimaryDisplay.computeScreenConfiguration(config);
- assertEquals(123, config.densityDpi);
- dc.computeScreenConfiguration(config);
- assertEquals(456, config.densityDpi);
+ // Density is set successfully.
+ assertEquals(123, mPrimaryDisplay.getConfiguration().densityDpi);
+ assertEquals(456, dc.getConfiguration().densityDpi);
+ // Invalid size won't be applied.
+ assertNotEquals(invalidW, mPrimaryDisplay.mBaseDisplayWidth);
+ assertNotEquals(invalidH, mPrimaryDisplay.mBaseDisplayHeight);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTests.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTests.java
index 9db647a..89d7252 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.os.Build.HW_TIMEOUT_MULTIPLIER;
import static android.window.SurfaceSyncGroup.TRANSACTION_READY_TIMEOUT;
import static org.junit.Assert.assertEquals;
@@ -52,6 +53,8 @@
public class SurfaceSyncGroupTests {
private static final String TAG = "SurfaceSyncGroupTests";
+ private static final long TIMEOUT_S = HW_TIMEOUT_MULTIPLIER * 5L;
+
@Rule
public ActivityTestRule<SurfaceSyncGroupActivity> mActivityRule = new ActivityTestRule<>(
SurfaceSyncGroupActivity.class);
@@ -93,7 +96,7 @@
addSecondSyncGroup(secondSsg, secondDrawCompleteLatch, bothSyncGroupsComplete);
assertTrue("Failed to draw two frames",
- secondDrawCompleteLatch.await(5, TimeUnit.SECONDS));
+ secondDrawCompleteLatch.await(TIMEOUT_S, TimeUnit.SECONDS));
mHandler.postDelayed(() -> {
// Don't add a markSyncReady for the first sync group until after it's added to another
@@ -105,7 +108,7 @@
}, 200);
assertTrue("Failed to wait for both SurfaceSyncGroups to apply",
- bothSyncGroupsComplete.await(5, TimeUnit.SECONDS));
+ bothSyncGroupsComplete.await(TIMEOUT_S, TimeUnit.SECONDS));
validateScreenshot();
}
@@ -123,7 +126,7 @@
transaction -> mHandler.postDelayed(() -> {
try {
assertTrue("Failed to draw two frames",
- secondDrawCompleteLatch.await(5, TimeUnit.SECONDS));
+ secondDrawCompleteLatch.await(TIMEOUT_S, TimeUnit.SECONDS));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
@@ -143,7 +146,7 @@
addSecondSyncGroup(secondSsg, secondDrawCompleteLatch, bothSyncGroupsComplete);
assertTrue("Failed to wait for both SurfaceSyncGroups to apply",
- bothSyncGroupsComplete.await(5, TimeUnit.SECONDS));
+ bothSyncGroupsComplete.await(TIMEOUT_S, TimeUnit.SECONDS));
validateScreenshot();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 0dac346..b59f027 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -23,6 +23,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
@@ -36,6 +37,7 @@
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
+import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static android.window.TransitionInfo.isIndependent;
@@ -74,6 +76,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.SurfaceControl;
+import android.view.WindowManager;
import android.window.IDisplayAreaOrganizer;
import android.window.IRemoteTransition;
import android.window.ITaskFragmentOrganizer;
@@ -96,6 +99,7 @@
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
import java.util.function.Function;
/**
@@ -1903,7 +1907,7 @@
assertTrue(targets.isEmpty());
// After collecting order changes, it should recognize that a task moved to top.
- transition.collectOrderChanges();
+ transition.collectOrderChanges(true);
targets = Transition.calculateTargets(participants, changes);
assertEquals(1, targets.size());
@@ -1914,6 +1918,192 @@
assertEquals(TRANSIT_CHANGE, info.getChanges().get(0).getMode());
}
+ private class OrderChangeTestSetup {
+ final TransitionController mController;
+ final TestTransitionPlayer mPlayer;
+ final Transition mTransitA;
+ final Transition mTransitB;
+
+ OrderChangeTestSetup() {
+ mController = mAtm.getTransitionController();
+ mPlayer = registerTestTransitionPlayer();
+ mController.setSyncEngine(mWm.mSyncEngine);
+
+ mTransitA = createTestTransition(TRANSIT_OPEN, mController);
+ mTransitA.mParallelCollectType = Transition.PARALLEL_TYPE_MUTUAL;
+ mTransitB = createTestTransition(TRANSIT_OPEN, mController);
+ mTransitB.mParallelCollectType = Transition.PARALLEL_TYPE_MUTUAL;
+ }
+
+ void startParallelCollect(boolean activityLevelFirst) {
+ // Start with taskB on top and taskA on bottom but both visible.
+ final Task taskA = createTask(mDisplayContent);
+ taskA.setVisibleRequested(true);
+ final ActivityRecord actA = createActivityRecord(taskA);
+ final TestWindowState winA = createWindowState(
+ new WindowManager.LayoutParams(TYPE_BASE_APPLICATION), actA);
+ actA.addWindow(winA);
+ final ActivityRecord actB = createActivityRecord(taskA);
+ final TestWindowState winB = createWindowState(
+ new WindowManager.LayoutParams(TYPE_BASE_APPLICATION), actB);
+ actB.addWindow(winB);
+
+ final Task taskB = createTask(mDisplayContent);
+ actA.setVisibleRequested(true);
+ actB.setVisibleRequested(false);
+ taskB.setVisibleRequested(true);
+ assertTrue(actA.isAttached());
+
+ final Consumer<Boolean> startAndCollectA = (doReady) -> {
+ mController.startCollectOrQueue(mTransitA, (deferred) -> {
+ });
+
+ // Collect activity-level change into A
+ mTransitA.collect(actA);
+ actA.setVisibleRequested(false);
+ winA.onSyncFinishedDrawing();
+ mTransitA.collect(actB);
+ actB.setVisibleRequested(true);
+ winB.onSyncFinishedDrawing();
+ mTransitA.start();
+ if (doReady) {
+ mTransitA.setReady(mDisplayContent, true);
+ }
+ };
+ final Consumer<Boolean> startAndCollectB = (doReady) -> {
+ mController.startCollectOrQueue(mTransitB, (deferred) -> {
+ });
+ mTransitB.collect(taskA);
+ taskA.moveToFront("test");
+ mTransitB.start();
+ if (doReady) {
+ mTransitB.setReady(mDisplayContent, true);
+ }
+ };
+
+ if (activityLevelFirst) {
+ startAndCollectA.accept(true);
+ startAndCollectB.accept(false);
+ } else {
+ startAndCollectB.accept(true);
+ startAndCollectA.accept(false);
+ }
+ }
+ }
+
+ @Test
+ public void testMoveToTopStartAfterReadyAfterParallel() {
+ // Start collect activity-only transit A
+ // Start collect task transit B in parallel
+ // finish A first -> should not include order change from B.
+ final OrderChangeTestSetup setup = new OrderChangeTestSetup();
+ setup.startParallelCollect(true /* activity first */);
+
+ mWm.mSyncEngine.tryFinishForTest(setup.mTransitA.getSyncId());
+ waitUntilHandlersIdle();
+ for (int i = 0; i < setup.mPlayer.mLastReady.getChanges().size(); ++i) {
+ assertNull(setup.mPlayer.mLastReady.getChanges().get(i).getTaskInfo());
+ }
+
+ setup.mTransitB.setAllReady();
+ mWm.mSyncEngine.tryFinishForTest(setup.mTransitB.getSyncId());
+ waitUntilHandlersIdle();
+ boolean hasOrderChange = false;
+ for (int i = 0; i < setup.mPlayer.mLastReady.getChanges().size(); ++i) {
+ final TransitionInfo.Change chg = setup.mPlayer.mLastReady.getChanges().get(i);
+ if (chg.getTaskInfo() == null) continue;
+ hasOrderChange = hasOrderChange || (chg.getFlags() & FLAG_MOVED_TO_TOP) != 0;
+ }
+ assertTrue(hasOrderChange);
+ }
+
+ @Test
+ public void testMoveToTopStartAfterReadyBeforeParallel() {
+ // Start collect activity-only transit A
+ // Start collect task transit B in parallel
+ // finish B first -> should include order change
+ // then finish A -> should NOT include order change.
+ final OrderChangeTestSetup setup = new OrderChangeTestSetup();
+ setup.startParallelCollect(true /* activity first */);
+ // Make it unready now so that it doesn't get dequeued automatically.
+ setup.mTransitA.setReady(mDisplayContent, false);
+
+ // Make task change ready first
+ setup.mTransitB.setAllReady();
+ mWm.mSyncEngine.tryFinishForTest(setup.mTransitB.getSyncId());
+ waitUntilHandlersIdle();
+ boolean hasOrderChange = false;
+ for (int i = 0; i < setup.mPlayer.mLastReady.getChanges().size(); ++i) {
+ final TransitionInfo.Change chg = setup.mPlayer.mLastReady.getChanges().get(i);
+ if (chg.getTaskInfo() == null) continue;
+ hasOrderChange = hasOrderChange || (chg.getFlags() & FLAG_MOVED_TO_TOP) != 0;
+ }
+ assertTrue(hasOrderChange);
+
+ setup.mTransitA.setAllReady();
+ mWm.mSyncEngine.tryFinishForTest(setup.mTransitA.getSyncId());
+ waitUntilHandlersIdle();
+ for (int i = 0; i < setup.mPlayer.mLastReady.getChanges().size(); ++i) {
+ assertNull(setup.mPlayer.mLastReady.getChanges().get(i).getTaskInfo());
+ }
+ }
+
+ @Test
+ public void testMoveToTopStartBeforeReadyAfterParallel() {
+ // Start collect task transit B
+ // Start collect activity-only transit A in parallel
+ // finish A first -> should not include order change from B.
+ final OrderChangeTestSetup setup = new OrderChangeTestSetup();
+ setup.startParallelCollect(false /* activity first */);
+ // Make B unready now so that it doesn't get dequeued automatically.
+ setup.mTransitB.setReady(mDisplayContent, false);
+
+ setup.mTransitA.setAllReady();
+ mWm.mSyncEngine.tryFinishForTest(setup.mTransitA.getSyncId());
+ waitUntilHandlersIdle();
+ for (int i = 0; i < setup.mPlayer.mLastReady.getChanges().size(); ++i) {
+ assertNull(setup.mPlayer.mLastReady.getChanges().get(i).getTaskInfo());
+ }
+
+ setup.mTransitB.setAllReady();
+ mWm.mSyncEngine.tryFinishForTest(setup.mTransitB.getSyncId());
+ waitUntilHandlersIdle();
+ boolean hasOrderChange = false;
+ for (int i = 0; i < setup.mPlayer.mLastReady.getChanges().size(); ++i) {
+ final TransitionInfo.Change chg = setup.mPlayer.mLastReady.getChanges().get(i);
+ if (chg.getTaskInfo() == null) continue;
+ hasOrderChange = hasOrderChange || (chg.getFlags() & FLAG_MOVED_TO_TOP) != 0;
+ }
+ assertTrue(hasOrderChange);
+ }
+
+ @Test
+ public void testMoveToTopStartBeforeReadyBeforeParallel() {
+ // Start collect task transit B
+ // Start collect activity-only transit A in parallel
+ // finish B first -> should include order change
+ // then finish A -> should NOT include order change.
+ final OrderChangeTestSetup setup = new OrderChangeTestSetup();
+ setup.startParallelCollect(false /* activity first */);
+
+ mWm.mSyncEngine.tryFinishForTest(setup.mTransitB.getSyncId());
+ waitUntilHandlersIdle();
+ boolean hasOrderChange = false;
+ for (int i = 0; i < setup.mPlayer.mLastReady.getChanges().size(); ++i) {
+ final TransitionInfo.Change chg = setup.mPlayer.mLastReady.getChanges().get(i);
+ if (chg.getTaskInfo() == null) continue;
+ hasOrderChange = hasOrderChange || (chg.getFlags() & FLAG_MOVED_TO_TOP) != 0;
+ }
+ assertTrue(hasOrderChange);
+
+ setup.mTransitA.setAllReady();
+ mWm.mSyncEngine.tryFinishForTest(setup.mTransitA.getSyncId());
+ waitUntilHandlersIdle();
+ for (int i = 0; i < setup.mPlayer.mLastReady.getChanges().size(); ++i) {
+ assertNull(setup.mPlayer.mLastReady.getChanges().get(i).getTaskInfo());
+ }
+ }
+
@Test
public void testQueueStartCollect() {
final TransitionController controller = mAtm.getTransitionController();
@@ -2018,6 +2208,94 @@
assertTrue(transitB.isCollecting());
}
+ @Test
+ public void testQueueParallel() {
+ final TransitionController controller = mAtm.getTransitionController();
+ final TestTransitionPlayer player = registerTestTransitionPlayer();
+
+ mSyncEngine = createTestBLASTSyncEngine();
+ controller.setSyncEngine(mSyncEngine);
+
+ final Transition transitA = createTestTransition(TRANSIT_OPEN, controller);
+ transitA.mParallelCollectType = Transition.PARALLEL_TYPE_MUTUAL;
+ final Transition transitB = createTestTransition(TRANSIT_OPEN, controller);
+ transitB.mParallelCollectType = Transition.PARALLEL_TYPE_MUTUAL;
+ final Transition transitC = createTestTransition(TRANSIT_OPEN, controller);
+ transitC.mParallelCollectType = Transition.PARALLEL_TYPE_MUTUAL;
+ final Transition transitSync = createTestTransition(TRANSIT_OPEN, controller);
+ final Transition transitD = createTestTransition(TRANSIT_OPEN, controller);
+
+ controller.startCollectOrQueue(transitA, (deferred) -> {});
+ controller.startCollectOrQueue(transitB, (deferred) -> {});
+ controller.startCollectOrQueue(transitC, (deferred) -> {});
+ controller.startCollectOrQueue(transitSync, (deferred) -> {});
+ controller.startCollectOrQueue(transitD, (deferred) -> {});
+
+ assertTrue(transitA.isCollecting() && !transitA.isStarted());
+ // We still serialize on readiness
+ assertTrue(transitB.isPending());
+ assertTrue(transitC.isPending());
+
+ transitA.start();
+ transitA.setAllReady();
+ transitB.start();
+ transitB.setAllReady();
+
+ // A, B, and C should be collecting in parallel now.
+ assertTrue(transitA.isStarted());
+ assertTrue(transitB.isStarted());
+ assertTrue(transitC.isCollecting() && !transitC.isStarted());
+
+ transitC.start();
+ transitC.setAllReady();
+
+ assertTrue(transitA.isStarted());
+ assertTrue(transitB.isStarted());
+ assertTrue(transitC.isStarted());
+ // Not parallel so should remain pending
+ assertTrue(transitSync.isPending());
+ // After Sync, so should also remain pending.
+ assertTrue(transitD.isPending());
+ // There should always be a collector, since Sync can't collect yet, C should remain.
+ assertEquals(transitC, controller.getCollectingTransition());
+
+ mSyncEngine.tryFinishForTest(transitB.getSyncId());
+
+ // The other transitions should remain waiting.
+ assertTrue(transitA.isStarted());
+ assertTrue(transitB.isPlaying());
+ assertTrue(transitC.isStarted());
+ assertEquals(transitC, controller.getCollectingTransition());
+
+ mSyncEngine.tryFinishForTest(transitC.getSyncId());
+ assertTrue(transitA.isStarted());
+ assertTrue(transitC.isPlaying());
+ // The "collecting" one became ready, so the first "waiting" should move back to collecting.
+ assertEquals(transitA, controller.getCollectingTransition());
+
+ assertTrue(transitSync.isPending());
+ assertTrue(transitD.isPending());
+ mSyncEngine.tryFinishForTest(transitA.getSyncId());
+
+ // Now all collectors are done, so sync can be pulled-off the queue.
+ assertTrue(transitSync.isCollecting() && !transitSync.isStarted());
+ transitSync.start();
+ transitSync.setAllReady();
+ // Since D can run in parallel, it should be pulled-off the queue.
+ assertTrue(transitSync.isStarted());
+ assertTrue(transitD.isPending());
+
+ mSyncEngine.tryFinishForTest(transitSync.getSyncId());
+ assertTrue(transitD.isCollecting());
+
+ transitD.start();
+ transitD.setAllReady();
+ mSyncEngine.tryFinishForTest(transitD.getSyncId());
+
+ // Now nothing should be collecting
+ assertFalse(controller.isCollecting());
+ }
+
private static void makeTaskOrganized(Task... tasks) {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
for (Task t : tasks) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 4530963..01ddcca 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -382,7 +382,7 @@
assertTrue(wallpaperWindow.isVisible());
assertTrue(token.isVisibleRequested());
assertTrue(token.isVisible());
- mWm.mAtmService.getTransitionController().abort(transit);
+ transit.abort();
// In a transition, setting invisible should ONLY set requestedVisible false; otherwise
// wallpaper should remain "visible" until transition is over.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index f85cdf0..07244a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -66,6 +66,7 @@
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -81,6 +82,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.util.SparseArray;
import android.view.Display;
@@ -109,6 +111,7 @@
import com.android.internal.policy.AttributeCache;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
import org.junit.After;
@@ -146,6 +149,7 @@
WindowManagerService mWm;
private final IWindow mIWindow = new TestIWindow();
private Session mMockSession;
+ private boolean mUseFakeSettingsProvider;
DisplayInfo mDisplayInfo = new DisplayInfo();
DisplayContent mDefaultDisplay;
@@ -272,16 +276,9 @@
@After
public void tearDown() throws Exception {
- // Revert back to device overrides.
- mAtm.mWindowManager.mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
- mAtm.mWindowManager.mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
- mAtm.mWindowManager.mLetterboxConfiguration.resetLetterboxVerticalPositionMultiplier();
- mAtm.mWindowManager.mLetterboxConfiguration.resetIsHorizontalReachabilityEnabled();
- mAtm.mWindowManager.mLetterboxConfiguration.resetIsVerticalReachabilityEnabled();
- mAtm.mWindowManager.mLetterboxConfiguration
- .resetIsSplitScreenAspectRatioForUnresizableAppsEnabled();
- mAtm.mWindowManager.mLetterboxConfiguration
- .resetIsDisplayAspectRatioEnabledForFixedOrientationLetterbox();
+ if (mUseFakeSettingsProvider) {
+ FakeSettingsProvider.clearSettingsProvider();
+ }
}
/**
@@ -428,6 +425,17 @@
// Called before display is created.
}
+ /** Avoid writing values to real Settings. */
+ ContentResolver useFakeSettingsProvider() {
+ mUseFakeSettingsProvider = true;
+ FakeSettingsProvider.clearSettingsProvider();
+ final FakeSettingsProvider provider = new FakeSettingsProvider();
+ // SystemServicesTestRule#setUpSystemCore has called spyOn for the ContentResolver.
+ final ContentResolver resolver = mContext.getContentResolver();
+ doReturn(provider.getIContentProvider()).when(resolver).acquireProvider(Settings.AUTHORITY);
+ return resolver;
+ }
+
private WindowState createCommonWindow(WindowState parent, int type, String name) {
final WindowState win = createWindow(parent, type, name);
// Prevent common windows from been IME targets.
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerEvent.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerEvent.java
new file mode 100644
index 0000000..2a55496
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerEvent.java
@@ -0,0 +1,135 @@
+/**
+ * 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.soundtrigger;
+
+import android.util.Slog;
+
+import com.android.server.utils.EventLogger.Event;
+
+import java.util.UUID;
+
+public abstract class SoundTriggerEvent extends Event {
+
+ @Override
+ public Event printLog(int type, String tag) {
+ switch (type) {
+ case ALOGI:
+ Slog.i(tag, eventToString());
+ break;
+ case ALOGE:
+ Slog.e(tag, eventToString());
+ break;
+ case ALOGW:
+ Slog.w(tag, eventToString());
+ break;
+ case ALOGV:
+ default:
+ Slog.v(tag, eventToString());
+ }
+ return this;
+ }
+
+ public static class ServiceEvent extends SoundTriggerEvent {
+ public enum Type {
+ ATTACH,
+ LIST_MODULE,
+ DETACH,
+ }
+
+ private final Type mType;
+ private final String mPackageName;
+ private final String mErrorString;
+
+ public ServiceEvent(Type type) {
+ this(type, null, null);
+ }
+
+ public ServiceEvent(Type type, String packageName) {
+ this(type, packageName, null);
+ }
+
+ public ServiceEvent(Type type, String packageName, String errorString) {
+ mType = type;
+ mPackageName = packageName;
+ mErrorString = errorString;
+ }
+
+ @Override
+ public String eventToString() {
+ var res = new StringBuilder(String.format("%-12s", mType.name()));
+ if (mErrorString != null) {
+ res.append(" ERROR: ").append(mErrorString);
+ }
+ if (mPackageName != null) {
+ res.append(" for: ").append(mPackageName);
+ }
+ return res.toString();
+ }
+ }
+
+ public static class SessionEvent extends SoundTriggerEvent {
+ public enum Type {
+ // Downward calls
+ START_RECOGNITION,
+ STOP_RECOGNITION,
+ LOAD_MODEL,
+ UNLOAD_MODEL,
+ UPDATE_MODEL,
+ DELETE_MODEL,
+ START_RECOGNITION_SERVICE,
+ STOP_RECOGNITION_SERVICE,
+ GET_MODEL_STATE,
+ SET_PARAMETER,
+ GET_MODULE_PROPERTIES,
+ DETACH,
+ // Callback events
+ RECOGNITION,
+ RESUME,
+ RESUME_FAILED,
+ PAUSE,
+ PAUSE_FAILED,
+ RESOURCES_AVAILABLE,
+ MODULE_DIED
+ }
+
+ private final UUID mModelUuid;
+ private final Type mType;
+ private final String mErrorString;
+
+ public SessionEvent(Type type, UUID modelUuid, String errorString) {
+ mType = type;
+ mModelUuid = modelUuid;
+ mErrorString = errorString;
+ }
+
+ public SessionEvent(Type type, UUID modelUuid) {
+ this(type, modelUuid, null);
+ }
+
+ @Override
+ public String eventToString() {
+ var res = new StringBuilder(String.format("%-25s", mType.name()));
+ if (mErrorString != null) {
+ res.append(" ERROR: ").append(mErrorString);
+ }
+ if (mModelUuid != null) {
+ res.append(" for: ").append(mModelUuid);
+ }
+ return res.toString();
+ }
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 07dc1c6..bee75df 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -16,6 +16,9 @@
package com.android.server.soundtrigger;
+import static com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent.Type;
+import static com.android.server.utils.EventLogger.Event.ALOGW;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
@@ -49,7 +52,11 @@
import android.telephony.TelephonyManager;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
+import com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent;
+import com.android.server.utils.EventLogger.Event;
+import com.android.server.utils.EventLogger;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -75,7 +82,6 @@
*/
public class SoundTriggerHelper implements SoundTrigger.StatusListener {
static final String TAG = "SoundTriggerHelper";
- static final boolean DBG = false;
// Module ID if there is no available module to connect to.
public static final int INVALID_MODULE_ID = -1;
@@ -128,8 +134,12 @@
private final int mModuleId;
private final Function<SoundTrigger.StatusListener, SoundTriggerModule> mModuleProvider;
private final Supplier<List<ModuleProperties>> mModulePropertiesProvider;
+ private final EventLogger mEventLogger;
- SoundTriggerHelper(Context context,
+ @GuardedBy("mLock")
+ private boolean mIsDetached = false;
+
+ SoundTriggerHelper(Context context, EventLogger eventLogger,
@NonNull Function<SoundTrigger.StatusListener, SoundTriggerModule> moduleProvider,
int moduleId,
@NonNull Supplier<List<ModuleProperties>> modulePropertiesProvider) {
@@ -140,6 +150,7 @@
mModelDataMap = new HashMap<UUID, ModelData>();
mKeyphraseUuidMap = new HashMap<Integer, UUID>();
mModuleProvider = moduleProvider;
+ mEventLogger = eventLogger;
mModulePropertiesProvider = modulePropertiesProvider;
if (moduleId == INVALID_MODULE_ID) {
mModule = null;
@@ -184,7 +195,7 @@
* recognition.
* @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
*/
- int startGenericRecognition(UUID modelId, GenericSoundModel soundModel,
+ public int startGenericRecognition(UUID modelId, GenericSoundModel soundModel,
IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
boolean runInBatterySaverMode) {
MetricsLogger.count(mContext, "sth_start_recognition", 1);
@@ -195,6 +206,9 @@
}
synchronized (mLock) {
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
ModelData modelData = getOrCreateGenericModelDataLocked(modelId);
if (modelData == null) {
Slog.w(TAG, "Irrecoverable error occurred, check UUID / sound model data.");
@@ -214,7 +228,7 @@
* @param callback The callback for the recognition events related to the given keyphrase.
* @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
*/
- int startKeyphraseRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
+ public int startKeyphraseRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
boolean runInBatterySaverMode) {
synchronized (mLock) {
@@ -223,12 +237,8 @@
return STATUS_ERROR;
}
- if (DBG) {
- Slog.d(TAG, "startKeyphraseRecognition for keyphraseId=" + keyphraseId
- + " soundModel=" + soundModel + ", callback=" + callback.asBinder()
- + ", recognitionConfig=" + recognitionConfig
- + ", runInBatterySaverMode=" + runInBatterySaverMode);
- dumpModelStateLocked();
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
}
ModelData model = getKeyphraseModelDataLocked(keyphraseId);
@@ -290,9 +300,6 @@
}
modelData.setHandle(handle[0]);
modelData.setLoaded();
- if (DBG) {
- Slog.d(TAG, "prepareForRecognition: Sound model loaded with handle:" + handle[0]);
- }
}
return STATUS_OK;
}
@@ -311,7 +318,7 @@
* for the recognition.
* @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
*/
- int startRecognition(SoundModel soundModel, ModelData modelData,
+ private int startRecognition(SoundModel soundModel, ModelData modelData,
IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
int keyphraseId, boolean runInBatterySaverMode) {
synchronized (mLock) {
@@ -385,7 +392,7 @@
*
* @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
*/
- int stopGenericRecognition(UUID modelId, IRecognitionStatusCallback callback) {
+ public int stopGenericRecognition(UUID modelId, IRecognitionStatusCallback callback) {
synchronized (mLock) {
MetricsLogger.count(mContext, "sth_stop_recognition", 1);
if (callback == null || modelId == null) {
@@ -393,7 +400,9 @@
modelId);
return STATUS_ERROR;
}
-
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
ModelData modelData = mModelDataMap.get(modelId);
if (modelData == null || !modelData.isGenericModel()) {
Slog.w(TAG, "Attempting stopRecognition on invalid model with id:" + modelId);
@@ -418,7 +427,7 @@
*
* @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
*/
- int stopKeyphraseRecognition(int keyphraseId, IRecognitionStatusCallback callback) {
+ public int stopKeyphraseRecognition(int keyphraseId, IRecognitionStatusCallback callback) {
synchronized (mLock) {
MetricsLogger.count(mContext, "sth_stop_recognition", 1);
if (callback == null) {
@@ -426,20 +435,15 @@
keyphraseId);
return STATUS_ERROR;
}
-
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
if (modelData == null || !modelData.isKeyphraseModel()) {
Slog.w(TAG, "No model exists for given keyphrase Id " + keyphraseId);
return STATUS_ERROR;
}
- if (DBG) {
- Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId + ", callback =" +
- callback.asBinder());
- Slog.d(TAG, "current callback="
- + ((modelData == null || modelData.getCallback() == null) ? "null" :
- modelData.getCallback().asBinder()));
- }
int status = stopRecognition(modelData, callback);
if (status != SoundTrigger.STATUS_OK) {
return status;
@@ -538,6 +542,11 @@
}
public ModuleProperties getModuleProperties() {
+ synchronized (mLock) {
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
+ }
for (ModuleProperties moduleProperties : mModulePropertiesProvider.get()) {
if (moduleProperties.getId() == mModuleId) {
return moduleProperties;
@@ -547,7 +556,7 @@
return null;
}
- int unloadKeyphraseSoundModel(int keyphraseId) {
+ public int unloadKeyphraseSoundModel(int keyphraseId) {
synchronized (mLock) {
MetricsLogger.count(mContext, "sth_unload_keyphrase_sound_model", 1);
ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
@@ -555,7 +564,9 @@
|| !modelData.isKeyphraseModel()) {
return STATUS_ERROR;
}
-
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
// Stop recognition if it's the current one.
modelData.setRequested(false);
int status = updateRecognitionLocked(modelData, false);
@@ -574,12 +585,15 @@
}
}
- int unloadGenericSoundModel(UUID modelId) {
+ public int unloadGenericSoundModel(UUID modelId) {
synchronized (mLock) {
MetricsLogger.count(mContext, "sth_unload_generic_sound_model", 1);
if (modelId == null || mModule == null) {
return STATUS_ERROR;
}
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
ModelData modelData = mModelDataMap.get(modelId);
if (modelData == null || !modelData.isGenericModel()) {
Slog.w(TAG, "Unload error: Attempting unload invalid generic model with id:" +
@@ -610,24 +624,29 @@
// Remove it from existence.
mModelDataMap.remove(modelId);
- if (DBG) dumpModelStateLocked();
return status;
}
}
- boolean isRecognitionRequested(UUID modelId) {
+ public boolean isRecognitionRequested(UUID modelId) {
synchronized (mLock) {
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
ModelData modelData = mModelDataMap.get(modelId);
return modelData != null && modelData.isRequested();
}
}
- int getGenericModelState(UUID modelId) {
+ public int getGenericModelState(UUID modelId) {
synchronized (mLock) {
MetricsLogger.count(mContext, "sth_get_generic_model_state", 1);
if (modelId == null || mModule == null) {
return STATUS_ERROR;
}
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
ModelData modelData = mModelDataMap.get(modelId);
if (modelData == null || !modelData.isGenericModel()) {
Slog.w(TAG, "GetGenericModelState error: Invalid generic model id:" +
@@ -647,19 +666,20 @@
}
}
- int getKeyphraseModelState(UUID modelId) {
- Slog.w(TAG, "GetKeyphraseModelState error: Not implemented");
- return STATUS_ERROR;
- }
-
- int setParameter(UUID modelId, @ModelParams int modelParam, int value) {
+ public int setParameter(UUID modelId, @ModelParams int modelParam, int value) {
synchronized (mLock) {
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
return setParameterLocked(mModelDataMap.get(modelId), modelParam, value);
}
}
- int setKeyphraseParameter(int keyphraseId, @ModelParams int modelParam, int value) {
+ public int setKeyphraseParameter(int keyphraseId, @ModelParams int modelParam, int value) {
synchronized (mLock) {
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
return setParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam, value);
}
}
@@ -678,14 +698,20 @@
return mModule.setParameter(modelData.getHandle(), modelParam, value);
}
- int getParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
+ public int getParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
synchronized (mLock) {
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
return getParameterLocked(mModelDataMap.get(modelId), modelParam);
}
}
- int getKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
+ public int getKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
synchronized (mLock) {
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
return getParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam);
}
}
@@ -707,15 +733,21 @@
}
@Nullable
- ModelParamRange queryParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
+ public ModelParamRange queryParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
synchronized (mLock) {
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
return queryParameterLocked(mModelDataMap.get(modelId), modelParam);
}
}
@Nullable
- ModelParamRange queryKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
+ public ModelParamRange queryKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
synchronized (mLock) {
+ if (mIsDetached) {
+ throw new IllegalStateException("SoundTriggerHelper has been detached");
+ }
return queryParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam);
}
}
@@ -753,7 +785,6 @@
return;
}
- if (DBG) Slog.d(TAG, "onRecognition: " + event);
synchronized (mLock) {
switch (event.status) {
case SoundTrigger.RECOGNITION_STATUS_ABORT:
@@ -801,12 +832,14 @@
}
try {
+ mEventLogger.enqueue(new SessionEvent(Type.RECOGNITION, model.getModelId()));
callback.onGenericSoundTriggerDetected((GenericRecognitionEvent) event);
- } catch (DeadObjectException e) {
+ } catch (RemoteException e) {
+ mEventLogger.enqueue(new SessionEvent(
+ Type.RECOGNITION, model.getModelId(), "RemoteException")
+ .printLog(ALOGW, TAG));
forceStopAndUnloadModelLocked(model, e);
return;
- } catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in onGenericSoundTriggerDetected", e);
}
RecognitionConfig config = model.getRecognitionConfig();
@@ -825,7 +858,6 @@
@Override
public void onModelUnloaded(int modelHandle) {
- if (DBG) Slog.d(TAG, "onModelUnloaded: " + modelHandle);
synchronized (mLock) {
MetricsLogger.count(mContext, "sth_sound_model_updated", 1);
onModelUnloadedLocked(modelHandle);
@@ -834,7 +866,6 @@
@Override
public void onResourcesAvailable() {
- if (DBG) Slog.d(TAG, "onResourcesAvailable");
synchronized (mLock) {
onResourcesAvailableLocked();
}
@@ -876,6 +907,7 @@
}
private void onResourcesAvailableLocked() {
+ mEventLogger.enqueue(new SessionEvent(Type.RESOURCES_AVAILABLE, null));
updateAllRecognitionsLocked();
}
@@ -888,12 +920,14 @@
try {
IRecognitionStatusCallback callback = modelData.getCallback();
if (callback != null) {
+ mEventLogger.enqueue(new SessionEvent(Type.PAUSE, modelData.getModelId()));
callback.onRecognitionPaused();
}
- } catch (DeadObjectException e) {
- forceStopAndUnloadModelLocked(modelData, e);
} catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
+ mEventLogger.enqueue(new SessionEvent(
+ Type.PAUSE, modelData.getModelId(), "RemoteException")
+ .printLog(ALOGW, TAG));
+ forceStopAndUnloadModelLocked(modelData, e);
}
updateRecognitionLocked(modelData, true);
}
@@ -935,12 +969,14 @@
}
try {
+ mEventLogger.enqueue(new SessionEvent(Type.RECOGNITION, modelData.getModelId()));
modelData.getCallback().onKeyphraseDetected((KeyphraseRecognitionEvent) event);
- } catch (DeadObjectException e) {
+ } catch (RemoteException e) {
+ mEventLogger.enqueue(new SessionEvent(
+ Type.RECOGNITION, modelData.getModelId(), "RemoteException")
+ .printLog(ALOGW, TAG));
forceStopAndUnloadModelLocked(modelData, e);
return;
- } catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in onKeyphraseDetected", e);
}
RecognitionConfig config = modelData.getRecognitionConfig();
@@ -992,10 +1028,13 @@
IRecognitionStatusCallback callback = modelData.getCallback();
if (callback != null) {
try {
+ mEventLogger.enqueue(new SessionEvent(Type.MODULE_DIED,
+ modelData.getModelId()).printLog(ALOGW, TAG));
callback.onModuleDied();
} catch (RemoteException e) {
- Slog.w(TAG, "RemoteException send moduleDied for model handle " +
- modelData.getHandle(), e);
+ mEventLogger.enqueue(new SessionEvent(Type.MODULE_DIED,
+ modelData.getModelId(), "RemoteException")
+ .printLog(ALOGW, TAG));
}
}
}
@@ -1041,7 +1080,6 @@
@Override
public void onCallStateChanged(int state, String arg1) {
- if (DBG) Slog.d(TAG, "onCallStateChanged: " + state);
if (mHandler != null) {
synchronized (mLock) {
@@ -1063,24 +1101,12 @@
}
@SoundTriggerPowerSaveMode int soundTriggerPowerSaveMode =
mPowerManager.getSoundTriggerPowerSaveMode();
- if (DBG) {
- Slog.d(TAG, "onPowerSaveModeChanged: " + soundTriggerPowerSaveMode);
- }
synchronized (mLock) {
onPowerSaveModeChangedLocked(soundTriggerPowerSaveMode);
}
}
}
- void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- synchronized (mLock) {
- pw.print(" module properties=");
- pw.print(" call active=");
- pw.println(mCallActive);
- pw.println(" SoundTrigger Power State=" + mSoundTriggerPowerSaveMode);
- }
- }
-
private void initializeDeviceStateListeners() {
if (mRecognitionRequested) {
return;
@@ -1115,6 +1141,8 @@
*/
public void detach() {
synchronized (mLock) {
+ if (mIsDetached) return;
+ mIsDetached = true;
for (ModelData model : mModelDataMap.values()) {
forceStopAndUnloadModelLocked(model, null);
}
@@ -1289,7 +1317,7 @@
* @param modelData Model data to be used for recognition
* @return True if device state allows recognition to run, false if not.
*/
- boolean isRecognitionAllowedByPowerState(ModelData modelData) {
+ private boolean isRecognitionAllowedByPowerState(ModelData modelData) {
return mSoundTriggerPowerSaveMode == PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED
|| (mSoundTriggerPowerSaveMode == PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY
&& modelData.shouldRunInBatterySaverMode());
@@ -1324,11 +1352,16 @@
// Notify of error if needed.
if (notifyClientOnError) {
try {
+ mEventLogger.enqueue(new SessionEvent(Type.RESUME_FAILED,
+ modelData.getModelId(), String.valueOf(status))
+ .printLog(ALOGW, TAG));
callback.onResumeFailed(status);
- } catch (DeadObjectException e) {
- forceStopAndUnloadModelLocked(modelData, e);
} catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in onResumeFailed", e);
+ mEventLogger.enqueue(new SessionEvent(Type.RESUME_FAILED,
+ modelData.getModelId(),
+ String.valueOf(status) + " - RemoteException")
+ .printLog(ALOGW, TAG));
+ forceStopAndUnloadModelLocked(modelData, e);
}
}
} else {
@@ -1338,17 +1371,16 @@
// Notify of resume if needed.
if (notifyClientOnError) {
try {
+ mEventLogger.enqueue(new SessionEvent(Type.RESUME,
+ modelData.getModelId()));
callback.onRecognitionResumed();
- } catch (DeadObjectException e) {
- forceStopAndUnloadModelLocked(modelData, e);
} catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in onRecognitionResumed", e);
+ mEventLogger.enqueue(new SessionEvent(Type.RESUME,
+ modelData.getModelId(), "RemoteException").printLog(ALOGW, TAG));
+ forceStopAndUnloadModelLocked(modelData, e);
}
}
}
- if (DBG) {
- Slog.d(TAG, "Model being started :" + modelData.toString());
- }
return status;
}
@@ -1368,11 +1400,16 @@
MetricsLogger.count(mContext, "sth_stop_recognition_error", 1);
if (notify) {
try {
+ mEventLogger.enqueue(new SessionEvent(Type.PAUSE_FAILED,
+ modelData.getModelId(), String.valueOf(status))
+ .printLog(ALOGW, TAG));
callback.onPauseFailed(status);
- } catch (DeadObjectException e) {
- forceStopAndUnloadModelLocked(modelData, e);
} catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in onPauseFailed", e);
+ mEventLogger.enqueue(new SessionEvent(Type.PAUSE_FAILED,
+ modelData.getModelId(),
+ String.valueOf(status) + " - RemoteException")
+ .printLog(ALOGW, TAG));
+ forceStopAndUnloadModelLocked(modelData, e);
}
}
} else {
@@ -1381,27 +1418,19 @@
// Notify of pause if needed.
if (notify) {
try {
+ mEventLogger.enqueue(new SessionEvent(Type.PAUSE,
+ modelData.getModelId()));
callback.onRecognitionPaused();
- } catch (DeadObjectException e) {
- forceStopAndUnloadModelLocked(modelData, e);
} catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
+ mEventLogger.enqueue(new SessionEvent(Type.PAUSE,
+ modelData.getModelId(), "RemoteException").printLog(ALOGW, TAG));
+ forceStopAndUnloadModelLocked(modelData, e);
}
}
}
- if (DBG) {
- Slog.d(TAG, "Model being stopped :" + modelData.toString());
- }
return status;
}
- private void dumpModelStateLocked() {
- for (UUID modelId : mModelDataMap.keySet()) {
- ModelData modelData = mModelDataMap.get(modelId);
- Slog.i(TAG, "Model :" + modelData.toString());
- }
- }
-
// Computes whether we have any recognition running at all (voice or generic). Sets
// the mRecognitionRequested variable with the result.
private boolean computeRecognitionRequestedLocked() {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 790be8d..77e5317 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -31,6 +31,9 @@
import static android.provider.Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY;
import static android.provider.Settings.Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT;
+import static com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent.Type;
+import static com.android.server.utils.EventLogger.Event.ALOGW;
+
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.Manifest;
@@ -83,6 +86,7 @@
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.SparseArray;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -90,6 +94,9 @@
import com.android.internal.app.ISoundTriggerSession;
import com.android.server.SoundTriggerInternal;
import com.android.server.SystemService;
+import com.android.server.soundtrigger.SoundTriggerEvent.ServiceEvent;
+import com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent;
+import com.android.server.utils.EventLogger.Event;
import com.android.server.utils.EventLogger;
import java.io.FileDescriptor;
@@ -97,11 +104,16 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
+import java.util.Deque;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
@@ -116,6 +128,7 @@
public class SoundTriggerService extends SystemService {
private static final String TAG = "SoundTriggerService";
private static final boolean DEBUG = true;
+ private static final int SESSION_MAX_EVENT_SIZE = 128;
final Context mContext;
private Object mLock;
@@ -123,6 +136,12 @@
private final LocalSoundTriggerService mLocalSoundTriggerService;
private SoundTriggerDbHelper mDbHelper;
+ private final EventLogger mServiceEventLogger = new EventLogger(256, "Service");
+
+ private final Set<EventLogger> mSessionEventLoggers = ConcurrentHashMap.newKeySet(4);
+ private final Deque<EventLogger> mDetachedSessionEventLoggers = new LinkedBlockingDeque<>(4);
+ private AtomicInteger mSessionIdCounter = new AtomicInteger(0);
+
class SoundModelStatTracker {
private class SoundModelStat {
SoundModelStat() {
@@ -164,7 +183,7 @@
public synchronized void onStop(UUID id) {
SoundModelStat stat = mModelStats.get(id);
if (stat == null) {
- Slog.w(TAG, "error onStop(): Model " + id + " has no stats available");
+ Slog.i(TAG, "error onStop(): Model " + id + " has no stats available");
return;
}
@@ -241,7 +260,9 @@
}
}
- private SoundTriggerHelper newSoundTriggerHelper(ModuleProperties moduleProperties) {
+ private SoundTriggerHelper newSoundTriggerHelper(
+ ModuleProperties moduleProperties, EventLogger eventLogger) {
+
Identity middlemanIdentity = new Identity();
middlemanIdentity.packageName = ActivityThread.currentOpPackageName();
Identity originatorIdentity = IdentityContext.getNonNull();
@@ -260,6 +281,7 @@
return new SoundTriggerHelper(
mContext,
+ eventLogger,
(SoundTrigger.StatusListener statusListener) ->
SoundTrigger.attachModuleAsMiddleman(
moduleId, statusListener, null /* handler */,
@@ -269,14 +291,33 @@
);
}
+ // Helper to add session logger to the capacity limited detached list.
+ // If we are at capacity, remove the oldest, and retry
+ private void addDetachedSessionLogger(EventLogger logger) {
+ // Attempt to push to the top of the queue
+ while (!mDetachedSessionEventLoggers.offerFirst(logger)) {
+ // Remove the oldest element, if one still exists
+ mDetachedSessionEventLoggers.pollLast();
+ }
+ }
+
class SoundTriggerServiceStub extends ISoundTriggerService.Stub {
@Override
public ISoundTriggerSession attachAsOriginator(@NonNull Identity originatorIdentity,
@NonNull ModuleProperties moduleProperties,
@NonNull IBinder client) {
+
+ int sessionId = mSessionIdCounter.getAndIncrement();
+ mServiceEventLogger.enqueue(new ServiceEvent(
+ ServiceEvent.Type.ATTACH, originatorIdentity.packageName + "#" + sessionId));
try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
originatorIdentity)) {
- return new SoundTriggerSessionStub(client, newSoundTriggerHelper(moduleProperties));
+ var eventLogger = new EventLogger(SESSION_MAX_EVENT_SIZE,
+ "SoundTriggerSessionLogs for package: "
+ + Objects.requireNonNull(originatorIdentity.packageName)
+ + "#" + sessionId);
+ return new SoundTriggerSessionStub(client,
+ newSoundTriggerHelper(moduleProperties, eventLogger), eventLogger);
}
}
@@ -285,15 +326,26 @@
@NonNull Identity middlemanIdentity,
@NonNull ModuleProperties moduleProperties,
@NonNull IBinder client) {
+
+ int sessionId = mSessionIdCounter.getAndIncrement();
+ mServiceEventLogger.enqueue(new ServiceEvent(
+ ServiceEvent.Type.ATTACH, originatorIdentity.packageName + "#" + sessionId));
try (SafeCloseable ignored = PermissionUtil.establishIdentityIndirect(mContext,
SOUNDTRIGGER_DELEGATE_IDENTITY, middlemanIdentity,
originatorIdentity)) {
- return new SoundTriggerSessionStub(client, newSoundTriggerHelper(moduleProperties));
+ var eventLogger = new EventLogger(SESSION_MAX_EVENT_SIZE,
+ "SoundTriggerSessionLogs for package: "
+ + Objects.requireNonNull(originatorIdentity.packageName) + "#"
+ + sessionId);
+ return new SoundTriggerSessionStub(client,
+ newSoundTriggerHelper(moduleProperties, eventLogger), eventLogger);
}
}
@Override
public List<ModuleProperties> listModuleProperties(@NonNull Identity originatorIdentity) {
+ mServiceEventLogger.enqueue(new ServiceEvent(
+ ServiceEvent.Type.LIST_MODULE, originatorIdentity.packageName));
try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
originatorIdentity)) {
return listUnderlyingModuleProperties(originatorIdentity);
@@ -316,6 +368,31 @@
throw e.rethrowFromSystemServer();
}
}
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ // Event loggers
+ pw.println("##Service-Wide logs:");
+ mServiceEventLogger.dump(pw, /* indent = */ " ");
+
+ pw.println("\n##Active Session dumps:\n");
+ for (var sessionLogger : mSessionEventLoggers) {
+ sessionLogger.dump(pw, /* indent= */ " ");
+ pw.println("");
+ }
+ pw.println("##Detached Session dumps:\n");
+ for (var sessionLogger : mDetachedSessionEventLoggers) {
+ sessionLogger.dump(pw, /* indent= */ " ");
+ pw.println("");
+ }
+ // enrolled models
+ pw.println("##Enrolled db dump:\n");
+ mDbHelper.dump(pw);
+
+ // stats
+ pw.println("\n##Sound Model Stats dump:\n");
+ mSoundModelStatTracker.dump(pw);
+ }
}
class SoundTriggerSessionStub extends ISoundTriggerSession.Stub {
@@ -326,17 +403,20 @@
private final TreeMap<UUID, SoundModel> mLoadedModels = new TreeMap<>();
private final Object mCallbacksLock = new Object();
private final TreeMap<UUID, IRecognitionStatusCallback> mCallbacks = new TreeMap<>();
+ private final EventLogger mEventLogger;
- SoundTriggerSessionStub(@NonNull IBinder client, SoundTriggerHelper soundTriggerHelper) {
+ SoundTriggerSessionStub(@NonNull IBinder client,
+ SoundTriggerHelper soundTriggerHelper, EventLogger eventLogger) {
mSoundTriggerHelper = soundTriggerHelper;
mClient = client;
mOriginatorIdentity = IdentityContext.getNonNull();
+ mEventLogger = eventLogger;
+ mSessionEventLoggers.add(mEventLogger);
+
try {
- mClient.linkToDeath(() -> {
- clientDied();
- }, 0);
+ mClient.linkToDeath(() -> clientDied(), 0);
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to register death listener.", e);
+ clientDied();
}
}
@@ -344,11 +424,14 @@
public int startRecognition(GenericSoundModel soundModel,
IRecognitionStatusCallback callback,
RecognitionConfig config, boolean runInBatterySaverMode) {
+ mEventLogger.enqueue(new SessionEvent(Type.START_RECOGNITION, getUuid(soundModel)));
+
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
if (soundModel == null) {
- Slog.e(TAG, "Null model passed to startRecognition");
+ mEventLogger.enqueue(new SessionEvent(Type.START_RECOGNITION,
+ getUuid(soundModel), "Invalid sound model").printLog(ALOGW, TAG));
return STATUS_ERROR;
}
@@ -356,13 +439,6 @@
enforceCallingPermission(Manifest.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER);
}
- if (DEBUG) {
- Slog.i(TAG, "startRecognition(): Uuid : " + soundModel.toString());
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "startRecognition(): Uuid : " + soundModel.getUuid().toString()));
-
int ret = mSoundTriggerHelper.startGenericRecognition(soundModel.getUuid(),
soundModel,
callback, config, runInBatterySaverMode);
@@ -375,15 +451,9 @@
@Override
public int stopRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback) {
+ mEventLogger.enqueue(new SessionEvent(Type.STOP_RECOGNITION, getUuid(parcelUuid)));
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
- if (DEBUG) {
- Slog.i(TAG, "stopRecognition(): Uuid : " + parcelUuid);
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent("stopRecognition(): Uuid : "
- + parcelUuid));
-
int ret = mSoundTriggerHelper.stopGenericRecognition(parcelUuid.getUuid(),
callback);
if (ret == STATUS_OK) {
@@ -397,13 +467,6 @@
public SoundTrigger.GenericSoundModel getSoundModel(ParcelUuid soundModelId) {
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
- if (DEBUG) {
- Slog.i(TAG, "getSoundModel(): id = " + soundModelId);
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent("getSoundModel(): id = "
- + soundModelId));
-
SoundTrigger.GenericSoundModel model = mDbHelper.getGenericSoundModel(
soundModelId.getUuid());
return model;
@@ -412,29 +475,18 @@
@Override
public void updateSoundModel(SoundTrigger.GenericSoundModel soundModel) {
+ mEventLogger.enqueue(new SessionEvent(Type.UPDATE_MODEL, getUuid(soundModel)));
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
- if (DEBUG) {
- Slog.i(TAG, "updateSoundModel(): model = " + soundModel);
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent("updateSoundModel(): model = "
- + soundModel));
- mDbHelper.updateGenericSoundModel(soundModel);
+ mDbHelper.updateGenericSoundModel(soundModel);
}
}
@Override
public void deleteSoundModel(ParcelUuid soundModelId) {
+ mEventLogger.enqueue(new SessionEvent(Type.DELETE_MODEL, getUuid(soundModelId)));
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
- if (DEBUG) {
- Slog.i(TAG, "deleteSoundModel(): id = " + soundModelId);
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent("deleteSoundModel(): id = "
- + soundModelId));
-
// Unload the model if it is loaded.
mSoundTriggerHelper.unloadGenericSoundModel(soundModelId.getUuid());
@@ -447,22 +499,14 @@
@Override
public int loadGenericSoundModel(GenericSoundModel soundModel) {
+ mEventLogger.enqueue(new SessionEvent(Type.LOAD_MODEL, getUuid(soundModel)));
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
if (soundModel == null || soundModel.getUuid() == null) {
- Slog.w(TAG, "Invalid sound model");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "loadGenericSoundModel(): Invalid sound model"));
-
+ mEventLogger.enqueue(new SessionEvent(Type.LOAD_MODEL,
+ getUuid(soundModel), "Invalid sound model").printLog(ALOGW, TAG));
return STATUS_ERROR;
}
- if (DEBUG) {
- Slog.i(TAG, "loadGenericSoundModel(): id = " + soundModel.getUuid());
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent("loadGenericSoundModel(): id = "
- + soundModel.getUuid()));
synchronized (mLock) {
SoundModel oldModel = mLoadedModels.get(soundModel.getUuid());
@@ -483,32 +527,22 @@
@Override
public int loadKeyphraseSoundModel(KeyphraseSoundModel soundModel) {
+ mEventLogger.enqueue(new SessionEvent(Type.LOAD_MODEL, getUuid(soundModel)));
+
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
if (soundModel == null || soundModel.getUuid() == null) {
- Slog.w(TAG, "Invalid sound model");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "loadKeyphraseSoundModel(): Invalid sound model"));
+ mEventLogger.enqueue(new SessionEvent(Type.LOAD_MODEL, getUuid(soundModel),
+ "Invalid sound model").printLog(ALOGW, TAG));
return STATUS_ERROR;
}
if (soundModel.getKeyphrases() == null || soundModel.getKeyphrases().length != 1) {
- Slog.w(TAG, "Only one keyphrase per model is currently supported.");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "loadKeyphraseSoundModel(): Only one keyphrase per model"
- + " is currently supported."));
-
+ mEventLogger.enqueue(new SessionEvent(Type.LOAD_MODEL, getUuid(soundModel),
+ "Only one keyphrase supported").printLog(ALOGW, TAG));
return STATUS_ERROR;
}
- if (DEBUG) {
- Slog.i(TAG, "loadKeyphraseSoundModel(): id = " + soundModel.getUuid());
- }
- sEventLogger.enqueue(
- new EventLogger.StringEvent("loadKeyphraseSoundModel(): id = "
- + soundModel.getUuid()));
synchronized (mLock) {
SoundModel oldModel = mLoadedModels.get(soundModel.getUuid());
@@ -530,23 +564,17 @@
@Override
public int startRecognitionForService(ParcelUuid soundModelId, Bundle params,
- ComponentName detectionService, SoundTrigger.RecognitionConfig config) {
+ ComponentName detectionService, SoundTrigger.RecognitionConfig config) {
+ mEventLogger.enqueue(new SessionEvent(Type.START_RECOGNITION_SERVICE,
+ getUuid(soundModelId)));
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
Objects.requireNonNull(soundModelId);
Objects.requireNonNull(detectionService);
Objects.requireNonNull(config);
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
-
enforceDetectionPermissions(detectionService);
- if (DEBUG) {
- Slog.i(TAG, "startRecognition(): id = " + soundModelId);
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "startRecognitionForService(): id = " + soundModelId));
-
IRecognitionStatusCallback callback =
new RemoteSoundTriggerDetectionService(soundModelId.getUuid(), params,
detectionService, Binder.getCallingUserHandle(), config);
@@ -554,10 +582,10 @@
synchronized (mLock) {
SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
if (soundModel == null) {
- Slog.w(TAG, soundModelId + " is not loaded");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "startRecognitionForService():" + soundModelId + " is not loaded"));
+ mEventLogger.enqueue(new SessionEvent(
+ Type.START_RECOGNITION_SERVICE,
+ getUuid(soundModelId),
+ "Model not loaded").printLog(ALOGW, TAG));
return STATUS_ERROR;
}
@@ -566,12 +594,10 @@
existingCallback = mCallbacks.get(soundModelId.getUuid());
}
if (existingCallback != null) {
- Slog.w(TAG, soundModelId + " is already running");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "startRecognitionForService():"
- + soundModelId + " is already running"));
-
+ mEventLogger.enqueue(new SessionEvent(
+ Type.START_RECOGNITION_SERVICE,
+ getUuid(soundModelId),
+ "Model already running").printLog(ALOGW, TAG));
return STATUS_ERROR;
}
int ret;
@@ -581,20 +607,18 @@
(GenericSoundModel) soundModel, callback, config, false);
break;
default:
- Slog.e(TAG, "Unknown model type");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "startRecognitionForService(): Unknown model type"));
-
+ mEventLogger.enqueue(new SessionEvent(
+ Type.START_RECOGNITION_SERVICE,
+ getUuid(soundModelId),
+ "Unsupported model type").printLog(ALOGW, TAG));
return STATUS_ERROR;
}
if (ret != STATUS_OK) {
- Slog.e(TAG, "Failed to start model: " + ret);
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "startRecognitionForService(): Failed to start model:"));
-
+ mEventLogger.enqueue(new SessionEvent(
+ Type.START_RECOGNITION_SERVICE,
+ getUuid(soundModelId),
+ "Model start fail").printLog(ALOGW, TAG));
return ret;
}
synchronized (mCallbacksLock) {
@@ -609,23 +633,20 @@
@Override
public int stopRecognitionForService(ParcelUuid soundModelId) {
+ mEventLogger.enqueue(new SessionEvent(Type.STOP_RECOGNITION_SERVICE,
+ getUuid(soundModelId)));
+
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
- if (DEBUG) {
- Slog.i(TAG, "stopRecognition(): id = " + soundModelId);
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "stopRecognitionForService(): id = " + soundModelId));
synchronized (mLock) {
SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
if (soundModel == null) {
- Slog.w(TAG, soundModelId + " is not loaded");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "stopRecognitionForService(): " + soundModelId
- + " is not loaded"));
+ mEventLogger.enqueue(new SessionEvent(
+ Type.STOP_RECOGNITION_SERVICE,
+ getUuid(soundModelId),
+ "Model not loaded")
+ .printLog(ALOGW, TAG));
return STATUS_ERROR;
}
@@ -634,12 +655,11 @@
callback = mCallbacks.get(soundModelId.getUuid());
}
if (callback == null) {
- Slog.w(TAG, soundModelId + " is not running");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "stopRecognitionForService(): " + soundModelId
- + " is not running"));
-
+ mEventLogger.enqueue(new SessionEvent(
+ Type.STOP_RECOGNITION_SERVICE,
+ getUuid(soundModelId),
+ "Model not running")
+ .printLog(ALOGW, TAG));
return STATUS_ERROR;
}
int ret;
@@ -649,20 +669,21 @@
soundModel.getUuid(), callback);
break;
default:
- Slog.e(TAG, "Unknown model type");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "stopRecognitionForService(): Unknown model type"));
+ mEventLogger.enqueue(new SessionEvent(
+ Type.STOP_RECOGNITION_SERVICE,
+ getUuid(soundModelId),
+ "Unknown model type")
+ .printLog(ALOGW, TAG));
return STATUS_ERROR;
}
if (ret != STATUS_OK) {
- Slog.e(TAG, "Failed to stop model: " + ret);
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "stopRecognitionForService(): Failed to stop model: " + ret));
-
+ mEventLogger.enqueue(new SessionEvent(
+ Type.STOP_RECOGNITION_SERVICE,
+ getUuid(soundModelId),
+ "Failed to stop model")
+ .printLog(ALOGW, TAG));
return ret;
}
synchronized (mCallbacksLock) {
@@ -677,23 +698,18 @@
@Override
public int unloadSoundModel(ParcelUuid soundModelId) {
+ mEventLogger.enqueue(new SessionEvent(Type.UNLOAD_MODEL, getUuid(soundModelId)));
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
- if (DEBUG) {
- Slog.i(TAG, "unloadSoundModel(): id = " + soundModelId);
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent("unloadSoundModel(): id = "
- + soundModelId));
synchronized (mLock) {
SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
if (soundModel == null) {
- Slog.w(TAG, soundModelId + " is not loaded");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "unloadSoundModel(): " + soundModelId + " is not loaded"));
-
+ mEventLogger.enqueue(new SessionEvent(
+ Type.UNLOAD_MODEL,
+ getUuid(soundModelId),
+ "Model not loaded")
+ .printLog(ALOGW, TAG));
return STATUS_ERROR;
}
int ret;
@@ -706,19 +722,19 @@
ret = mSoundTriggerHelper.unloadGenericSoundModel(soundModel.getUuid());
break;
default:
- Slog.e(TAG, "Unknown model type");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "unloadSoundModel(): Unknown model type"));
-
+ mEventLogger.enqueue(new SessionEvent(
+ Type.UNLOAD_MODEL,
+ getUuid(soundModelId),
+ "Unknown model type")
+ .printLog(ALOGW, TAG));
return STATUS_ERROR;
}
if (ret != STATUS_OK) {
- Slog.e(TAG, "Failed to unload model");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "unloadSoundModel(): Failed to unload model"));
-
+ mEventLogger.enqueue(new SessionEvent(
+ Type.UNLOAD_MODEL,
+ getUuid(soundModelId),
+ "Failed to unload model")
+ .printLog(ALOGW, TAG));
return ret;
}
mLoadedModels.remove(soundModelId.getUuid());
@@ -743,24 +759,19 @@
@Override
public int getModelState(ParcelUuid soundModelId) {
+ mEventLogger.enqueue(new SessionEvent(Type.GET_MODEL_STATE, getUuid(soundModelId)));
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
int ret = STATUS_ERROR;
- if (DEBUG) {
- Slog.i(TAG, "getModelState(): id = " + soundModelId);
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent("getModelState(): id = "
- + soundModelId));
synchronized (mLock) {
SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
if (soundModel == null) {
- Slog.w(TAG, soundModelId + " is not loaded");
-
- sEventLogger.enqueue(new EventLogger.StringEvent("getModelState(): "
- + soundModelId + " is not loaded"));
-
+ mEventLogger.enqueue(new SessionEvent(
+ Type.GET_MODEL_STATE,
+ getUuid(soundModelId),
+ "Model is not loaded")
+ .printLog(ALOGW, TAG));
return ret;
}
switch (soundModel.getType()) {
@@ -769,13 +780,13 @@
break;
default:
// SoundModel.TYPE_KEYPHRASE is not supported to increase privacy.
- Slog.e(TAG, "Unsupported model type, " + soundModel.getType());
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "getModelState(): Unsupported model type, "
- + soundModel.getType()));
+ mEventLogger.enqueue(new SessionEvent(
+ Type.GET_MODEL_STATE,
+ getUuid(soundModelId),
+ "Unsupported model type")
+ .printLog(ALOGW, TAG));
break;
}
-
return ret;
}
}
@@ -784,16 +795,11 @@
@Override
@Nullable
public ModuleProperties getModuleProperties() {
+ mEventLogger.enqueue(new SessionEvent(Type.GET_MODULE_PROPERTIES, null));
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
- if (DEBUG) {
- Slog.i(TAG, "getModuleProperties()");
- }
-
synchronized (mLock) {
ModuleProperties properties = mSoundTriggerHelper.getModuleProperties();
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "getModuleProperties(): " + properties));
return properties;
}
}
@@ -802,33 +808,21 @@
@Override
public int setParameter(ParcelUuid soundModelId,
@ModelParams int modelParam, int value) {
+ mEventLogger.enqueue(new SessionEvent(Type.SET_PARAMETER, getUuid(soundModelId)));
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
- if (DEBUG) {
- Slog.d(TAG, "setParameter(): id=" + soundModelId
- + ", param=" + modelParam
- + ", value=" + value);
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "setParameter(): id=" + soundModelId
- + ", param=" + modelParam
- + ", value=" + value));
-
synchronized (mLock) {
SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
if (soundModel == null) {
- Slog.w(TAG, soundModelId + " is not loaded. Loaded models: "
- + mLoadedModels.toString());
-
- sEventLogger.enqueue(new EventLogger.StringEvent("setParameter(): "
- + soundModelId + " is not loaded"));
-
+ mEventLogger.enqueue(new SessionEvent(
+ Type.SET_PARAMETER,
+ getUuid(soundModelId),
+ "Model not loaded")
+ .printLog(ALOGW, TAG));
return STATUS_BAD_VALUE;
}
-
- return mSoundTriggerHelper.setParameter(soundModel.getUuid(), modelParam,
- value);
+ return mSoundTriggerHelper.setParameter(
+ soundModel.getUuid(), modelParam, value);
}
}
}
@@ -839,26 +833,11 @@
throws UnsupportedOperationException, IllegalArgumentException {
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
- if (DEBUG) {
- Slog.d(TAG, "getParameter(): id=" + soundModelId
- + ", param=" + modelParam);
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "getParameter(): id=" + soundModelId
- + ", param=" + modelParam));
-
synchronized (mLock) {
SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
if (soundModel == null) {
- Slog.w(TAG, soundModelId + " is not loaded");
-
- sEventLogger.enqueue(new EventLogger.StringEvent("getParameter(): "
- + soundModelId + " is not loaded"));
-
throw new IllegalArgumentException("sound model is not loaded");
}
-
return mSoundTriggerHelper.getParameter(soundModel.getUuid(), modelParam);
}
}
@@ -870,37 +849,28 @@
@ModelParams int modelParam) {
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
- if (DEBUG) {
- Slog.d(TAG, "queryParameter(): id=" + soundModelId
- + ", param=" + modelParam);
- }
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "queryParameter(): id=" + soundModelId
- + ", param=" + modelParam));
-
synchronized (mLock) {
SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
if (soundModel == null) {
- Slog.w(TAG, soundModelId + " is not loaded");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "queryParameter(): "
- + soundModelId + " is not loaded"));
-
return null;
}
-
return mSoundTriggerHelper.queryParameter(soundModel.getUuid(), modelParam);
}
}
}
private void clientDied() {
- Slog.w(TAG, "Client died, cleaning up session.");
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "Client died, cleaning up session."));
+ mEventLogger.enqueue(new SessionEvent(Type.DETACH, null));
+ mServiceEventLogger.enqueue(new ServiceEvent(
+ ServiceEvent.Type.DETACH, mOriginatorIdentity.packageName, "Client died")
+ .printLog(ALOGW, TAG));
+ detach();
+ }
+
+ private void detach() {
mSoundTriggerHelper.detach();
+ mSessionEventLoggers.remove(mEventLogger);
+ addDetachedSessionLogger(mEventLogger);
}
private void enforceCallingPermission(String permission) {
@@ -922,6 +892,14 @@
}
}
+ private UUID getUuid(ParcelUuid uuid) {
+ return (uuid != null) ? uuid.getUuid() : null;
+ }
+
+ private UUID getUuid(SoundModel model) {
+ return (model != null) ? model.getUuid() : null;
+ }
+
/**
* Local end for a {@link SoundTriggerDetectionService}. Operations are queued up and
* executed when the service connects.
@@ -1068,7 +1046,7 @@
} catch (Exception e) {
Slog.e(TAG, mPuuid + ": Cannot remove client", e);
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": Cannot remove client"));
}
@@ -1091,9 +1069,7 @@
* dropped.
*/
private void destroy() {
- if (DEBUG) Slog.v(TAG, mPuuid + ": destroy");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid + ": destroy"));
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid + ": destroy"));
synchronized (mRemoteServiceLock) {
disconnectLocked();
@@ -1127,7 +1103,7 @@
Slog.e(TAG, mPuuid + ": Could not stop operation "
+ mRunningOpIds.valueAt(i), e);
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": Could not stop operation " + mRunningOpIds.valueAt(
i)));
@@ -1157,7 +1133,7 @@
if (ri == null) {
Slog.w(TAG, mPuuid + ": " + mServiceName + " not found");
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": " + mServiceName + " not found"));
return;
@@ -1168,7 +1144,7 @@
Slog.w(TAG, mPuuid + ": " + mServiceName + " does not require "
+ BIND_SOUND_TRIGGER_DETECTION_SERVICE);
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": " + mServiceName + " does not require "
+ BIND_SOUND_TRIGGER_DETECTION_SERVICE));
@@ -1184,7 +1160,7 @@
} else {
Slog.w(TAG, mPuuid + ": Could not bind to " + mServiceName);
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": Could not bind to " + mServiceName));
}
@@ -1206,7 +1182,7 @@
mPuuid + ": Dropped operation as already destroyed or marked for "
+ "destruction");
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ":Dropped operation as already destroyed or marked for "
+ "destruction"));
@@ -1238,7 +1214,7 @@
mPuuid + ": Dropped operation as too many operations "
+ "were run in last 24 hours");
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": Dropped operation as too many operations "
+ "were run in last 24 hours"));
@@ -1248,7 +1224,7 @@
} catch (Exception e) {
Slog.e(TAG, mPuuid + ": Could not drop operation", e);
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": Could not drop operation"));
}
@@ -1265,7 +1241,7 @@
try {
if (DEBUG) Slog.v(TAG, mPuuid + ": runOp " + opId);
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": runOp " + opId));
op.run(opId, mService);
@@ -1273,7 +1249,7 @@
} catch (Exception e) {
Slog.e(TAG, mPuuid + ": Could not run operation " + opId, e);
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": Could not run operation " + opId));
}
@@ -1303,11 +1279,6 @@
@Override
public void onKeyphraseDetected(SoundTrigger.KeyphraseRecognitionEvent event) {
- Slog.w(TAG, mPuuid + "->" + mServiceName + ": IGNORED onKeyphraseDetected(" + event
- + ")");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid + "->" + mServiceName
- + ": IGNORED onKeyphraseDetected(" + event + ")"));
}
/**
@@ -1325,7 +1296,7 @@
AudioFormat originalFormat = event.getCaptureFormat();
- sEventLogger.enqueue(new EventLogger.StringEvent("createAudioRecordForEvent"));
+ mEventLogger.enqueue(new EventLogger.StringEvent("createAudioRecordForEvent"));
return (new AudioRecord.Builder())
.setAudioAttributes(attributes)
@@ -1340,11 +1311,6 @@
@Override
public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) {
- if (DEBUG) Slog.v(TAG, mPuuid + ": Generic sound trigger event: " + event);
-
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
- + ": Generic sound trigger event: " + event));
-
runOrAddOperation(new Operation(
// always execute:
() -> {
@@ -1376,7 +1342,7 @@
private void onError(int status) {
if (DEBUG) Slog.v(TAG, mPuuid + ": onError: " + status);
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": onError: " + status));
runOrAddOperation(
@@ -1421,27 +1387,17 @@
@Override
public void onRecognitionPaused() {
- Slog.i(TAG, mPuuid + "->" + mServiceName + ": IGNORED onRecognitionPaused");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
- + "->" + mServiceName + ": IGNORED onRecognitionPaused"));
-
}
@Override
public void onRecognitionResumed() {
- Slog.i(TAG, mPuuid + "->" + mServiceName + ": IGNORED onRecognitionResumed");
-
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
- + "->" + mServiceName + ": IGNORED onRecognitionResumed"));
-
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Slog.v(TAG, mPuuid + ": onServiceConnected(" + service + ")");
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": onServiceConnected(" + service + ")"));
synchronized (mRemoteServiceLock) {
@@ -1464,7 +1420,7 @@
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Slog.v(TAG, mPuuid + ": onServiceDisconnected");
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": onServiceDisconnected"));
synchronized (mRemoteServiceLock) {
@@ -1476,7 +1432,7 @@
public void onBindingDied(ComponentName name) {
if (DEBUG) Slog.v(TAG, mPuuid + ": onBindingDied");
- sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ mEventLogger.enqueue(new EventLogger.StringEvent(mPuuid
+ ": onBindingDied"));
synchronized (mRemoteServiceLock) {
@@ -1488,7 +1444,7 @@
public void onNullBinding(ComponentName name) {
Slog.w(TAG, name + " for model " + mPuuid + " returned a null binding");
- sEventLogger.enqueue(new EventLogger.StringEvent(name + " for model "
+ mEventLogger.enqueue(new EventLogger.StringEvent(name + " for model "
+ mPuuid + " returned a null binding"));
synchronized (mRemoteServiceLock) {
@@ -1613,17 +1569,25 @@
private class SessionImpl implements Session {
private final @NonNull SoundTriggerHelper mSoundTriggerHelper;
private final @NonNull IBinder mClient;
+ private final EventLogger mEventLogger;
+ private final Identity mOriginatorIdentity;
- private SessionImpl(
- @NonNull SoundTriggerHelper soundTriggerHelper, @NonNull IBinder client) {
+ private final SparseArray<UUID> mModelUuid = new SparseArray<>(1);
+
+ private SessionImpl(@NonNull SoundTriggerHelper soundTriggerHelper,
+ @NonNull IBinder client,
+ @NonNull EventLogger eventLogger, @NonNull Identity originatorIdentity) {
+
mSoundTriggerHelper = soundTriggerHelper;
mClient = client;
+ mOriginatorIdentity = originatorIdentity;
+ mEventLogger = eventLogger;
+
+ mSessionEventLoggers.add(mEventLogger);
try {
- mClient.linkToDeath(() -> {
- clientDied();
- }, 0);
+ mClient.linkToDeath(() -> clientDied(), 0);
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to register death listener.", e);
+ clientDied();
}
}
@@ -1631,6 +1595,9 @@
public int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig,
boolean runInBatterySaverMode) {
+ mModelUuid.put(keyphraseId, soundModel.getUuid());
+ mEventLogger.enqueue(new SessionEvent(Type.START_RECOGNITION,
+ soundModel.getUuid()));
return mSoundTriggerHelper.startKeyphraseRecognition(keyphraseId, soundModel,
listener, recognitionConfig, runInBatterySaverMode);
}
@@ -1638,16 +1605,21 @@
@Override
public synchronized int stopRecognition(int keyphraseId,
IRecognitionStatusCallback listener) {
+ var uuid = mModelUuid.get(keyphraseId);
+ mEventLogger.enqueue(new SessionEvent(Type.STOP_RECOGNITION, uuid));
return mSoundTriggerHelper.stopKeyphraseRecognition(keyphraseId, listener);
}
@Override
public ModuleProperties getModuleProperties() {
+ mEventLogger.enqueue(new SessionEvent(Type.GET_MODULE_PROPERTIES, null));
return mSoundTriggerHelper.getModuleProperties();
}
@Override
public int setParameter(int keyphraseId, @ModelParams int modelParam, int value) {
+ var uuid = mModelUuid.get(keyphraseId);
+ mEventLogger.enqueue(new SessionEvent(Type.SET_PARAMETER, uuid));
return mSoundTriggerHelper.setKeyphraseParameter(keyphraseId, modelParam, value);
}
@@ -1663,53 +1635,55 @@
}
@Override
- public int unloadKeyphraseModel(int keyphraseId) {
- return mSoundTriggerHelper.unloadKeyphraseSoundModel(keyphraseId);
+ public void detach() {
+ detachInternal();
}
@Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- mSoundTriggerHelper.dump(fd, pw, args);
+ public int unloadKeyphraseModel(int keyphraseId) {
+ var uuid = mModelUuid.get(keyphraseId);
+ mEventLogger.enqueue(new SessionEvent(Type.UNLOAD_MODEL, uuid));
+ return mSoundTriggerHelper.unloadKeyphraseSoundModel(keyphraseId);
}
private void clientDied() {
- Slog.w(TAG, "Client died, cleaning up session.");
- sEventLogger.enqueue(new EventLogger.StringEvent(
- "Client died, cleaning up session."));
+ mServiceEventLogger.enqueue(new ServiceEvent(
+ ServiceEvent.Type.DETACH, mOriginatorIdentity.packageName,
+ "Client died")
+ .printLog(ALOGW, TAG));
+ detachInternal();
+ }
+
+ private void detachInternal() {
+ mEventLogger.enqueue(new SessionEvent(Type.DETACH, null));
+ mSessionEventLoggers.remove(mEventLogger);
+ addDetachedSessionLogger(mEventLogger);
mSoundTriggerHelper.detach();
}
}
@Override
public Session attach(@NonNull IBinder client, ModuleProperties underlyingModule) {
- return new SessionImpl(newSoundTriggerHelper(underlyingModule), client);
+ var identity = IdentityContext.getNonNull();
+ int sessionId = mSessionIdCounter.getAndIncrement();
+ mServiceEventLogger.enqueue(new ServiceEvent(
+ ServiceEvent.Type.ATTACH, identity.packageName + "#" + sessionId));
+ var eventLogger = new EventLogger(SESSION_MAX_EVENT_SIZE,
+ "LocalSoundTriggerEventLogger for package: " +
+ identity.packageName + "#" + sessionId);
+
+ return new SessionImpl(newSoundTriggerHelper(underlyingModule, eventLogger),
+ client, eventLogger, identity);
}
@Override
public List<ModuleProperties> listModuleProperties(Identity originatorIdentity) {
+ mServiceEventLogger.enqueue(new ServiceEvent(
+ ServiceEvent.Type.LIST_MODULE, originatorIdentity.packageName));
try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
originatorIdentity)) {
return listUnderlyingModuleProperties(originatorIdentity);
}
}
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- // log
- sEventLogger.dump(pw);
-
- // enrolled models
- mDbHelper.dump(pw);
-
- // stats
- mSoundModelStatTracker.dump(pw);
- }
}
-
- //=================================================================
- // For logging
-
- private static final EventLogger sEventLogger = new EventLogger(200,
- "SoundTrigger activity");
-
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
index fba0fb4..cbc959c 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
@@ -45,6 +45,16 @@
}
/**
+ * Same as {@link #print(StringBuilder, Object, int)} with default max length.
+ *
+ * @param builder StringBuilder to print into.
+ * @param obj The object to print.
+ */
+ static void print(@NonNull StringBuilder builder, @Nullable Object obj) {
+ print(builder, obj, kDefaultMaxCollectionLength);
+ }
+
+ /**
* A version of {@link #print(Object, int)} that uses a {@link StringBuilder}.
*
* @param builder StringBuilder to print into.
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
index 4c134af..0e796d1 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
@@ -16,6 +16,10 @@
package com.android.server.soundtrigger_middleware;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.*;
+import static com.android.server.utils.EventLogger.Event.ALOGI;
+import static com.android.server.utils.EventLogger.Event.ALOGW;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -41,13 +45,20 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.LatencyTracker;
import com.android.server.LocalServices;
+import com.android.server.utils.EventLogger.Event;
+import com.android.server.utils.EventLogger;
+
import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.LinkedList;
+import java.util.Arrays;
import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
+import java.util.Deque;
+
/**
* An ISoundTriggerMiddlewareService decorator, which adds logging of all API calls (and
@@ -74,9 +85,17 @@
*/
public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInternal, Dumpable {
private static final String TAG = "SoundTriggerMiddlewareLogging";
+ private static final int SESSION_MAX_EVENT_SIZE = 128;
private final @NonNull ISoundTriggerMiddlewareInternal mDelegate;
private final @NonNull LatencyTracker mLatencyTracker;
private final @NonNull Supplier<BatteryStatsInternal> mBatteryStatsInternalSupplier;
+ private final @NonNull EventLogger mServiceEventLogger = new EventLogger(256,
+ "Service Events");
+
+ private final Set<EventLogger> mSessionEventLoggers = ConcurrentHashMap.newKeySet(4);
+ private final Deque<EventLogger> mDetachedSessionEventLoggers = new LinkedBlockingDeque<>(4);
+ private final AtomicInteger mSessionCount = new AtomicInteger(0);
+
public SoundTriggerMiddlewareLogging(@NonNull Context context,
@NonNull ISoundTriggerMiddlewareInternal delegate) {
@@ -99,10 +118,19 @@
SoundTriggerModuleDescriptor[] listModules() {
try {
SoundTriggerModuleDescriptor[] result = mDelegate.listModules();
- logReturn("listModules", result);
+ var moduleSummary = Arrays.stream(result).map((descriptor) ->
+ new ModulePropertySummary(descriptor.handle,
+ descriptor.properties.implementor,
+ descriptor.properties.version)).toArray(ModulePropertySummary[]::new);
+
+ mServiceEventLogger.enqueue(ServiceEvent.createForReturn(
+ ServiceEvent.Type.LIST_MODULE,
+ IdentityContext.get().packageName, moduleSummary).printLog(ALOGI, TAG));
return result;
} catch (Exception e) {
- logException("listModules", e);
+ mServiceEventLogger.enqueue(ServiceEvent.createForException(
+ ServiceEvent.Type.LIST_MODULE,
+ IdentityContext.get().packageName, e).printLog(ALOGW, TAG));
throw e;
}
}
@@ -111,12 +139,29 @@
public @NonNull
ISoundTriggerModule attach(int handle, ISoundTriggerCallback callback) {
try {
- ModuleLogging result = new ModuleLogging(callback);
- result.attach(mDelegate.attach(handle, result.getCallbackWrapper()));
- logReturn("attach", result, handle, callback);
+ var originatorIdentity = IdentityContext.getNonNull();
+ String packageIdentification = originatorIdentity.packageName
+ + mSessionCount.getAndIncrement();
+ ModuleLogging result = new ModuleLogging();
+ var eventLogger = new EventLogger(SESSION_MAX_EVENT_SIZE,
+ "Session logger for: " + packageIdentification);
+
+ var callbackWrapper = new CallbackLogging(callback, eventLogger, originatorIdentity);
+
+ result.attach(mDelegate.attach(handle, callbackWrapper), eventLogger);
+
+ mServiceEventLogger.enqueue(ServiceEvent.createForReturn(
+ ServiceEvent.Type.ATTACH,
+ packageIdentification, result, handle, callback)
+ .printLog(ALOGI, TAG));
+
+ mSessionEventLoggers.add(eventLogger);
return result;
} catch (Exception e) {
- logException("attach", e, handle, callback);
+ mServiceEventLogger.enqueue(ServiceEvent.createForException(
+ ServiceEvent.Type.ATTACH,
+ IdentityContext.get().packageName, e, handle, callback)
+ .printLog(ALOGW, TAG));
throw e;
}
}
@@ -127,44 +172,27 @@
return mDelegate.toString();
}
- private void logException(String methodName, Exception ex, Object... args) {
- logExceptionWithObject(this, IdentityContext.get(), methodName, ex, args);
- }
-
- private void logReturn(String methodName, Object retVal, Object... args) {
- logReturnWithObject(this, IdentityContext.get(), methodName, retVal, args);
- }
-
- private void logVoidReturn(String methodName, Object... args) {
- logVoidReturnWithObject(this, IdentityContext.get(), methodName, args);
- }
-
private class ModuleLogging implements ISoundTriggerModule {
private ISoundTriggerModule mDelegate;
- private final @NonNull CallbackLogging mCallbackWrapper;
- private final @NonNull Identity mOriginatorIdentity;
+ private EventLogger mEventLogger;
- ModuleLogging(@NonNull ISoundTriggerCallback callback) {
- mCallbackWrapper = new CallbackLogging(callback);
- mOriginatorIdentity = IdentityContext.getNonNull();
- }
-
- void attach(@NonNull ISoundTriggerModule delegate) {
+ void attach(@NonNull ISoundTriggerModule delegate, EventLogger eventLogger) {
mDelegate = delegate;
- }
-
- ISoundTriggerCallback getCallbackWrapper() {
- return mCallbackWrapper;
+ mEventLogger = eventLogger;
}
@Override
public int loadModel(SoundModel model) throws RemoteException {
try {
int result = mDelegate.loadModel(model);
- logReturn("loadModel", result, model);
+ mEventLogger.enqueue(SessionEvent.createForReturn(
+ LOAD_MODEL, result, model.uuid)
+ .printLog(ALOGI, TAG));
return result;
} catch (Exception e) {
- logException("loadModel", e, model);
+ mEventLogger.enqueue(SessionEvent.createForReturn(
+ LOAD_MODEL, e, model.uuid)
+ .printLog(ALOGW, TAG));
throw e;
}
}
@@ -173,10 +201,14 @@
public int loadPhraseModel(PhraseSoundModel model) throws RemoteException {
try {
int result = mDelegate.loadPhraseModel(model);
- logReturn("loadPhraseModel", result, model);
+ mEventLogger.enqueue(SessionEvent.createForReturn(
+ LOAD_PHRASE_MODEL, result, model.common.uuid)
+ .printLog(ALOGI, TAG));
return result;
} catch (Exception e) {
- logException("loadPhraseModel", e, model);
+ mEventLogger.enqueue(SessionEvent.createForException(
+ LOAD_PHRASE_MODEL, e, model.common.uuid)
+ .printLog(ALOGW, TAG));
throw e;
}
}
@@ -185,9 +217,13 @@
public void unloadModel(int modelHandle) throws RemoteException {
try {
mDelegate.unloadModel(modelHandle);
- logVoidReturn("unloadModel", modelHandle);
+ mEventLogger.enqueue(SessionEvent.createForVoid(
+ UNLOAD_MODEL, modelHandle)
+ .printLog(ALOGI, TAG));
} catch (Exception e) {
- logException("unloadModel", e, modelHandle);
+ mEventLogger.enqueue(SessionEvent.createForException(
+ UNLOAD_MODEL, e, modelHandle)
+ .printLog(ALOGW, TAG));
throw e;
}
}
@@ -197,9 +233,13 @@
throws RemoteException {
try {
mDelegate.startRecognition(modelHandle, config);
- logVoidReturn("startRecognition", modelHandle, config);
+ mEventLogger.enqueue(SessionEvent.createForVoid(
+ START_RECOGNITION, modelHandle, config)
+ .printLog(ALOGI, TAG));
} catch (Exception e) {
- logException("startRecognition", e, modelHandle, config);
+ mEventLogger.enqueue(SessionEvent.createForException(
+ START_RECOGNITION, e, modelHandle, config)
+ .printLog(ALOGW, TAG));
throw e;
}
}
@@ -208,9 +248,13 @@
public void stopRecognition(int modelHandle) throws RemoteException {
try {
mDelegate.stopRecognition(modelHandle);
- logVoidReturn("stopRecognition", modelHandle);
+ mEventLogger.enqueue(SessionEvent.createForVoid(
+ STOP_RECOGNITION, modelHandle)
+ .printLog(ALOGI, TAG));
} catch (Exception e) {
- logException("stopRecognition", e, modelHandle);
+ mEventLogger.enqueue(SessionEvent.createForException(
+ STOP_RECOGNITION, e, modelHandle)
+ .printLog(ALOGW, TAG));
throw e;
}
}
@@ -219,9 +263,13 @@
public void forceRecognitionEvent(int modelHandle) throws RemoteException {
try {
mDelegate.forceRecognitionEvent(modelHandle);
- logVoidReturn("forceRecognitionEvent", modelHandle);
+ mEventLogger.enqueue(SessionEvent.createForVoid(
+ FORCE_RECOGNITION, modelHandle)
+ .printLog(ALOGI, TAG));
} catch (Exception e) {
- logException("forceRecognitionEvent", e, modelHandle);
+ mEventLogger.enqueue(SessionEvent.createForException(
+ FORCE_RECOGNITION, e, modelHandle)
+ .printLog(ALOGW, TAG));
throw e;
}
}
@@ -231,9 +279,13 @@
throws RemoteException {
try {
mDelegate.setModelParameter(modelHandle, modelParam, value);
- logVoidReturn("setModelParameter", modelHandle, modelParam, value);
+ mEventLogger.enqueue(SessionEvent.createForVoid(
+ SET_MODEL_PARAMETER, modelHandle, modelParam, value)
+ .printLog(ALOGI, TAG));
} catch (Exception e) {
- logException("setModelParameter", e, modelHandle, modelParam, value);
+ mEventLogger.enqueue(SessionEvent.createForException(
+ SET_MODEL_PARAMETER, e, modelHandle, modelParam, value)
+ .printLog(ALOGW, TAG));
throw e;
}
}
@@ -242,10 +294,14 @@
public int getModelParameter(int modelHandle, int modelParam) throws RemoteException {
try {
int result = mDelegate.getModelParameter(modelHandle, modelParam);
- logReturn("getModelParameter", result, modelHandle, modelParam);
+ mEventLogger.enqueue(SessionEvent.createForReturn(
+ GET_MODEL_PARAMETER, result, modelHandle, modelParam)
+ .printLog(ALOGI, TAG));
return result;
} catch (Exception e) {
- logException("getModelParameter", e, modelHandle, modelParam);
+ mEventLogger.enqueue(SessionEvent.createForException(
+ GET_MODEL_PARAMETER, e, modelHandle, modelParam)
+ .printLog(ALOGW, TAG));
throw e;
}
}
@@ -256,10 +312,14 @@
try {
ModelParameterRange result = mDelegate.queryModelParameterSupport(modelHandle,
modelParam);
- logReturn("queryModelParameterSupport", result, modelHandle, modelParam);
+ mEventLogger.enqueue(SessionEvent.createForReturn(
+ QUERY_MODEL_PARAMETER, result, modelHandle, modelParam)
+ .printLog(ALOGI, TAG));
return result;
} catch (Exception e) {
- logException("queryModelParameterSupport", e, modelHandle, modelParam);
+ mEventLogger.enqueue(SessionEvent.createForException(
+ QUERY_MODEL_PARAMETER, e, modelHandle, modelParam)
+ .printLog(ALOGW, TAG));
throw e;
}
}
@@ -267,10 +327,20 @@
@Override
public void detach() throws RemoteException {
try {
+ if (mSessionEventLoggers.remove(mEventLogger)) {
+ while (!mDetachedSessionEventLoggers.offerFirst(mEventLogger)) {
+ // Remove the oldest element, if one still exists
+ mDetachedSessionEventLoggers.pollLast();
+ }
+ }
mDelegate.detach();
- logVoidReturn("detach");
+ mEventLogger.enqueue(SessionEvent.createForVoid(
+ DETACH)
+ .printLog(ALOGI, TAG));
} catch (Exception e) {
- logException("detach", e);
+ mEventLogger.enqueue(SessionEvent.createForException(
+ DETACH, e)
+ .printLog(ALOGW, TAG));
throw e;
}
}
@@ -285,107 +355,112 @@
public String toString() {
return Objects.toString(mDelegate);
}
+ }
- private void logException(String methodName, Exception ex, Object... args) {
- logExceptionWithObject(this, mOriginatorIdentity, methodName, ex, args);
+ private class CallbackLogging implements ISoundTriggerCallback {
+ private final ISoundTriggerCallback mCallbackDelegate;
+ private final EventLogger mEventLogger;
+ private final Identity mOriginatorIdentity;
+
+ private CallbackLogging(ISoundTriggerCallback delegate,
+ EventLogger eventLogger, Identity originatorIdentity) {
+ mCallbackDelegate = Objects.requireNonNull(delegate);
+ mEventLogger = Objects.requireNonNull(eventLogger);
+ mOriginatorIdentity = originatorIdentity;
}
- private void logReturn(String methodName, Object retVal, Object... args) {
- logReturnWithObject(this, mOriginatorIdentity, methodName, retVal, args);
+ @Override
+ public void onRecognition(int modelHandle, RecognitionEvent event, int captureSession)
+ throws RemoteException {
+ try {
+ mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
+ SystemClock.elapsedRealtime(), mOriginatorIdentity.uid);
+ mCallbackDelegate.onRecognition(modelHandle, event, captureSession);
+ mEventLogger.enqueue(SessionEvent.createForVoid(
+ RECOGNITION, modelHandle, event, captureSession)
+ .printLog(ALOGI, TAG));
+ } catch (Exception e) {
+ mEventLogger.enqueue(SessionEvent.createForException(
+ RECOGNITION, e, modelHandle, event, captureSession)
+ .printLog(ALOGW, TAG));
+ throw e;
+ }
}
- private void logVoidReturn(String methodName, Object... args) {
- logVoidReturnWithObject(this, mOriginatorIdentity, methodName, args);
+ @Override
+ public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event,
+ int captureSession)
+ throws RemoteException {
+ try {
+ mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
+ SystemClock.elapsedRealtime(), mOriginatorIdentity.uid);
+ startKeyphraseEventLatencyTracking(event);
+ mCallbackDelegate.onPhraseRecognition(modelHandle, event, captureSession);
+ mEventLogger.enqueue(SessionEvent.createForVoid(
+ RECOGNITION, modelHandle, event, captureSession)
+ .printLog(ALOGI, TAG));
+ } catch (Exception e) {
+ mEventLogger.enqueue(SessionEvent.createForException(
+ RECOGNITION, e, modelHandle, event, captureSession)
+ .printLog(ALOGW, TAG));
+ throw e;
+ }
}
- private class CallbackLogging implements ISoundTriggerCallback {
- private final ISoundTriggerCallback mCallbackDelegate;
-
- private CallbackLogging(ISoundTriggerCallback delegate) {
- mCallbackDelegate = delegate;
+ @Override
+ public void onModelUnloaded(int modelHandle) throws RemoteException {
+ try {
+ mCallbackDelegate.onModelUnloaded(modelHandle);
+ mEventLogger.enqueue(SessionEvent.createForVoid(
+ MODEL_UNLOADED, modelHandle)
+ .printLog(ALOGI, TAG));
+ } catch (Exception e) {
+ mEventLogger.enqueue(SessionEvent.createForException(
+ MODEL_UNLOADED, e, modelHandle)
+ .printLog(ALOGW, TAG));
+ throw e;
}
+ }
- @Override
- public void onRecognition(int modelHandle, RecognitionEvent event, int captureSession)
- throws RemoteException {
- try {
- mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
- SystemClock.elapsedRealtime(), mOriginatorIdentity.uid);
- mCallbackDelegate.onRecognition(modelHandle, event, captureSession);
- logVoidReturn("onRecognition", modelHandle, event);
- } catch (Exception e) {
- logException("onRecognition", e, modelHandle, event);
- throw e;
- }
+ @Override
+ public void onResourcesAvailable() throws RemoteException {
+ try {
+ mCallbackDelegate.onResourcesAvailable();
+ mEventLogger.enqueue(SessionEvent.createForVoid(
+ RESOURCES_AVAILABLE)
+ .printLog(ALOGI, TAG));
+ } catch (Exception e) {
+ mEventLogger.enqueue(SessionEvent.createForException(
+ RESOURCES_AVAILABLE, e)
+ .printLog(ALOGW, TAG));
+ throw e;
}
+ }
- @Override
- public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event,
- int captureSession)
- throws RemoteException {
- try {
- mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
- SystemClock.elapsedRealtime(), mOriginatorIdentity.uid);
- startKeyphraseEventLatencyTracking(event);
- mCallbackDelegate.onPhraseRecognition(modelHandle, event, captureSession);
- logVoidReturn("onPhraseRecognition", modelHandle, event);
- } catch (Exception e) {
- logException("onPhraseRecognition", e, modelHandle, event);
- throw e;
- }
+ @Override
+ public void onModuleDied() throws RemoteException {
+ try {
+ mCallbackDelegate.onModuleDied();
+ mEventLogger.enqueue(SessionEvent.createForVoid(
+ MODULE_DIED)
+ .printLog(ALOGW, TAG));
+ } catch (Exception e) {
+ mEventLogger.enqueue(SessionEvent.createForException(
+ MODULE_DIED, e)
+ .printLog(ALOGW, TAG));
+ throw e;
}
+ }
- @Override
- public void onModelUnloaded(int modelHandle) throws RemoteException {
- try {
- mCallbackDelegate.onModelUnloaded(modelHandle);
- logVoidReturn("onModelUnloaded", modelHandle);
- } catch (Exception e) {
- logException("onModelUnloaded", e, modelHandle);
- throw e;
- }
- }
+ @Override
+ public IBinder asBinder() {
+ return mCallbackDelegate.asBinder();
+ }
- @Override
- public void onResourcesAvailable() throws RemoteException {
- try {
- mCallbackDelegate.onResourcesAvailable();
- logVoidReturn("onResourcesAvailable");
- } catch (Exception e) {
- logException("onResourcesAvailable", e);
- throw e;
- }
- }
-
- @Override
- public void onModuleDied() throws RemoteException {
- try {
- mCallbackDelegate.onModuleDied();
- logVoidReturn("onModuleDied");
- } catch (Exception e) {
- logException("onModuleDied", e);
- throw e;
- }
- }
-
- private void logException(String methodName, Exception ex, Object... args) {
- logExceptionWithObject(this, mOriginatorIdentity, methodName, ex, args);
- }
-
- private void logVoidReturn(String methodName, Object... args) {
- logVoidReturnWithObject(this, mOriginatorIdentity, methodName, args);
- }
-
- @Override
- public IBinder asBinder() {
- return mCallbackDelegate.asBinder();
- }
-
- // Override toString() in order to have the delegate's ID in it.
- @Override
- public String toString() {
- return Objects.toString(mCallbackDelegate);
- }
+ // Override toString() in order to have the delegate's ID in it.
+ @Override
+ public String toString() {
+ return Objects.toString(mCallbackDelegate);
}
}
@@ -418,105 +493,193 @@
latencyTrackerTag);
}
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Actual logging logic below.
- private static final int NUM_EVENTS_TO_DUMP = 64;
- private final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss:SSS");
- private final @NonNull LinkedList<Event> mLastEvents = new LinkedList<>();
-
- static private class Event {
- public final long timestamp = System.currentTimeMillis();
- public final String message;
-
- private Event(String message) {
- this.message = message;
- }
- }
-
- private static String printArgs(@NonNull Object[] args) {
- StringBuilder result = new StringBuilder();
+ private static StringBuilder printArgs(StringBuilder builder, @NonNull Object[] args) {
for (int i = 0; i < args.length; ++i) {
if (i > 0) {
- result.append(", ");
+ builder.append(", ");
}
- printObject(result, args[i]);
+ ObjectPrinter.print(builder, args[i]);
}
- return result.toString();
- }
-
- private static void printObject(@NonNull StringBuilder builder, @Nullable Object obj) {
- ObjectPrinter.print(builder, obj, 16);
- }
-
- private static String printObject(@Nullable Object obj) {
- StringBuilder builder = new StringBuilder();
- printObject(builder, obj);
- return builder.toString();
- }
-
- private void logReturnWithObject(@NonNull Object object, @Nullable Identity originatorIdentity,
- String methodName,
- @Nullable Object retVal,
- @NonNull Object[] args) {
- final String message = String.format("%s[this=%s, client=%s](%s) -> %s", methodName,
- object,
- printObject(originatorIdentity),
- printArgs(args),
- printObject(retVal));
- Slog.i(TAG, message);
- appendMessage(message);
- }
-
- private void logVoidReturnWithObject(@NonNull Object object,
- @Nullable Identity originatorIdentity, @NonNull String methodName,
- @NonNull Object[] args) {
- final String message = String.format("%s[this=%s, client=%s](%s)", methodName,
- object,
- printObject(originatorIdentity),
- printArgs(args));
- Slog.i(TAG, message);
- appendMessage(message);
- }
-
- private void logExceptionWithObject(@NonNull Object object,
- @Nullable Identity originatorIdentity, @NonNull String methodName,
- @NonNull Exception ex,
- Object[] args) {
- final String message = String.format("%s[this=%s, client=%s](%s) threw", methodName,
- object,
- printObject(originatorIdentity),
- printArgs(args));
- Slog.e(TAG, message, ex);
- appendMessage(message + " " + ex.toString());
- }
-
- private void appendMessage(@NonNull String message) {
- Event event = new Event(message);
- synchronized (mLastEvents) {
- if (mLastEvents.size() > NUM_EVENTS_TO_DUMP) {
- mLastEvents.remove();
- }
- mLastEvents.add(event);
- }
+ return builder;
}
@Override
public void dump(PrintWriter pw) {
- pw.println();
- pw.println("=========================================");
- pw.println("Last events");
- pw.println("=========================================");
- synchronized (mLastEvents) {
- for (Event event : mLastEvents) {
- pw.print(DATE_FORMAT.format(new Date(event.timestamp)));
- pw.print('\t');
- pw.println(event.message);
- }
+ // Event loggers
+ pw.println("##Service-Wide logs:");
+ mServiceEventLogger.dump(pw, /* indent = */ " ");
+
+ pw.println("\n##Active Session dumps:\n");
+ for (var sessionLogger : mSessionEventLoggers) {
+ sessionLogger.dump(pw, /* indent= */ " ");
+ pw.println("");
}
- pw.println();
+ pw.println("##Detached Session dumps:\n");
+ for (var sessionLogger : mDetachedSessionEventLoggers) {
+ sessionLogger.dump(pw, /* indent= */ " ");
+ pw.println("");
+ }
if (mDelegate instanceof Dumpable) {
((Dumpable) mDelegate).dump(pw);
}
}
+
+ public static void printSystemLog(int type, String tag, String message, Exception e) {
+ switch (type) {
+ case Event.ALOGI:
+ Slog.i(tag, message, e);
+ break;
+ case Event.ALOGE:
+ Slog.e(tag, message, e);
+ break;
+ case Event.ALOGW:
+ Slog.w(tag, message, e);
+ break;
+ case Event.ALOGV:
+ default:
+ Slog.v(tag, message, e);
+ }
+ }
+
+ public static class ServiceEvent extends Event {
+ private final Type mType;
+ private final String mPackageName;
+ private final Object mReturnValue;
+ private final Object[] mParams;
+ private final Exception mException;
+
+ public enum Type {
+ ATTACH,
+ LIST_MODULE,
+ }
+
+ public static ServiceEvent createForException(Type type, String packageName,
+ Exception exception, Object... params) {
+ return new ServiceEvent(exception, type, packageName, null, params);
+ }
+
+ public static ServiceEvent createForReturn(Type type, String packageName,
+ Object returnValue, Object... params) {
+ return new ServiceEvent(null , type, packageName, returnValue, params);
+ }
+
+ private ServiceEvent(Exception exception, Type type, String packageName, Object returnValue,
+ Object... params) {
+ mException = exception;
+ mType = type;
+ mPackageName = packageName;
+ mReturnValue = returnValue;
+ mParams = params;
+ }
+
+ @Override
+ public Event printLog(int type, String tag) {
+ printSystemLog(type, tag, eventToString(), mException);
+ return this;
+ }
+
+ @Override
+ public String eventToString() {
+ var sb = new StringBuilder(mType.name()).append(" [client= ");
+ ObjectPrinter.print(sb, mPackageName);
+ sb.append("] (");
+ printArgs(sb, mParams);
+ sb.append(") -> ");
+ if (mException != null) {
+ sb.append("ERROR: ");
+ ObjectPrinter.print(sb, mException);
+ } else {
+ ObjectPrinter.print(sb, mReturnValue);
+ }
+ return sb.toString();
+ }
+ }
+
+ public static class SessionEvent extends Event {
+ public enum Type {
+ LOAD_MODEL,
+ LOAD_PHRASE_MODEL,
+ START_RECOGNITION,
+ STOP_RECOGNITION,
+ FORCE_RECOGNITION,
+ UNLOAD_MODEL,
+ GET_MODEL_PARAMETER,
+ SET_MODEL_PARAMETER,
+ QUERY_MODEL_PARAMETER,
+ DETACH,
+ RECOGNITION,
+ MODEL_UNLOADED,
+ MODULE_DIED,
+ RESOURCES_AVAILABLE,
+ }
+
+ private final Type mType;
+ private final Exception mException;
+ private final Object mReturnValue;
+ private final Object[] mParams;
+
+ public static SessionEvent createForException(Type type, Exception exception,
+ Object... params) {
+ return new SessionEvent(exception, type, null, params);
+ }
+
+ public static SessionEvent createForReturn(Type type,
+ Object returnValue, Object... params) {
+ return new SessionEvent(null , type, returnValue, params);
+ }
+
+ public static SessionEvent createForVoid(Type type, Object... params) {
+ return new SessionEvent(null, type, null, params);
+ }
+
+
+ private SessionEvent(Exception exception, Type type, Object returnValue,
+ Object... params) {
+ mException = exception;
+ mType = type;
+ mReturnValue = returnValue;
+ mParams = params;
+ }
+
+ @Override
+ public Event printLog(int type, String tag) {
+ printSystemLog(type, tag, eventToString(), mException);
+ return this;
+ }
+
+ @Override
+ public String eventToString() {
+ var sb = new StringBuilder(mType.name());
+ sb.append(" (");
+ printArgs(sb, mParams);
+ sb.append(")");
+ if (mException != null) {
+ sb.append(" -> ERROR: ");
+ ObjectPrinter.print(sb, mException);
+ } else if (mReturnValue != null) {
+ sb.append(" -> ");
+ ObjectPrinter.print(sb, mReturnValue);
+ }
+ return sb.toString();
+ }
+ }
+
+ private static final class ModulePropertySummary {
+ private int mId;
+ private String mImplementor;
+ private int mVersion;
+
+ ModulePropertySummary(int id, String implementor, int version) {
+ mId = id;
+ mImplementor = implementor;
+ mVersion = version;
+ }
+
+ @Override
+ public String toString() {
+ return "{Id: " + mId + ", Implementor: " + mImplementor
+ + ", Version: " + mVersion + "}";
+ }
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
index 2413072..65c95d1 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
@@ -339,7 +339,11 @@
} catch (IOException e) {
mAudioSource.closeWithError(e.getMessage());
mAudioSink.closeWithError(e.getMessage());
- Slog.e(TAG, mStreamTaskId + ": Failed to copy audio stream", e);
+ // This is expected when VIS closes the read side of the pipe on their end,
+ // so when the HotwordAudioStreamCopier tries to write, we will get that broken
+ // pipe error. HDS is also closing the write side of the pipe (the system is on the
+ // read end of that pipe).
+ Slog.i(TAG, mStreamTaskId + ": Failed to copy audio stream", e);
HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__CLOSE_ERROR_FROM_SYSTEM,
mUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0,
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionBinderProxy.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionBinderProxy.java
index dd9fee3..0ef2f06 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionBinderProxy.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionBinderProxy.java
@@ -69,4 +69,9 @@
public SoundTrigger.ModelParamRange queryParameter(int i, int i1) throws RemoteException {
return mDelegate.queryParameter(i, i1);
}
+
+ @Override
+ public void detach() throws RemoteException {
+ mDelegate.detach();
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
index c0c3e6f..0f8a945 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
@@ -113,6 +113,15 @@
"This object isn't intended to be used as a Binder.");
}
+ @Override
+ public void detach() {
+ try {
+ mDelegate.detach();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
// TODO: Share this code with SoundTriggerMiddlewarePermission.
private boolean isHoldingPermissions() {
try {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 1d7b966..27f3fb3 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1856,6 +1856,11 @@
"This object isn't intended to be used as a Binder.");
}
+ @Override
+ public void detach() {
+ mSession.detach();
+ }
+
private int unloadKeyphraseModel(int keyphraseId) {
final long caller = Binder.clearCallingIdentity();
try {
@@ -2133,8 +2138,6 @@
mImpl.dumpLocked(fd, pw, args);
}
}
-
- mSoundTriggerInternal.dump(fd, pw, args);
}
@Override
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 282b64d..18e4c37 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3008,4 +3008,14 @@
* @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
*/
boolean setSatelliteListeningTimeoutDuration(in long timeoutMillis);
+
+ /**
+ * This API can be used by only CTS to update satellite pointing UI app package and class names.
+ *
+ * @param packageName The package name of the satellite pointing UI app.
+ * @param className The class name of the satellite pointing UI app.
+ * @return {@code true} if the satellite pointing UI app package and class is set successfully,
+ * {@code false} otherwise.
+ */
+ boolean setSatellitePointingUiClassName(in String packageName, in String className);
}