Merge "Provide color override path through keyguard preview renderer" into udc-dev
diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl
index 0c920f1..60c2eed 100644
--- a/core/java/android/app/IUidObserver.aidl
+++ b/core/java/android/app/IUidObserver.aidl
@@ -58,8 +58,9 @@
* Report a proc oom adj change associated with a uid.
*
* @param uid The uid for which the state change is being reported.
+ * @param adj The minimum OOM adj among all processes with this uid.
*/
- void onUidProcAdjChanged(int uid);
+ void onUidProcAdjChanged(int uid, int adj);
// =============== End of transactions used on native side as well ============================
diff --git a/core/java/android/app/UidObserver.java b/core/java/android/app/UidObserver.java
index 9e92807..5196624 100644
--- a/core/java/android/app/UidObserver.java
+++ b/core/java/android/app/UidObserver.java
@@ -41,7 +41,7 @@
}
@Override
- public void onUidProcAdjChanged(int uid) {
+ public void onUidProcAdjChanged(int uid, int adj) {
}
@Override
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 6592019..f673304 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -822,6 +822,10 @@
*/
@TestApi
public boolean isLockscreenLiveWallpaperEnabled() {
+ return isLockscreenLiveWallpaperEnabledHelper();
+ }
+
+ private static boolean isLockscreenLiveWallpaperEnabledHelper() {
if (sGlobals == null) {
sIsLockscreenLiveWallpaperEnabled = SystemProperties.getBoolean(
"persist.wm.debug.lockscreen_live_wallpaper", false);
@@ -2757,7 +2761,7 @@
public static InputStream openDefaultWallpaper(Context context, @SetWallpaperFlags int which) {
final String whichProp;
final int defaultResId;
- if (which == FLAG_LOCK && !sIsLockscreenLiveWallpaperEnabled) {
+ if (which == FLAG_LOCK && !isLockscreenLiveWallpaperEnabledHelper()) {
/* Factory-default lock wallpapers are not yet supported
whichProp = PROP_LOCK_WALLPAPER;
defaultResId = com.android.internal.R.drawable.default_lock_wallpaper;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 1ba84c5..d802b46 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -502,6 +502,8 @@
boolean hasSystemFeature(String name, int version);
+ List<String> getInitialNonStoppedSystemPackages();
+
void enterSafeMode();
@UnsupportedAppUsage
boolean isSafeMode();
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 295df5c..be40143 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -50,7 +50,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
-import java.lang.IllegalArgumentException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -285,6 +284,12 @@
*/
public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103;
+ /**
+ * The maximum length of Shortcut ID. IDs will be truncated at this limit.
+ * @hide
+ */
+ public static final int MAX_ID_LENGTH = 1000;
+
/** @hide */
@IntDef(prefix = { "DISABLED_REASON_" }, value = {
DISABLED_REASON_NOT_DISABLED,
@@ -477,8 +482,7 @@
private ShortcutInfo(Builder b) {
mUserId = b.mContext.getUserId();
-
- mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided");
+ mId = getSafeId(Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided"));
// Note we can't do other null checks here because SM.updateShortcuts() takes partial
// information.
@@ -584,6 +588,14 @@
return ret;
}
+ @NonNull
+ private static String getSafeId(@NonNull String id) {
+ if (id.length() > MAX_ID_LENGTH) {
+ return id.substring(0, MAX_ID_LENGTH);
+ }
+ return id;
+ }
+
/**
* Throws if any of the mandatory fields is not set.
*
@@ -2342,7 +2354,8 @@
final ClassLoader cl = getClass().getClassLoader();
mUserId = source.readInt();
- mId = source.readString8();
+ mId = getSafeId(Preconditions.checkStringNotEmpty(source.readString8(),
+ "Shortcut ID must be provided"));
mPackageName = source.readString8();
mActivity = source.readParcelable(cl, android.content.ComponentName.class);
mFlags = source.readInt();
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index 888047d..21fe686 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -32,10 +32,12 @@
import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionMode;
import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.os.ParcelFileDescriptor;
-import android.system.ErrnoException;
import android.os.SharedMemory;
+import android.system.ErrnoException;
import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -219,36 +221,40 @@
return new SoundTrigger.ConfidenceLevel(apiLevel.userId, apiLevel.levelPercent);
}
- public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent(
- int modelHandle, int captureSession, RecognitionEvent aidlEvent) {
+ public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent(int modelHandle,
+ int captureSession, RecognitionEventSys aidlEvent) {
+ RecognitionEvent recognitionEvent = aidlEvent.recognitionEvent;
// The API recognition event doesn't allow for a null audio format, even though it doesn't
// always make sense. We thus replace it with a default.
- AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.audioConfig,
+ AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(recognitionEvent.audioConfig,
true /*isInput*/);
- // TODO(b/265852186) propagate a timestamp from aidl interfaces
- return new SoundTrigger.GenericRecognitionEvent(aidlEvent.status, modelHandle,
- aidlEvent.captureAvailable, captureSession, aidlEvent.captureDelayMs,
- aidlEvent.capturePreambleMs, aidlEvent.triggerInData, audioFormat, aidlEvent.data,
- aidlEvent.recognitionStillActive, -1 /* halEventReceivedMillis */);
+ return new SoundTrigger.GenericRecognitionEvent(recognitionEvent.status, modelHandle,
+ recognitionEvent.captureAvailable, captureSession, recognitionEvent.captureDelayMs,
+ recognitionEvent.capturePreambleMs, recognitionEvent.triggerInData, audioFormat,
+ recognitionEvent.data,
+ recognitionEvent.recognitionStillActive, aidlEvent.halEventReceivedMillis);
}
public static SoundTrigger.RecognitionEvent aidl2apiPhraseRecognitionEvent(
- int modelHandle, int captureSession,
- PhraseRecognitionEvent aidlEvent) {
+ int modelHandle, int captureSession, PhraseRecognitionEventSys aidlEvent) {
+ PhraseRecognitionEvent recognitionEvent = aidlEvent.phraseRecognitionEvent;
SoundTrigger.KeyphraseRecognitionExtra[] apiExtras =
- new SoundTrigger.KeyphraseRecognitionExtra[aidlEvent.phraseExtras.length];
- for (int i = 0; i < aidlEvent.phraseExtras.length; ++i) {
- apiExtras[i] = aidl2apiPhraseRecognitionExtra(aidlEvent.phraseExtras[i]);
+ new SoundTrigger.KeyphraseRecognitionExtra[recognitionEvent.phraseExtras.length];
+ for (int i = 0; i < recognitionEvent.phraseExtras.length; ++i) {
+ apiExtras[i] = aidl2apiPhraseRecognitionExtra(recognitionEvent.phraseExtras[i]);
}
// The API recognition event doesn't allow for a null audio format, even though it doesn't
// always make sense. We thus replace it with a default.
- AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.common.audioConfig,
+ AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(
+ recognitionEvent.common.audioConfig,
true /*isInput*/);
- // TODO(b/265852186) propagate a timestamp from aidl interfaces
- return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle,
- aidlEvent.common.captureAvailable, captureSession, aidlEvent.common.captureDelayMs,
- aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData, audioFormat,
- aidlEvent.common.data, apiExtras, -1 /* halEventReceivedMillis */);
+ return new SoundTrigger.KeyphraseRecognitionEvent(recognitionEvent.common.status,
+ modelHandle,
+ recognitionEvent.common.captureAvailable, captureSession,
+ recognitionEvent.common.captureDelayMs,
+ recognitionEvent.common.capturePreambleMs, recognitionEvent.common.triggerInData,
+ audioFormat,
+ recognitionEvent.common.data, apiExtras, aidlEvent.halEventReceivedMillis);
}
// In case of a null input returns a non-null valid output.
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index 37c5213..5cdbe23 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -22,13 +22,13 @@
import android.media.permission.ClearCallingIdentityContext;
import android.media.permission.Identity;
import android.media.permission.SafeCloseable;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -398,7 +398,7 @@
}
@Override
- public synchronized void onRecognition(int handle, RecognitionEvent event,
+ public synchronized void onRecognition(int handle, RecognitionEventSys event,
int captureSession)
throws RemoteException {
Message m = mHandler.obtainMessage(EVENT_RECOGNITION,
@@ -407,7 +407,7 @@
}
@Override
- public synchronized void onPhraseRecognition(int handle, PhraseRecognitionEvent event,
+ public synchronized void onPhraseRecognition(int handle, PhraseRecognitionEventSys event,
int captureSession)
throws RemoteException {
Message m = mHandler.obtainMessage(EVENT_RECOGNITION,
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 24e28e9..5bcbaa1 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -65,7 +65,6 @@
import android.view.WindowManager.LayoutParams;
import com.android.internal.R;
-import com.android.internal.util.FrameworkStatsLog;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -2533,38 +2532,6 @@
}
/**
- * Returns the enum defined in the statsd UserLifecycleJourneyReported atom corresponding to the
- * user type.
- * @hide
- */
- public static int getUserTypeForStatsd(@NonNull String userType) {
- switch (userType) {
- case USER_TYPE_FULL_SYSTEM:
- return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SYSTEM;
- case USER_TYPE_FULL_SECONDARY:
- return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY;
- case USER_TYPE_FULL_GUEST:
- return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_GUEST;
- case USER_TYPE_FULL_DEMO:
- return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_DEMO;
- case USER_TYPE_FULL_RESTRICTED:
- return FrameworkStatsLog
- .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_RESTRICTED;
- case USER_TYPE_PROFILE_MANAGED:
- return FrameworkStatsLog
- .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__PROFILE_MANAGED;
- case USER_TYPE_SYSTEM_HEADLESS:
- return FrameworkStatsLog
- .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__SYSTEM_HEADLESS;
- case USER_TYPE_PROFILE_CLONE:
- return FrameworkStatsLog
- .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__PROFILE_CLONE;
- default:
- return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN;
- }
- }
-
- /**
* @hide
* @deprecated Use {@link #isRestrictedProfile()}
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4a46beb..329a2fa5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7175,6 +7175,13 @@
public static final String CREDENTIAL_SERVICE = "credential_service";
/**
+ * The currently selected primary credential service flattened ComponentName.
+ *
+ * @hide
+ */
+ public static final String CREDENTIAL_SERVICE_PRIMARY = "credential_service_primary";
+
+ /**
* The currently selected autofill service flattened ComponentName.
* @hide
*/
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index e39b3a1..6ff4b74 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1477,14 +1477,22 @@
// to PCC classification service.
if (AutofillFeatureFlags.isAutofillPccClassificationEnabled()) {
synchronized (mLock) {
- final boolean clientAdded = tryAddServiceClientIfNeededLocked();
- if (clientAdded){
- startSessionLocked(/* id= */ AutofillId.NO_AUTOFILL_ID,
- /* bounds= */ null, /* value= */ null, /* flags= */ FLAG_PCC_DETECTION);
- } else {
- if (sVerbose) {
- Log.v(TAG, "not starting session: no service client");
+ // If session has already been created, that'd mean we already have issued the
+ // detection request previously. It is possible in cases like autofocus that this
+ // method isn't invoked, so the server should still handle such cases where fill
+ // request comes in but PCC Detection hasn't been triggered. There is no benefit to
+ // trigger PCC Detection separately in those cases.
+ if (!isActiveLocked()) {
+ final boolean clientAdded = tryAddServiceClientIfNeededLocked();
+ if (clientAdded) {
+ startSessionLocked(/* id= */ AutofillId.NO_AUTOFILL_ID, /* bounds= */ null,
+ /* value= */ null, /* flags= */ FLAG_PCC_DETECTION);
+ } else {
+ if (sVerbose) {
+ Log.v(TAG, "not starting session: no service client");
+ }
}
+
}
}
}
diff --git a/core/proto/android/companion/telecom.proto b/core/proto/android/companion/telecom.proto
index 3a9e5ee..02ba7c5 100644
--- a/core/proto/android/companion/telecom.proto
+++ b/core/proto/android/companion/telecom.proto
@@ -25,7 +25,7 @@
// Next index: 6
message Call {
// UUID representing this call
- int64 id = 1;
+ string id = 1;
message Origin {
// Caller's name and/or phone number; what a user would see displayed when receiving an
@@ -48,22 +48,23 @@
}
Status status = 3;
- enum Control {
- UNKNOWN_CONTROL = 0;
- ACCEPT = 1;
- REJECT = 2;
- SILENCE = 3;
- MUTE = 4;
- UNMUTE = 5;
- END = 6;
- PUT_ON_HOLD = 7;
- TAKE_OFF_HOLD = 8;
- REJECT_AND_BLOCK = 9;
- IGNORE = 10;
- }
repeated Control controls = 4;
}
+ enum Control {
+ UNKNOWN_CONTROL = 0;
+ ACCEPT = 1;
+ REJECT = 2;
+ SILENCE = 3;
+ MUTE = 4;
+ UNMUTE = 5;
+ END = 6;
+ PUT_ON_HOLD = 7;
+ TAKE_OFF_HOLD = 8;
+ REJECT_AND_BLOCK = 9;
+ IGNORE = 10;
+ }
+
// The list of active calls.
repeated Call calls = 1;
// The list of requested calls or call changes.
diff --git a/core/res/res/drawable-hdpi/pointer_context_menu.png b/core/res/res/drawable-hdpi/pointer_context_menu.png
index c45d29b..60d37c4 100644
--- a/core/res/res/drawable-hdpi/pointer_context_menu.png
+++ b/core/res/res/drawable-hdpi/pointer_context_menu.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_help.png b/core/res/res/drawable-hdpi/pointer_help.png
index a3afdb6..2d9d20c 100644
--- a/core/res/res/drawable-hdpi/pointer_help.png
+++ b/core/res/res/drawable-hdpi/pointer_help.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_context_menu.png b/core/res/res/drawable-mdpi/pointer_context_menu.png
index e0e849d..d87d040 100644
--- a/core/res/res/drawable-mdpi/pointer_context_menu.png
+++ b/core/res/res/drawable-mdpi/pointer_context_menu.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_context_menu_large.png b/core/res/res/drawable-mdpi/pointer_context_menu_large.png
index e8c9be4..15266a6 100644
--- a/core/res/res/drawable-mdpi/pointer_context_menu_large.png
+++ b/core/res/res/drawable-mdpi/pointer_context_menu_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_help.png b/core/res/res/drawable-mdpi/pointer_help.png
index 286242c..bd04bbd 100644
--- a/core/res/res/drawable-mdpi/pointer_help.png
+++ b/core/res/res/drawable-mdpi/pointer_help.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_help_large.png b/core/res/res/drawable-mdpi/pointer_help_large.png
index 27f4a84..f9bd2b7 100644
--- a/core/res/res/drawable-mdpi/pointer_help_large.png
+++ b/core/res/res/drawable-mdpi/pointer_help_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_context_menu.png b/core/res/res/drawable-xhdpi/pointer_context_menu.png
index d4b2bde..15d1e33 100644
--- a/core/res/res/drawable-xhdpi/pointer_context_menu.png
+++ b/core/res/res/drawable-xhdpi/pointer_context_menu.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_context_menu_large.png b/core/res/res/drawable-xhdpi/pointer_context_menu_large.png
index 977df10..e4ff7a6 100644
--- a/core/res/res/drawable-xhdpi/pointer_context_menu_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_context_menu_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_help.png b/core/res/res/drawable-xhdpi/pointer_help.png
index 5a6805c..952a4ee 100644
--- a/core/res/res/drawable-xhdpi/pointer_help.png
+++ b/core/res/res/drawable-xhdpi/pointer_help.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_help_large.png b/core/res/res/drawable-xhdpi/pointer_help_large.png
index 4bdc3d1..1d68437 100644
--- a/core/res/res/drawable-xhdpi/pointer_help_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_help_large.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_context_menu.png b/core/res/res/drawable-xxhdpi/pointer_context_menu.png
index 6ebfaab..4cd20f5 100644
--- a/core/res/res/drawable-xxhdpi/pointer_context_menu.png
+++ b/core/res/res/drawable-xxhdpi/pointer_context_menu.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_help.png b/core/res/res/drawable-xxhdpi/pointer_help.png
index 96b2a71..0c7a264 100644
--- a/core/res/res/drawable-xxhdpi/pointer_help.png
+++ b/core/res/res/drawable-xxhdpi/pointer_help.png
Binary files differ
diff --git a/core/res/res/drawable/pointer_context_menu_large_icon.xml b/core/res/res/drawable/pointer_context_menu_large_icon.xml
index e07e5b6..325ea669 100644
--- a/core/res/res/drawable/pointer_context_menu_large_icon.xml
+++ b/core/res/res/drawable/pointer_context_menu_large_icon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
android:bitmap="@drawable/pointer_context_menu_large"
- android:hotSpotX="13.5dp"
- android:hotSpotY="10.5dp" />
+ android:hotSpotX="10.5dp"
+ android:hotSpotY="8dp" />
diff --git a/core/res/res/drawable/pointer_help_large_icon.xml b/core/res/res/drawable/pointer_help_large_icon.xml
index 43a1261..20f0c5336 100644
--- a/core/res/res/drawable/pointer_help_large_icon.xml
+++ b/core/res/res/drawable/pointer_help_large_icon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
android:bitmap="@drawable/pointer_help_large"
- android:hotSpotX="13.5dp"
- android:hotSpotY="10.5dp" />
+ android:hotSpotX="10.5dp"
+ android:hotSpotY="8dp" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7bc3ab8..50aec83 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -991,6 +991,25 @@
<!-- Nominal White Z --> <item>1.089058</item>
</string-array>
+ <!-- The CCT closest to the white coordinates (primary) above and in SurfaceControl. -->
+ <integer name="config_displayWhiteBalanceDisplayNominalWhiteCct">6500</integer>
+
+ <!-- Range minimums corresponding to config_displayWhiteBalanceDisplaySteps. For example, if the
+ range minimums are [0, 3000] and the steps are [10, 20] then between 0 and 3000, exclusive,
+ the step between them will be 10 (i.e. 0, 10, 20, etc.) and the step between 3000 and the
+ maximum value is 20 (i.e. 3000, 3020, 3040, etc.). -->
+ <integer-array name="config_displayWhiteBalanceDisplayRangeMinimums">
+ <item>0</item>
+ </integer-array>
+
+ <!-- Steps corresponding to config_displayWhiteBalanceDisplayRangeMinimums. For example, if the
+ range minimums are [0, 3000] and the steps are [10, 20] then between 0 and 3000, exclusive,
+ the step between them will be 10 (i.e. 0, 10, 20, etc.) and the step between 3000 and the
+ maximum value is 20 (i.e. 3000, 3020, 3040, etc.). -->
+ <integer-array name="config_displayWhiteBalanceDisplaySteps">
+ <item>1</item>
+ </integer-array>
+
<!-- Boolean indicating whether light mode is allowed when DWB is turned on. -->
<bool name="config_displayWhiteBalanceLightModeAllowed">true</bool>
@@ -6396,7 +6415,7 @@
Packages can be added by OEMs in an allowlist, to prevent them from being scanned as
"stopped" during initial boot of a device, or after an OTA update. Stopped state of
an app is not changed during subsequent reboots. -->
- <bool name="config_stopSystemPackagesByDefault">false</bool>
+ <bool name="config_stopSystemPackagesByDefault">true</bool>
<!-- Whether to show weather on the lock screen by default. -->
<bool name="config_lockscreenWeatherEnabledByDefault">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e25425d..218bbc2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3423,6 +3423,9 @@
<java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureDefault" />
<java-symbol type="array" name="config_displayWhiteBalanceDisplayPrimaries" />
<java-symbol type="array" name="config_displayWhiteBalanceDisplayNominalWhite" />
+ <java-symbol type="integer" name="config_displayWhiteBalanceDisplayNominalWhiteCct" />
+ <java-symbol type="array" name="config_displayWhiteBalanceDisplayRangeMinimums" />
+ <java-symbol type="array" name="config_displayWhiteBalanceDisplaySteps" />
<java-symbol type="bool" name="config_displayWhiteBalanceLightModeAllowed" />
<java-symbol type="integer" name="config_displayWhiteBalanceTransitionTime" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 40cb7f2..1f1239e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -520,6 +520,10 @@
<permission name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"/>
<!-- Permission required for CTS test - SatelliteManagerTest -->
<permission name="android.permission.SATELLITE_COMMUNICATION"/>
+ <!-- Permission required for GTS test - GtsAttestationVerificationDeviceSideTestCases -->
+ <permission name="android.permission.USE_ATTESTATION_VERIFICATION_SERVICE" />
+ <!-- Permission required for GTS test - GtsCredentialsTestCases -->
+ <permission name="android.permission.LAUNCH_CREDENTIAL_SELECTOR"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 6a79bc1..54978bd 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -125,34 +125,6 @@
// End ProtoLog
-gensrcs {
- name: "wm-shell-protos",
-
- tools: [
- "aprotoc",
- "protoc-gen-javastream",
- "soong_zip",
- ],
-
- tool_files: [
- ":libprotobuf-internal-protos",
- ],
-
- cmd: "mkdir -p $(genDir)/$(in) " +
- "&& $(location aprotoc) " +
- " --plugin=$(location protoc-gen-javastream) " +
- " --javastream_out=$(genDir)/$(in) " +
- " -Iexternal/protobuf/src " +
- " -I . " +
- " $(in) " +
- "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
-
- srcs: [
- "proto/**/*.proto",
- ],
- output_extension: "srcjar",
-}
-
java_library {
name: "WindowManager-Shell-proto",
@@ -170,7 +142,6 @@
// TODO(b/168581922) protologtool do not support kotlin(*.kt)
":wm_shell-sources-kt",
":wm_shell-aidls",
- ":wm-shell-protos",
],
resource_dirs: [
"res",
diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml
deleted file mode 100644
index 876ee02..0000000
--- a/libs/WindowManager/Shell/res/color/taskbar_background.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 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.
- -->
-<!-- Should be the same as in packages/apps/Launcher3/res/color-v31/taskbar_background.xml -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
-</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/color-night/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background_dark.xml
similarity index 100%
rename from libs/WindowManager/Shell/res/color-night/taskbar_background.xml
rename to libs/WindowManager/Shell/res/color/taskbar_background_dark.xml
diff --git a/libs/WindowManager/Shell/res/values-night/colors.xml b/libs/WindowManager/Shell/res/values-night/colors.xml
index 5c6bb57..83c4d93 100644
--- a/libs/WindowManager/Shell/res/values-night/colors.xml
+++ b/libs/WindowManager/Shell/res/values-night/colors.xml
@@ -15,7 +15,6 @@
-->
<resources>
- <color name="docked_divider_handle">#ffffff</color>
<!-- Bubbles -->
<color name="bubbles_icon_tint">@color/GM2_grey_200</color>
<!-- Splash screen-->
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index c487e4a..54a8f33 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -17,8 +17,8 @@
*/
-->
<resources>
- <color name="docked_divider_handle">#000000</color>
- <color name="split_divider_background">@color/taskbar_background</color>
+ <color name="docked_divider_handle">#ffffff</color>
+ <color name="split_divider_background">@color/taskbar_background_dark</color>
<drawable name="forced_resizable_background">#59000000</drawable>
<color name="minimize_dock_shadow_start">#60000000</color>
<color name="minimize_dock_shadow_end">#00000000</color>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index f3efaad..e7ec7aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -3320,7 +3320,9 @@
* @return the normalized x-axis position of the bubble stack rounded to 4 decimal places.
*/
public float getNormalizedXPosition() {
- return new BigDecimal(getStackPosition().x / mPositioner.getAvailableRect().width())
+ int width = mPositioner.getAvailableRect().width();
+ float stackPosition = width > 0 ? getStackPosition().x / width : 0;
+ return new BigDecimal(stackPosition)
.setScale(4, RoundingMode.CEILING.HALF_UP)
.floatValue();
}
@@ -3329,7 +3331,9 @@
* @return the normalized y-axis position of the bubble stack rounded to 4 decimal places.
*/
public float getNormalizedYPosition() {
- return new BigDecimal(getStackPosition().y / mPositioner.getAvailableRect().height())
+ int height = mPositioner.getAvailableRect().height();
+ float stackPosition = height > 0 ? getStackPosition().y / height : 0;
+ return new BigDecimal(stackPosition)
.setScale(4, RoundingMode.CEILING.HALF_UP)
.floatValue();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 80e920f..28368ef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -189,12 +189,13 @@
static Optional<DragAndDropController> provideDragAndDropController(Context context,
ShellInit shellInit,
ShellController shellController,
+ ShellCommandHandler shellCommandHandler,
DisplayController displayController,
UiEventLogger uiEventLogger,
IconProvider iconProvider,
@ShellMainThread ShellExecutor mainExecutor) {
return Optional.ofNullable(DragAndDropController.create(context, shellInit, shellController,
- displayController, uiEventLogger, iconProvider, mainExecutor));
+ shellCommandHandler, displayController, uiEventLogger, iconProvider, mainExecutor));
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index fb0a91f..0f0d572 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -162,7 +162,7 @@
/**
* Release the indicator and its components when it is no longer needed.
*/
- public void releaseVisualIndicator() {
+ public void releaseVisualIndicator(SurfaceControl.Transaction t) {
if (mViewHost == null) return;
if (mViewHost != null) {
mViewHost.release();
@@ -170,13 +170,8 @@
}
if (mLeash != null) {
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.remove(mLeash);
mLeash = null;
- mSyncQueue.runInSync(transaction -> {
- transaction.merge(t);
- t.close();
- });
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 73a0e36..ee94f30 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -78,6 +78,11 @@
private val desktopMode: DesktopModeImpl
private var visualIndicator: DesktopModeVisualIndicator? = null
+ private val mOnAnimationFinishedCallback = Consumer<SurfaceControl.Transaction> {
+ t: SurfaceControl.Transaction ->
+ visualIndicator?.releaseVisualIndicator(t)
+ visualIndicator = null
+ }
init {
desktopMode = DesktopModeImpl()
@@ -154,14 +159,14 @@
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
enterDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_ENTER_FREEFORM, wct)
+ Transitions.TRANSIT_ENTER_FREEFORM, wct, mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
}
}
/** Brings apps to front and sets freeform task bounds */
- fun moveToDesktopWithAnimation(
+ private fun moveToDesktopWithAnimation(
taskInfo: RunningTaskInfo,
freeformBounds: Rect
) {
@@ -172,9 +177,10 @@
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
enterDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_ENTER_DESKTOP_MODE, wct)
+ Transitions.TRANSIT_ENTER_DESKTOP_MODE, wct, mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
+ releaseVisualIndicator()
}
}
@@ -205,21 +211,24 @@
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task.token)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, startPosition)
+ enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, startPosition,
+ mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
+ releaseVisualIndicator()
}
}
- fun moveToFullscreenWithAnimation(task: ActivityManager.RunningTaskInfo) {
+ private fun moveToFullscreenWithAnimation(task: ActivityManager.RunningTaskInfo) {
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task.token)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
exitDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_EXIT_DESKTOP_MODE, wct)
+ Transitions.TRANSIT_EXIT_DESKTOP_MODE, wct, mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
+ releaseVisualIndicator()
}
}
@@ -330,6 +339,16 @@
?.let { homeTask -> wct.reorder(homeTask.getToken(), true /* onTop */) }
}
+ private fun releaseVisualIndicator() {
+ val t = SurfaceControl.Transaction()
+ visualIndicator?.releaseVisualIndicator(t)
+ visualIndicator = null
+ syncQueue.runInSync { transaction ->
+ transaction.merge(t)
+ t.close()
+ }
+ }
+
override fun getContext(): Context {
return context
}
@@ -471,8 +490,7 @@
rootTaskDisplayAreaOrganizer)
visualIndicator?.createFullscreenIndicatorWithAnimatedBounds()
} else if (y > statusBarHeight && visualIndicator != null) {
- visualIndicator?.releaseVisualIndicator()
- visualIndicator = null
+ releaseVisualIndicator()
}
}
}
@@ -489,8 +507,6 @@
) {
val statusBarHeight = getStatusBarHeight(taskInfo)
if (y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
- visualIndicator?.releaseVisualIndicator()
- visualIndicator = null
moveToFullscreenWithAnimation(taskInfo)
}
}
@@ -508,6 +524,11 @@
taskSurface: SurfaceControl,
y: Float
) {
+ // If the motion event is above the status bar, return since we do not need to show the
+ // visual indicator at this point.
+ if (y < getStatusBarHeight(taskInfo)) {
+ return
+ }
if (visualIndicator == null) {
visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo,
displayController, context, taskSurface, shellTaskOrganizer,
@@ -535,11 +556,8 @@
freeformBounds: Rect
) {
moveToDesktopWithAnimation(taskInfo, freeformBounds)
- visualIndicator?.releaseVisualIndicator()
- visualIndicator = null
}
-
private fun getStatusBarHeight(taskInfo: RunningTaskInfo): Int {
return displayController.getDisplayLayout(taskInfo.displayId)?.stableInsets()?.top ?: 0
}
@@ -566,7 +584,6 @@
desktopModeTaskRepository.removeTaskCorners(taskId)
}
-
/**
* Adds a listener to find out about changes in the visibility of freeform tasks.
*
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 9467578..d55fddd 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
@@ -39,6 +39,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Supplier;
/**
@@ -58,6 +59,7 @@
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
private Point mStartPosition;
+ private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
public EnterDesktopTaskTransitionHandler(
Transitions transitions) {
@@ -75,9 +77,12 @@
* Starts Transition of a given type
* @param type Transition type
* @param wct WindowContainerTransaction for transition
+ * @param onAnimationEndCallback to be called after animation
*/
public void startTransition(@WindowManager.TransitionType int type,
- @NonNull WindowContainerTransaction wct) {
+ @NonNull WindowContainerTransaction wct,
+ Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+ mOnAnimationFinishedCallback = onAnimationEndCallback;
final IBinder token = mTransitions.startTransition(type, wct, this);
mPendingTransitionTokens.add(token);
}
@@ -86,11 +91,14 @@
* Starts Transition of type TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
* @param wct WindowContainerTransaction for transition
* @param startPosition Position of task when transition is triggered
+ * @param onAnimationEndCallback to be called after animation
*/
public void startCancelMoveToDesktopMode(@NonNull WindowContainerTransaction wct,
- Point startPosition) {
+ Point startPosition,
+ Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
mStartPosition = startPosition;
- startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct);
+ startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct,
+ mOnAnimationFinishedCallback);
}
@Override
@@ -111,7 +119,7 @@
if (change.getMode() == WindowManager.TRANSIT_CHANGE) {
transitionHandled |= startChangeTransition(
- transition, info.getType(), change, startT, finishCallback);
+ transition, info.getType(), change, startT, finishT, finishCallback);
}
}
@@ -125,6 +133,7 @@
@WindowManager.TransitionType int type,
@NonNull TransitionInfo.Change change,
@NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
if (!mPendingTransitionTokens.contains(transition)) {
return false;
@@ -178,6 +187,9 @@
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
+ }
mTransitions.getMainExecutor().execute(
() -> finishCallback.onTransitionFinished(null, null));
}
@@ -204,7 +216,7 @@
animator.setDuration(FREEFORM_ANIMATION_DURATION);
final SurfaceControl.Transaction t = mTransactionSupplier.get();
animator.addUpdateListener(animation -> {
- final float scale = animation.getAnimatedFraction();
+ final float scale = (float) animation.getAnimatedValue();
t.setPosition(sc, mStartPosition.x * (1 - scale), mStartPosition.y * (1 - scale))
.setScale(sc, scale, scale)
.show(sc)
@@ -213,6 +225,9 @@
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
+ }
mTransitions.getMainExecutor().execute(
() -> finishCallback.onTransitionFinished(null, null));
}
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 fa3eee2..160a83d 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
@@ -42,6 +42,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -54,7 +55,7 @@
private final Context mContext;
private final Transitions mTransitions;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
-
+ private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
private Supplier<SurfaceControl.Transaction> mTransactionSupplier;
public ExitDesktopTaskTransitionHandler(
@@ -76,9 +77,12 @@
* Starts Transition of a given type
* @param type Transition type
* @param wct WindowContainerTransaction for transition
+ * @param onAnimationEndCallback to be called after animation
*/
public void startTransition(@WindowManager.TransitionType int type,
- @NonNull WindowContainerTransaction wct) {
+ @NonNull WindowContainerTransaction wct,
+ Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+ mOnAnimationFinishedCallback = onAnimationEndCallback;
final IBinder token = mTransitions.startTransition(type, wct, this);
mPendingTransitionTokens.add(token);
}
@@ -101,7 +105,7 @@
if (change.getMode() == WindowManager.TRANSIT_CHANGE) {
transitionHandled |= startChangeTransition(
- transition, info.getType(), change, startT, finishCallback);
+ transition, info.getType(), change, startT, finishT, finishCallback);
}
}
@@ -116,6 +120,7 @@
@WindowManager.TransitionType int type,
@NonNull TransitionInfo.Change change,
@NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
if (!mPendingTransitionTokens.contains(transition)) {
return false;
@@ -156,6 +161,9 @@
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
+ }
mTransitions.getMainExecutor().execute(
() -> finishCallback.onTransitionFinished(null, null));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 091de3a..be2489d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -35,10 +35,14 @@
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;
+
import android.content.ClipDescription;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.HardwareRenderer;
import android.graphics.PixelFormat;
import android.util.Slog;
import android.util.SparseArray;
@@ -50,6 +54,8 @@
import android.view.WindowManager;
import android.widget.FrameLayout;
+import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.InstanceId;
@@ -58,25 +64,31 @@
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.ExternalInterfaceBinder;
+import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ExternalMainThread;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
+import java.io.PrintWriter;
import java.util.ArrayList;
/**
* Handles the global drag and drop handling for the Shell.
*/
-public class DragAndDropController implements DisplayController.OnDisplaysChangedListener,
+public class DragAndDropController implements RemoteCallable<DragAndDropController>,
+ DisplayController.OnDisplaysChangedListener,
View.OnDragListener, ComponentCallbacks2 {
private static final String TAG = DragAndDropController.class.getSimpleName();
private final Context mContext;
private final ShellController mShellController;
+ private final ShellCommandHandler mShellCommandHandler;
private final DisplayController mDisplayController;
private final DragAndDropEventLogger mLogger;
private final IconProvider mIconProvider;
@@ -100,6 +112,7 @@
public static DragAndDropController create(Context context,
ShellInit shellInit,
ShellController shellController,
+ ShellCommandHandler shellCommandHandler,
DisplayController displayController,
UiEventLogger uiEventLogger,
IconProvider iconProvider,
@@ -107,19 +120,21 @@
if (!context.getResources().getBoolean(R.bool.config_enableShellDragDrop)) {
return null;
}
- return new DragAndDropController(context, shellInit, shellController, displayController,
- uiEventLogger, iconProvider, mainExecutor);
+ return new DragAndDropController(context, shellInit, shellController, shellCommandHandler,
+ displayController, uiEventLogger, iconProvider, mainExecutor);
}
DragAndDropController(Context context,
ShellInit shellInit,
ShellController shellController,
+ ShellCommandHandler shellCommandHandler,
DisplayController displayController,
UiEventLogger uiEventLogger,
IconProvider iconProvider,
ShellExecutor mainExecutor) {
mContext = context;
mShellController = shellController;
+ mShellCommandHandler = shellCommandHandler;
mDisplayController = displayController;
mLogger = new DragAndDropEventLogger(uiEventLogger);
mIconProvider = iconProvider;
@@ -137,6 +152,23 @@
mMainExecutor.executeDelayed(() -> {
mDisplayController.addDisplayWindowListener(this);
}, 0);
+ mShellController.addExternalInterface(KEY_EXTRA_SHELL_DRAG_AND_DROP,
+ this::createExternalInterface, this);
+ mShellCommandHandler.addDumpCallback(this::dump, this);
+ }
+
+ private ExternalInterfaceBinder createExternalInterface() {
+ return new IDragAndDropImpl(this);
+ }
+
+ @Override
+ public Context getContext() {
+ return mContext;
+ }
+
+ @Override
+ public ShellExecutor getRemoteCallExecutor() {
+ return mMainExecutor;
}
/**
@@ -156,7 +188,7 @@
mListeners.remove(listener);
}
- private void notifyListeners() {
+ private void notifyDragStarted() {
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onDragStarted();
}
@@ -273,7 +305,7 @@
pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId),
event.getClipData(), loggerSessionId);
setDropTargetWindowVisibility(pd, View.VISIBLE);
- notifyListeners();
+ notifyDragStarted();
break;
case ACTION_DRAG_ENTERED:
pd.dragLayout.show();
@@ -327,13 +359,7 @@
}
private void setDropTargetWindowVisibility(PerDisplay pd, int visibility) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
- "Set drop target window visibility: displayId=%d visibility=%d",
- pd.displayId, visibility);
- pd.rootView.setVisibility(visibility);
- if (visibility == View.VISIBLE) {
- pd.rootView.requestApplyInsets();
- }
+ pd.setWindowVisibility(visibility);
}
private String getMimeTypes(ClipDescription description) {
@@ -347,6 +373,18 @@
return mimeTypes;
}
+ /**
+ * Returns if any displays are currently ready to handle a drag/drop.
+ */
+ private boolean isReadyToHandleDrag() {
+ for (int i = 0; i < mDisplayDropTargets.size(); i++) {
+ if (mDisplayDropTargets.valueAt(i).mHasDrawn) {
+ return true;
+ }
+ }
+ return false;
+ }
+
// Note: Component callbacks are always called on the main thread of the process
@ExternalMainThread
@Override
@@ -372,12 +410,53 @@
// Do nothing
}
- private static class PerDisplay {
+ /**
+ * Dumps information about this controller.
+ */
+ public void dump(@NonNull PrintWriter pw, String prefix) {
+ pw.println(prefix + TAG);
+ pw.println(prefix + " listeners=" + mListeners.size());
+ }
+
+ /**
+ * The interface for calls from outside the host process.
+ */
+ @BinderThread
+ private static class IDragAndDropImpl extends IDragAndDrop.Stub
+ implements ExternalInterfaceBinder {
+ private DragAndDropController mController;
+
+ public IDragAndDropImpl(DragAndDropController controller) {
+ mController = controller;
+ }
+
+ /**
+ * Invalidates this instance, preventing future calls from updating the controller.
+ */
+ @Override
+ public void invalidate() {
+ mController = null;
+ }
+
+ @Override
+ public boolean isReadyToHandleDrag() {
+ boolean[] result = new boolean[1];
+ executeRemoteCallWithTaskPermission(mController, "isReadyToHandleDrag",
+ controller -> result[0] = controller.isReadyToHandleDrag(),
+ true /* blocking */
+ );
+ return result[0];
+ }
+ }
+
+ private static class PerDisplay implements HardwareRenderer.FrameDrawingCallback {
final int displayId;
final Context context;
final WindowManager wm;
final FrameLayout rootView;
final DragLayout dragLayout;
+ // Tracks whether the window has fully drawn since it was last made visible
+ boolean mHasDrawn;
boolean isHandlingDrag;
// A count of the number of active drags in progress to ensure that we only hide the window
@@ -391,5 +470,25 @@
rootView = rv;
dragLayout = dl;
}
+
+ private void setWindowVisibility(int visibility) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
+ "Set drop target window visibility: displayId=%d visibility=%d",
+ displayId, visibility);
+ rootView.setVisibility(visibility);
+ if (visibility == View.VISIBLE) {
+ rootView.requestApplyInsets();
+ if (!mHasDrawn && rootView.getViewRootImpl() != null) {
+ rootView.getViewRootImpl().registerRtFrameCallback(this);
+ }
+ } else {
+ mHasDrawn = false;
+ }
+ }
+
+ @Override
+ public void onFrameDraw(long frame) {
+ mHasDrawn = true;
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index 28f59b5..724a130 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -104,7 +104,7 @@
setContainerMargin(0, 0, 0, 0); // make sure it's populated
mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
- mMarginColor = getResources().getColor(R.color.taskbar_background);
+ mMarginColor = getResources().getColor(R.color.taskbar_background_dark);
int c = getResources().getColor(android.R.color.system_accent1_500);
mHighlightColor = Color.argb(HIGHLIGHT_ALPHA, Color.red(c), Color.green(c), Color.blue(c));
mSplashScreenColor = Color.argb(SPLASHSCREEN_ALPHA, 0, 0, 0);
@@ -125,7 +125,7 @@
public void onThemeChange() {
mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(getContext());
- mMarginColor = getResources().getColor(R.color.taskbar_background);
+ mMarginColor = getResources().getColor(R.color.taskbar_background_dark);
mHighlightColor = getResources().getColor(android.R.color.system_accent1_500);
if (mMarginPercent > 0) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/IDragAndDrop.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/IDragAndDrop.aidl
new file mode 100644
index 0000000..aeb0c63
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/IDragAndDrop.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.draganddrop;
+
+/**
+ * Interface that is exposed to remote callers to manipulate drag and drop.
+ */
+interface IDragAndDrop {
+ /**
+ * Returns whether the shell drop target is showing and will handle a drag/drop.
+ */
+ boolean isReadyToHandleDrag() = 1;
+}
+// Last id = 1
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index d3e7f9ca..6cedcf5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -27,6 +27,7 @@
import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.wm.shell.pip.PipAnimationController.FRACTION_START;
@@ -524,12 +525,18 @@
}
}
- final Rect destinationBounds = getExitDestinationBounds();
+ final Rect displayBounds = mPipBoundsState.getDisplayBounds();
+ final Rect destinationBounds = new Rect(displayBounds);
final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
: TRANSITION_DIRECTION_LEAVE_PIP;
+ // For exiting to fullscreen, the windowing mode of task will be changed to fullscreen
+ // until the animation is finished. Otherwise if the activity is resumed and focused at the
+ // begin of aniamtion, the app may do something too early to distub the animation.
+ final boolean toFullscreen = destinationBounds.equals(displayBounds);
- if (Transitions.ENABLE_SHELL_TRANSITIONS && direction == TRANSITION_DIRECTION_LEAVE_PIP) {
+ if (Transitions.SHELL_TRANSITIONS_ROTATION || (Transitions.ENABLE_SHELL_TRANSITIONS
+ && !toFullscreen)) {
// When exit to fullscreen with Shell transition enabled, we update the Task windowing
// mode directly so that it can also trigger display rotation and visibility update in
// the same transition if there will be any.
@@ -605,7 +612,7 @@
removePip();
}
- private void applyWindowingModeChangeOnExit(WindowContainerTransaction wct, int direction) {
+ void applyWindowingModeChangeOnExit(WindowContainerTransaction wct, int direction) {
// Reset the final windowing mode.
wct.setWindowingMode(mToken, getOutPipWindowingMode());
// Simply reset the activity mode set prior to the animation running.
@@ -1771,14 +1778,26 @@
* @return {@code true} if destinationBounds is altered for split screen
*/
private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut, boolean enterSplit) {
- if (!enterSplit || !mSplitScreenOptional.isPresent()) {
+ if (mSplitScreenOptional.isEmpty()) {
+ return false;
+ }
+ final SplitScreenController split = mSplitScreenOptional.get();
+ final int position = mTaskInfo.lastParentTaskIdBeforePip > 0
+ ? split.getSplitPosition(mTaskInfo.lastParentTaskIdBeforePip)
+ : SPLIT_POSITION_UNDEFINED;
+ if (position == SPLIT_POSITION_UNDEFINED && !enterSplit) {
return false;
}
final Rect topLeft = new Rect();
final Rect bottomRight = new Rect();
- mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
- destinationBoundsOut.set(isPipToTopLeft() ? topLeft : bottomRight);
- return true;
+ split.getStageBounds(topLeft, bottomRight);
+ if (enterSplit) {
+ destinationBoundsOut.set(isPipToTopLeft() ? topLeft : bottomRight);
+ return true;
+ }
+ // Moving to an existing split task.
+ destinationBoundsOut.set(position == SPLIT_POSITION_TOP_OR_LEFT ? topLeft : bottomRight);
+ return false;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 99cb6f78..98db707 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -508,8 +508,16 @@
currentBounds.offset(-offset.x, -offset.y);
startTransaction.setPosition(pipLeash, currentBounds.left, currentBounds.top);
+ final WindowContainerToken pipTaskToken = pipChange.getContainer();
+ final boolean toFullscreen = pipChange.getEndAbsBounds().equals(
+ mPipBoundsState.getDisplayBounds());
mFinishCallback = (wct, wctCB) -> {
mPipOrganizer.onExitPipFinished(taskInfo);
+ if (!Transitions.SHELL_TRANSITIONS_ROTATION && toFullscreen) {
+ wct = wct != null ? wct : new WindowContainerTransaction();
+ wct.setBounds(pipTaskToken, null);
+ mPipOrganizer.applyWindowingModeChangeOnExit(wct, TRANSITION_DIRECTION_LEAVE_PIP);
+ }
finishCallback.onTransitionFinished(wct, wctCB);
};
mFinishTransaction = finishTransaction;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
index bfa6390..5f54f58 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
@@ -42,4 +42,6 @@
public static final String KEY_EXTRA_SHELL_FLOATING_TASKS = "extra_shell_floating_tasks";
// See IDesktopMode.aidl
public static final String KEY_EXTRA_SHELL_DESKTOP_MODE = "extra_shell_desktop_mode";
+ // See IDragAndDrop.aidl
+ public static final String KEY_EXTRA_SHELL_DRAG_AND_DROP = "extra_shell_drag_and_drop";
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
index c7e534a..2faed3a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
@@ -202,6 +202,7 @@
}
void setTaskViewVisible(TaskViewTaskController taskView, boolean visible) {
+ if (mTaskViews.get(taskView) == null) return;
if (mTaskViews.get(taskView).mVisible == visible) return;
if (taskView.getTaskInfo() == null) {
// Nothing to update, task is not yet available
@@ -220,17 +221,19 @@
void updateBoundsState(TaskViewTaskController taskView, Rect boundsOnScreen) {
TaskViewRequestedState state = mTaskViews.get(taskView);
+ if (state == null) return;
state.mBounds.set(boundsOnScreen);
}
void updateVisibilityState(TaskViewTaskController taskView, boolean visible) {
TaskViewRequestedState state = mTaskViews.get(taskView);
+ if (state == null) return;
state.mVisible = visible;
}
void setTaskBounds(TaskViewTaskController taskView, Rect boundsOnScreen) {
TaskViewRequestedState state = mTaskViews.get(taskView);
- if (Objects.equals(boundsOnScreen, state.mBounds)) {
+ if (state == null || Objects.equals(boundsOnScreen, state.mBounds)) {
return;
}
state.mBounds.set(boundsOnScreen);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
index ba364f8..0cede90 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
@@ -18,25 +18,29 @@
import static android.os.Build.IS_USER;
-import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER;
-import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER_H;
-import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER_L;
+import static com.android.wm.shell.nano.WmShellTransitionTraceProto.MAGIC_NUMBER_H;
+import static com.android.wm.shell.nano.WmShellTransitionTraceProto.MAGIC_NUMBER_L;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.SystemClock;
import android.os.Trace;
import android.util.Log;
-import android.util.proto.ProtoOutputStream;
import com.android.internal.util.TraceBuffer;
+import com.android.wm.shell.nano.HandlerMapping;
import com.android.wm.shell.sysui.ShellCommandHandler;
+import com.google.protobuf.nano.MessageNano;
+
import java.io.File;
import java.io.IOException;
+import java.io.OutputStream;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
+import java.util.Queue;
/**
* Helper class to collect and dump transition traces.
@@ -54,8 +58,35 @@
private final Object mEnabledLock = new Object();
private boolean mActiveTracingEnabled = false;
- private final TraceBuffer mTraceBuffer = new TraceBuffer(ALWAYS_ON_TRACING_CAPACITY,
- (proto) -> handleOnEntryRemovedFromTrace(proto));
+ private final TraceBuffer.ProtoProvider mProtoProvider =
+ new TraceBuffer.ProtoProvider<MessageNano,
+ com.android.wm.shell.nano.WmShellTransitionTraceProto,
+ com.android.wm.shell.nano.Transition>() {
+ @Override
+ public int getItemSize(MessageNano proto) {
+ return proto.getCachedSize();
+ }
+
+ @Override
+ public byte[] getBytes(MessageNano proto) {
+ return MessageNano.toByteArray(proto);
+ }
+
+ @Override
+ public void write(
+ com.android.wm.shell.nano.WmShellTransitionTraceProto encapsulatingProto,
+ Queue<com.android.wm.shell.nano.Transition> buffer, OutputStream os)
+ throws IOException {
+ encapsulatingProto.transitions = buffer.toArray(
+ new com.android.wm.shell.nano.Transition[0]);
+ os.write(getBytes(encapsulatingProto));
+ }
+ };
+ private final TraceBuffer<MessageNano,
+ com.android.wm.shell.nano.WmShellTransitionTraceProto,
+ com.android.wm.shell.nano.Transition> mTraceBuffer
+ = new TraceBuffer(ALWAYS_ON_TRACING_CAPACITY, mProtoProvider,
+ (proto) -> handleOnEntryRemovedFromTrace(proto));
private final Map<Object, Runnable> mRemovedFromTraceCallbacks = new HashMap<>();
private final Map<Transitions.TransitionHandler, Integer> mHandlerIds = new HashMap<>();
@@ -78,26 +109,20 @@
mHandlerIds.put(handler, handlerId);
}
- ProtoOutputStream outputStream = new ProtoOutputStream();
- final long protoToken =
- outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
-
- outputStream.write(com.android.wm.shell.Transition.ID, transitionId);
- outputStream.write(com.android.wm.shell.Transition.DISPATCH_TIME_NS,
- SystemClock.elapsedRealtimeNanos());
- outputStream.write(com.android.wm.shell.Transition.HANDLER, handlerId);
-
- outputStream.end(protoToken);
+ com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+ proto.id = transitionId;
+ proto.dispatchTimeNs = SystemClock.elapsedRealtimeNanos();
+ proto.handler = handlerId;
final int useCountAfterAdd = mHandlerUseCountInTrace.getOrDefault(handler, 0) + 1;
mHandlerUseCountInTrace.put(handler, useCountAfterAdd);
- mRemovedFromTraceCallbacks.put(outputStream, () -> {
+ mRemovedFromTraceCallbacks.put(proto, () -> {
final int useCountAfterRemove = mHandlerUseCountInTrace.get(handler) - 1;
mHandlerUseCountInTrace.put(handler, useCountAfterRemove);
});
- mTraceBuffer.add(outputStream);
+ mTraceBuffer.add(proto);
}
/**
@@ -107,18 +132,12 @@
* @param playingTransitionId The id of the transition we was to merge the transition into.
*/
public void logMergeRequested(int mergeRequestedTransitionId, int playingTransitionId) {
- ProtoOutputStream outputStream = new ProtoOutputStream();
- final long protoToken =
- outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
+ com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+ proto.id = mergeRequestedTransitionId;
+ proto.mergeRequestTimeNs = SystemClock.elapsedRealtimeNanos();
+ proto.mergedInto = playingTransitionId;
- outputStream.write(com.android.wm.shell.Transition.ID, mergeRequestedTransitionId);
- outputStream.write(com.android.wm.shell.Transition.MERGE_REQUEST_TIME_NS,
- SystemClock.elapsedRealtimeNanos());
- outputStream.write(com.android.wm.shell.Transition.MERGED_INTO, playingTransitionId);
-
- outputStream.end(protoToken);
-
- mTraceBuffer.add(outputStream);
+ mTraceBuffer.add(proto);
}
/**
@@ -128,18 +147,12 @@
* @param playingTransitionId The id of the transition the transition was merged into.
*/
public void logMerged(int mergedTransitionId, int playingTransitionId) {
- ProtoOutputStream outputStream = new ProtoOutputStream();
- final long protoToken =
- outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
+ com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+ proto.id = mergedTransitionId;
+ proto.mergeTimeNs = SystemClock.elapsedRealtimeNanos();
+ proto.mergedInto = playingTransitionId;
- outputStream.write(com.android.wm.shell.Transition.ID, mergedTransitionId);
- outputStream.write(
- com.android.wm.shell.Transition.MERGE_TIME_NS, SystemClock.elapsedRealtimeNanos());
- outputStream.write(com.android.wm.shell.Transition.MERGED_INTO, playingTransitionId);
-
- outputStream.end(protoToken);
-
- mTraceBuffer.add(outputStream);
+ mTraceBuffer.add(proto);
}
/**
@@ -148,17 +161,11 @@
* @param transitionId The id of the transition that was aborted.
*/
public void logAborted(int transitionId) {
- ProtoOutputStream outputStream = new ProtoOutputStream();
- final long protoToken =
- outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
+ com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+ proto.id = transitionId;
+ proto.abortTimeNs = SystemClock.elapsedRealtimeNanos();
- outputStream.write(com.android.wm.shell.Transition.ID, transitionId);
- outputStream.write(
- com.android.wm.shell.Transition.ABORT_TIME_NS, SystemClock.elapsedRealtimeNanos());
-
- outputStream.end(protoToken);
-
- mTraceBuffer.add(outputStream);
+ mTraceBuffer.add(proto);
}
/**
@@ -230,8 +237,9 @@
private void writeTraceToFileLocked(@Nullable PrintWriter pw, File file) {
Trace.beginSection("TransitionTracer#writeTraceToFileLocked");
try {
- ProtoOutputStream proto = new ProtoOutputStream();
- proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ com.android.wm.shell.nano.WmShellTransitionTraceProto proto =
+ new com.android.wm.shell.nano.WmShellTransitionTraceProto();
+ proto.magicNumber = MAGIC_NUMBER_VALUE;
writeHandlerMappingToProto(proto);
int pid = android.os.Process.myPid();
LogAndPrintln.i(pw, "Writing file to " + file.getAbsolutePath()
@@ -243,19 +251,21 @@
Trace.endSection();
}
- private void writeHandlerMappingToProto(ProtoOutputStream outputStream) {
+ private void writeHandlerMappingToProto(
+ com.android.wm.shell.nano.WmShellTransitionTraceProto proto) {
+ ArrayList<com.android.wm.shell.nano.HandlerMapping> handlerMappings = new ArrayList<>();
for (Transitions.TransitionHandler handler : mHandlerUseCountInTrace.keySet()) {
final int count = mHandlerUseCountInTrace.get(handler);
if (count > 0) {
- final long protoToken = outputStream.start(
- com.android.wm.shell.WmShellTransitionTraceProto.HANDLER_MAPPINGS);
- outputStream.write(com.android.wm.shell.HandlerMapping.ID,
- mHandlerIds.get(handler));
- outputStream.write(com.android.wm.shell.HandlerMapping.NAME,
- handler.getClass().getName());
- outputStream.end(protoToken);
+ com.android.wm.shell.nano.HandlerMapping mapping =
+ new com.android.wm.shell.nano.HandlerMapping();
+ mapping.id = mHandlerIds.get(handler);
+ mapping.name = handler.getClass().getName();
+ handlerMappings.add(mapping);
}
}
+ proto.handlerMappings = handlerMappings.toArray(
+ new com.android.wm.shell.nano.HandlerMapping[0]);
}
private void handleOnEntryRemovedFromTrace(Object proto) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 12edc35..dffbedd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -111,7 +111,6 @@
private ValueAnimator mDragToDesktopValueAnimator;
private final Rect mDragToDesktopAnimationStartBounds = new Rect();
private boolean mDragToDesktopAnimationStarted;
- private float mCaptionDragStartX;
public DesktopModeWindowDecorViewModel(
Context context,
@@ -525,7 +524,6 @@
DesktopModeWindowDecoration relevantDecor) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
- mCaptionDragStartX = ev.getX();
// Begin drag through status bar if applicable.
if (relevantDecor != null) {
mDragToDesktopAnimationStartBounds.set(
@@ -580,8 +578,9 @@
}
if (mTransitionDragActive) {
mDesktopTasksController.ifPresent(
- c -> c.onDragPositioningMoveThroughStatusBar(relevantDecor.mTaskInfo,
- relevantDecor.mTaskSurface, ev.getY()));
+ c -> c.onDragPositioningMoveThroughStatusBar(
+ relevantDecor.mTaskInfo,
+ relevantDecor.mTaskSurface, ev.getY()));
final int statusBarHeight = getStatusBarHeight(
relevantDecor.mTaskInfo.displayId);
if (ev.getY() > statusBarHeight) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
index 11c5951..6178156 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -18,15 +18,18 @@
import android.content.Context
import android.system.helpers.CommandsHelper
+import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.LetterboxAppHelper
import android.tools.device.flicker.legacy.FlickerTestFactory
import android.tools.device.flicker.legacy.IFlickerTestData
-import com.android.server.wm.flicker.helpers.LetterboxAppHelper
-import com.android.server.wm.flicker.helpers.setRotation
import com.android.wm.shell.flicker.BaseTest
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
+import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.layerKeepVisible
+import org.junit.After
import org.junit.Assume
import org.junit.Before
import org.junit.runners.Parameterized
@@ -35,7 +38,7 @@
protected val context: Context = instrumentation.context
protected val letterboxApp = LetterboxAppHelper(instrumentation)
lateinit var cmdHelper: CommandsHelper
- lateinit var letterboxStyle: HashMap<String, String>
+ private lateinit var letterboxStyle: HashMap<String, String>
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -45,12 +48,22 @@
letterboxApp.launchViaIntent(wmHelper)
setEndRotation()
}
+ teardown {
+ letterboxApp.exit(wmHelper)
+ }
}
@Before
fun before() {
cmdHelper = CommandsHelper.getInstance(instrumentation)
Assume.assumeTrue(tapl.isTablet && isIgnoreOrientationRequest())
+ letterboxStyle = mapLetterboxStyle()
+ setLetterboxEducationEnabled(false)
+ }
+
+ @After
+ fun after() {
+ resetLetterboxEducationEnabled()
}
private fun mapLetterboxStyle(): HashMap<String, String> {
@@ -67,6 +80,22 @@
return map
}
+ private fun getLetterboxStyle(): HashMap<String, String> {
+ if (!::letterboxStyle.isInitialized) {
+ letterboxStyle = mapLetterboxStyle()
+ }
+ return letterboxStyle
+ }
+
+ private fun resetLetterboxEducationEnabled() {
+ val enabled = getLetterboxStyle().getValue("Is education enabled")
+ cmdHelper.executeShellCommand("wm set-letterbox-style --isEducationEnabled $enabled")
+ }
+
+ private fun setLetterboxEducationEnabled(enabled: Boolean) {
+ cmdHelper.executeShellCommand("wm set-letterbox-style --isEducationEnabled $enabled")
+ }
+
private fun isIgnoreOrientationRequest(): Boolean {
val res = cmdHelper.executeShellCommand("wm get-ignore-orientation-request")
return res != null && res.contains("true")
@@ -89,10 +118,7 @@
/** Only run on tests with config_letterboxActivityCornersRadius != 0 in devices */
private fun assumeLetterboxRoundedCornersEnabled() {
- if (!::letterboxStyle.isInitialized) {
- letterboxStyle = mapLetterboxStyle()
- }
- Assume.assumeTrue(letterboxStyle.getValue("Corner radius") != "0")
+ Assume.assumeTrue(getLetterboxStyle().getValue("Corner radius") != "0")
}
fun assertLetterboxAppVisibleAtStartAndEnd() {
@@ -100,12 +126,20 @@
flicker.appWindowIsVisibleAtEnd(letterboxApp)
}
+ fun assertAppLetterboxedAtEnd() =
+ flicker.assertLayersEnd { isVisible(ComponentNameMatcher.LETTERBOX) }
+
+ fun assertAppLetterboxedAtStart() =
+ flicker.assertLayersStart { isVisible(ComponentNameMatcher.LETTERBOX) }
+
+ fun assertLetterboxAppLayerKeepVisible() = flicker.layerKeepVisible(letterboxApp)
+
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.rotationTests] for configuring screen orientation and navigation
- * modes.
+ * See [FlickerTestFactory.rotationTests] for configuring screen orientation and
+ * navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
index f212a4e..c2141a3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -70,6 +70,10 @@
@Test
fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtEndHasRoundedCorners()
+ @Postsubmit
+ @Test
+ fun appIsLetterboxedAtEnd() = assertAppLetterboxedAtEnd()
+
/**
* Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
* flicker, and disappears before the transition is complete
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
index 8e75439..b0e1a42 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
@@ -53,25 +53,32 @@
get() = {
super.transition(this)
transitions { letterboxApp.clickRestart(wmHelper) }
- teardown { letterboxApp.exit(wmHelper) }
}
@Postsubmit @Test fun appVisibleAtStartAndEnd() = assertLetterboxAppVisibleAtStartAndEnd()
@Postsubmit
@Test
- fun appLayerVisibilityChanges() {
- flicker.assertLayers {
- this.isVisible(letterboxApp)
+ fun appWindowVisibilityChanges() {
+ flicker.assertWm {
+ this.isAppWindowVisible(letterboxApp)
.then()
- .isInvisible(letterboxApp)
+ .isAppWindowInvisible(letterboxApp) // animatingExit true
.then()
- .isVisible(letterboxApp)
+ .isAppWindowVisible(letterboxApp) // Activity finish relaunching
}
}
@Postsubmit
@Test
+ fun appLayerKeepVisible() = assertLetterboxAppLayerKeepVisible()
+
+ @Postsubmit
+ @Test
+ fun appIsLetterboxedAtStart() = assertAppLetterboxedAtStart()
+
+ @Postsubmit
+ @Test
fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtStartHasRoundedCorners()
/** Checks that the visible region of [letterboxApp] is still within display bounds */
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
index 6199e0b..8592dea 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
@@ -94,7 +94,7 @@
WindowContainerTransaction wct = new WindowContainerTransaction();
doReturn(mToken).when(mTransitions)
.startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
- mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+ mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
@@ -115,7 +115,7 @@
WindowContainerTransaction wct = new WindowContainerTransaction();
doReturn(mToken).when(mTransitions)
.startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
- mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+ mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
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 4fad054..265b10d 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
@@ -100,7 +100,7 @@
doReturn(mToken).when(mTransitions)
.startTransition(transitionType, wct, mExitDesktopTaskTransitionHandler);
- mExitDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+ mExitDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FULLSCREEN);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
index 523cb66..54f36f6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
@@ -48,6 +48,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
@@ -71,6 +72,8 @@
@Mock
private ShellController mShellController;
@Mock
+ private ShellCommandHandler mShellCommandHandler;
+ @Mock
private DisplayController mDisplayController;
@Mock
private UiEventLogger mUiEventLogger;
@@ -89,7 +92,8 @@
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
mController = new DragAndDropController(mContext, mShellInit, mShellController,
- mDisplayController, mUiEventLogger, mIconProvider, mMainExecutor);
+ mShellCommandHandler, mDisplayController, mUiEventLogger, mIconProvider,
+ mMainExecutor);
mController.onInit();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
index 4559095..9d56686 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
@@ -179,4 +179,23 @@
mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_CHANGE);
assertThat(pendingBounds2).isNull();
}
+
+ @Test
+ public void testSetTaskVisibility_taskRemoved_noNPE() {
+ mTaskViewTransitions.removeTaskView(mTaskViewTaskController);
+
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController, false);
+ }
+
+ @Test
+ public void testSetTaskBounds_taskRemoved_noNPE() {
+ mTaskViewTransitions.removeTaskView(mTaskViewTaskController);
+
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
+ new Rect(0, 0, 100, 100));
+ }
}
diff --git a/libs/hwui/Tonemapper.cpp b/libs/hwui/Tonemapper.cpp
index 0d39f0e..974a5d0 100644
--- a/libs/hwui/Tonemapper.cpp
+++ b/libs/hwui/Tonemapper.cpp
@@ -97,7 +97,6 @@
.inputDataspace = sourceDataspace,
.outputDataspace = destinationDataspace,
.undoPremultipliedAlpha = source.alphaType() == kPremul_SkAlphaType,
- .fakeInputDataspace = destinationDataspace,
.type = shaders::LinearEffect::SkSLType::ColorFilter};
constexpr float kMaxDisplayBrightnessNits = 1000.f;
constexpr float kCurrentDisplayBrightnessNits = 500.f;
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 7e9d44f..c00a270 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -29,6 +29,7 @@
#include "Layer.h"
#include "Properties.h"
#include "RenderThread.h"
+#include "VulkanManager.h"
#include "pipeline/skia/ATraceMemoryDump.h"
#include "pipeline/skia/ShaderCache.h"
#include "pipeline/skia/SkiaMemoryTracer.h"
@@ -182,8 +183,14 @@
}
log.appendFormat("Contexts: %zu (stopped = %zu)\n", mCanvasContexts.size(), stoppedContexts);
+ auto vkInstance = VulkanManager::peekInstance();
if (!mGrContext) {
- log.appendFormat("No GPU context.\n");
+ if (!vkInstance) {
+ log.appendFormat("No GPU context.\n");
+ } else {
+ log.appendFormat("No GrContext; however %d remaining Vulkan refs",
+ vkInstance->getStrongCount() - 1);
+ }
return;
}
std::vector<skiapipeline::ResourcePair> cpuResourceMap = {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index f198bca..4cffc6c 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -107,11 +107,11 @@
#define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
-sp<VulkanManager> VulkanManager::getInstance() {
- // cache a weakptr to the context to enable a second thread to share the same vulkan state
- static wp<VulkanManager> sWeakInstance = nullptr;
- static std::mutex sLock;
+// cache a weakptr to the context to enable a second thread to share the same vulkan state
+static wp<VulkanManager> sWeakInstance = nullptr;
+static std::mutex sLock;
+sp<VulkanManager> VulkanManager::getInstance() {
std::lock_guard _lock{sLock};
sp<VulkanManager> vulkanManager = sWeakInstance.promote();
if (!vulkanManager.get()) {
@@ -122,6 +122,11 @@
return vulkanManager;
}
+sp<VulkanManager> VulkanManager::peekInstance() {
+ std::lock_guard _lock{sLock};
+ return sWeakInstance.promote();
+}
+
VulkanManager::~VulkanManager() {
if (mDevice != VK_NULL_HANDLE) {
mDeviceWaitIdle(mDevice);
@@ -404,9 +409,13 @@
}
}
-sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options,
- ContextType contextType) {
+static void onGrContextReleased(void* context) {
+ VulkanManager* manager = (VulkanManager*)context;
+ manager->decStrong((void*)onGrContextReleased);
+}
+sk_sp<GrDirectContext> VulkanManager::createContext(GrContextOptions& options,
+ ContextType contextType) {
GrVkBackendContext backendContext;
backendContext.fInstance = mInstance;
backendContext.fPhysicalDevice = mPhysicalDevice;
@@ -418,6 +427,11 @@
backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
backendContext.fGetProc = sSkiaGetProp;
+ LOG_ALWAYS_FATAL_IF(options.fContextDeleteProc != nullptr, "Conflicting fContextDeleteProcs!");
+ this->incStrong((void*)onGrContextReleased);
+ options.fContextDeleteContext = this;
+ options.fContextDeleteProc = onGrContextReleased;
+
return GrDirectContext::MakeVulkan(backendContext, options);
}
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index c5196ee..00a40c0 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -66,6 +66,7 @@
class VulkanManager final : public RefBase {
public:
static sp<VulkanManager> getInstance();
+ static sp<VulkanManager> peekInstance();
// Sets up the vulkan context that is shared amonst all clients of the VulkanManager. This must
// be call once before use of the VulkanManager. Multiple calls after the first will simiply
@@ -109,7 +110,7 @@
};
// returns a Skia graphic context used to draw content on the specified thread
- sk_sp<GrDirectContext> createContext(const GrContextOptions& options,
+ sk_sp<GrDirectContext> createContext(GrContextOptions& options,
ContextType contextType = ContextType::kRenderThread);
uint32_t getDriverVersion() const { return mDriverVersion; }
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index bffe137..913af8a 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -284,7 +284,9 @@
case HAL_DATASPACE_TRANSFER_GAMMA2_8:
return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
case HAL_DATASPACE_TRANSFER_ST2084:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
+ return SkColorSpace::MakeRGB({-2.0, -1.555223, 1.860454, 32 / 2523.0, 2413 / 128.0,
+ -2392 / 128.0, 8192 / 1305.0},
+ gamut);
case HAL_DATASPACE_TRANSFER_SMPTE_170M:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut);
case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
@@ -427,10 +429,10 @@
}
// Skia skcms' default HLG maps encoded [0, 1] to linear [1, 12] in order to follow ARIB
-// but LinearEffect expects a decoded [0, 1] range instead to follow Rec 2100.
+// but LinearEffect expects to map 1.0 == 203 nits
std::optional<skcms_TransferFunction> GetHLGScaleTransferFunction() {
skcms_TransferFunction hlgFn;
- if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 1.f / 12.f, 2.f, 2.f, 1.f / 0.17883277f,
+ if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 0.314509843, 2.f, 2.f, 1.f / 0.17883277f,
0.28466892f, 0.55991073f)) {
return std::make_optional<skcms_TransferFunction>(hlgFn);
}
diff --git a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
index 6092ac5..82fc33e 100644
--- a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
@@ -15,8 +15,8 @@
*/
package android.media.soundtrigger_middleware;
-import android.media.soundtrigger.RecognitionEvent;
-import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
/**
* Main interface for a client to get notifications of events coming from this module.
@@ -31,7 +31,7 @@
* In case of abortion, the caller may retry after the next onRecognitionAvailabilityChange()
* callback.
*/
- void onRecognition(int modelHandle, in RecognitionEvent event, int captureSession);
+ void onRecognition(int modelHandle, in RecognitionEventSys event, int captureSession);
/**
* Invoked whenever a phrase recognition event is triggered (typically, on recognition, but
* also in case of external aborting of a recognition or a forced recognition event - see the
@@ -39,7 +39,7 @@
* In case of abortion, the caller may retry after the next onRecognitionAvailabilityChange()
* callback.
*/
- void onPhraseRecognition(int modelHandle, in PhraseRecognitionEvent event, int captureSession);
+ void onPhraseRecognition(int modelHandle, in PhraseRecognitionEventSys event, int captureSession);
/**
* Notifies the client that some start/load operations that have previously failed for resource
* reasons (threw a ServiceSpecificException(RESOURCE_CONTENTION) or have been preempted) may
diff --git a/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEventSys.aidl b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEventSys.aidl
new file mode 100644
index 0000000..6c912ed
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEventSys.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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 android.media.soundtrigger_middleware;
+
+import android.media.soundtrigger.PhraseRecognitionEvent;
+
+/**
+ * Wrapper to android.media.soundtrigger.RecognitionEvent providing additional fields used by the
+ * framework.
+ */
+parcelable PhraseRecognitionEventSys {
+
+ PhraseRecognitionEvent phraseRecognitionEvent;
+ /**
+ * Timestamp of when the trigger event from SoundTriggerHal was received by the
+ * framework.
+ *
+ * <p>same units and timebase as {@link SystemClock#elapsedRealtime()}.
+ * The value will be -1 if the event was not generated from the HAL.
+ */
+ // @ElapsedRealtimeLong
+ long halEventReceivedMillis = -1;
+}
diff --git a/media/aidl/android/media/soundtrigger_middleware/RecognitionEventSys.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionEventSys.aidl
new file mode 100644
index 0000000..84e327d
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger_middleware/RecognitionEventSys.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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 android.media.soundtrigger_middleware;
+
+import android.media.soundtrigger.RecognitionEvent;
+
+/**
+ * Wrapper to android.media.soundtrigger.RecognitionEvent providing additional fields used by the
+ * framework.
+ */
+parcelable RecognitionEventSys {
+
+ RecognitionEvent recognitionEvent;
+ /**
+ * Timestamp of when the trigger event from SoundTriggerHal was received by the
+ * framework.
+ *
+ * <p>same units and timebase as {@link SystemClock#elapsedRealtime()}.
+ * The value will be -1 if the event was not generated from the HAL.
+ */
+ // @ElapsedRealtimeLong
+ long halEventReceivedMillis = -1;
+}
diff --git a/native/android/activity_manager.cpp b/native/android/activity_manager.cpp
index 155a355..bc6a84f 100644
--- a/native/android/activity_manager.cpp
+++ b/native/android/activity_manager.cpp
@@ -45,7 +45,7 @@
void onUidIdle(uid_t uid, bool disabled) override;
void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
int32_t capability) override;
- void onUidProcAdjChanged(uid_t uid) override;
+ void onUidProcAdjChanged(uid_t uid, int32_t adj) override;
// IBinder::DeathRecipient implementation
void binderDied(const wp<IBinder>& who) override;
@@ -121,7 +121,7 @@
void UidObserver::onUidIdle(uid_t uid __unused, bool disabled __unused) {}
-void UidObserver::onUidProcAdjChanged(uid_t uid __unused) {}
+void UidObserver::onUidProcAdjChanged(uid_t uid __unused, int32_t adj __unused) {}
void UidObserver::onUidStateChanged(uid_t uid, int32_t procState,
int64_t procStateSeq __unused,
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
index 5f067e9..b8887390 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
@@ -60,6 +60,7 @@
@NonNull private Intent mIntent;
@NonNull private URL mUrl;
@TelephonyManager.PremiumCapability protected int mCapability;
+ private boolean mIsUserTriggeredFinish;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -71,6 +72,7 @@
SlicePurchaseController.PREMIUM_CAPABILITY_INVALID);
String url = mIntent.getStringExtra(SlicePurchaseController.EXTRA_PURCHASE_URL);
mApplicationContext = getApplicationContext();
+ mIsUserTriggeredFinish = true;
logd("onCreate: subId=" + subId + ", capability="
+ TelephonyManager.convertPremiumCapabilityToString(mCapability) + ", url=" + url);
@@ -153,12 +155,20 @@
@Override
protected void onDestroy() {
- logd("onDestroy: User canceled the purchase by closing the application.");
- SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponse(
- mIntent, SlicePurchaseController.EXTRA_INTENT_CANCELED);
+ if (mIsUserTriggeredFinish) {
+ logd("onDestroy: User canceled the purchase by closing the application.");
+ SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponse(
+ mIntent, SlicePurchaseController.EXTRA_INTENT_CANCELED);
+ }
super.onDestroy();
}
+ @Override
+ public void finishAndRemoveTask() {
+ mIsUserTriggeredFinish = false;
+ super.finishAndRemoveTask();
+ }
+
private void setupWebView() {
// Create WebView
mWebView = new WebView(this);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
index f594bf2..7ed1816 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
@@ -123,12 +123,11 @@
viewHolder.mExpandButton.setTag(R.drawable.btn_expand_more);
}
- setAccessibility(view, viewType,
- AccessibilityNodeInfo.ACTION_CLICK, R.string.permission_expand, 0);
-
// Add expand buttons if the permissions are more than PERMISSION_SIZE in this list also
// make the summary invisible by default.
if (mPermissions.size() > PERMISSION_SIZE) {
+ setAccessibility(view, viewType,
+ AccessibilityNodeInfo.ACTION_CLICK, R.string.permission_expand, 0);
viewHolder.mPermissionSummary.setVisibility(View.GONE);
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 7d71bd5..6df0778 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -24,8 +24,8 @@
<string name="string_cancel">Cancel</string>
<!-- This is a label for a button that takes user to the next screen. [CHAR LIMIT=20] -->
<string name="string_continue">Continue</string>
- <!-- This is a label for a button that links to different places where the user can save their passkeys. [CHAR LIMIT=20] -->
- <string name="string_more_options">More options</string>
+ <!-- This is a label for a button that leads to a holistic view of all different options where the user can save their new app credential. [CHAR LIMIT=20] -->
+ <string name="string_more_options">Save another way</string>
<!-- This is a label for a button that links to additional information about passkeys. [CHAR LIMIT=20] -->
<string name="string_learn_more">Learn more</string>
<!-- This is a label for content description for show password icon button. -->
@@ -120,6 +120,8 @@
<!-- Strings for the get flow. -->
<!-- This appears as the title of the modal bottom sheet asking for user confirmation to use the single previously saved passkey to sign in to the app. [CHAR LIMIT=200] -->
<string name="get_dialog_title_use_passkey_for">Use your saved passkey for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
+ <!-- This appears as the title of the modal bottom sheet asking for user confirmation to use the single previously saved password to sign in to the app. [CHAR LIMIT=200] -->
+ <string name="get_dialog_title_use_password_for">Use your saved password for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
<!-- This appears as the title of the dialog asking for user confirmation to use the single user credential (previously saved or to be created) to sign in to the app. [CHAR LIMIT=200] -->
<string name="get_dialog_title_use_sign_in_for">Use your sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
<!-- This appears as the title of the dialog asking for user to make a choice from various available user credentials (previously saved or to be created) to sign in to the app. [CHAR LIMIT=200] -->
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 1fb5e3f..54a8678d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -25,6 +25,7 @@
import android.os.ResultReceiver
import android.util.Log
import androidx.activity.ComponentActivity
+import androidx.activity.OnBackPressedCallback
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.viewModels
@@ -48,11 +49,12 @@
class CredentialSelectorActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ Log.d(Constants.LOG_TAG, "Creating new CredentialSelectorActivity")
overrideActivityTransition(Activity.OVERRIDE_TRANSITION_OPEN,
0, 0)
overrideActivityTransition(Activity.OVERRIDE_TRANSITION_CLOSE,
0, 0)
- Log.d(Constants.LOG_TAG, "Creating new CredentialSelectorActivity")
+
try {
val (isCancellationRequest, shouldShowCancellationUi, _) =
maybeCancelUIUponRequest(intent)
@@ -61,6 +63,18 @@
}
val userConfigRepo = UserConfigRepo(this)
val credManRepo = CredentialManagerRepo(this, intent, userConfigRepo)
+
+ val backPressedCallback = object : OnBackPressedCallback(
+ true // default to enabled
+ ) {
+ override fun handleOnBackPressed() {
+ credManRepo.onUserCancel()
+ Log.d(Constants.LOG_TAG, "Activity back triggered: finish the activity.")
+ [email protected]()
+ }
+ }
+ onBackPressedDispatcher.addCallback(this, backPressedCallback)
+
setContent {
PlatformTheme {
CredentialManagerBottomSheet(
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 00c2f1a..a35310c 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -482,7 +482,8 @@
CredentialType.PASSWORD,
appLabel,
context.getDrawable(R.drawable.ic_password_24) ?: return null,
- preferImmediatelyAvailableCredentials = false,
+ preferImmediatelyAvailableCredentials =
+ createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
appPreferredDefaultProviderId = appPreferredDefaultProviderId,
userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
)
@@ -509,7 +510,8 @@
appName = appLabel,
typeIcon = displayInfo.credentialTypeIcon?.loadDrawable(context)
?: context.getDrawable(R.drawable.ic_other_sign_in_24) ?: return null,
- preferImmediatelyAvailableCredentials = false,
+ preferImmediatelyAvailableCredentials =
+ createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
appPreferredDefaultProviderId = appPreferredDefaultProviderId,
userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
)
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 706666c..2e49dd5 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -841,7 +841,8 @@
Settings.Secure.ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT,
Settings.Secure.UI_TRANSLATION_ENABLED,
- Settings.Secure.CREDENTIAL_SERVICE);
+ Settings.Secure.CREDENTIAL_SERVICE,
+ Settings.Secure.CREDENTIAL_SERVICE_PRIMARY);
@Test
public void systemSettingsBackedUpOrDenied() {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index a110f56..8b3fd41 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -17,12 +17,12 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.shell"
- coreApp="true"
- android:sharedUserId="android.uid.shell"
- >
+ package="com.android.shell"
+ coreApp="true"
+ android:sharedUserId="android.uid.shell"
+ >
- <!-- Standard permissions granted to the shell. -->
+ <!-- Standard permissions granted to the shell. -->
<uses-permission android:name="android.permission.MANAGE_HEALTH_PERMISSIONS" />
<uses-permission android:name="android.permission.MANAGE_HEALTH_DATA" />
<uses-permission android:name="android.permission.health.READ_EXERCISE_ROUTE" />
@@ -125,7 +125,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
- <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- BLUETOOTH_PRIVILEGED is needed for testing purposes only. -->
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
@@ -136,7 +136,7 @@
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.MANAGE_USB" />
<uses-permission android:name="android.permission.USE_RESERVED_DISK" />
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- System tool permissions granted to the shell. -->
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
@@ -231,16 +231,16 @@
<uses-permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS" />
<uses-permission android:name="android.permission.CLEAR_FREEZE_PERIOD" />
<uses-permission android:name="android.permission.MODIFY_QUIET_MODE" />
- <uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE"/>
- <uses-permission android:name="android.permission.CHANGE_LOWPAN_STATE"/>
- <uses-permission android:name="android.permission.READ_LOWPAN_CREDENTIAL"/>
+ <uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE" />
+ <uses-permission android:name="android.permission.CHANGE_LOWPAN_STATE" />
+ <uses-permission android:name="android.permission.READ_LOWPAN_CREDENTIAL" />
<uses-permission android:name="android.permission.BLUETOOTH_STACK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" />
<uses-permission android:name="android.permission.FRAME_STATS" />
<uses-permission android:name="android.permission.BIND_APPWIDGET" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
- <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
+ <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS" />
<uses-permission android:name="android.permission.CHANGE_APP_IDLE_STATE" />
<uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
@@ -304,7 +304,7 @@
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.BACKGROUND_CAMERA" />
<uses-permission android:name="android.permission.SYSTEM_CAMERA" />
- <!-- Permissions needed to test onCameraOpened/Closed callbacks -->
+ <!-- Permissions needed to test onCameraOpened/Closed callbacks -->
<uses-permission android:name="android.permission.CAMERA_OPEN_CLOSE_LISTENER" />
<!-- Permissions needed for CTS camera test: RecordingTest.java when assuming shell id -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
@@ -344,7 +344,7 @@
<uses-permission android:name="android.permission.LOADER_USAGE_STATS" />
<!-- Permission required for storage tests - FuseDaemonHostTest -->
- <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- Permission needed to run network tests in CTS -->
<uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
@@ -386,54 +386,54 @@
<uses-permission android:name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE" />
<!-- Permission required for CTS test - CrossProfileAppsHostSideTest -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES" />
<!-- Permission required for CTS test - CrossProfileAppsHostSideTest -->
- <uses-permission android:name="android.permission.START_CROSS_PROFILE_ACTIVITIES"/>
+ <uses-permission android:name="android.permission.START_CROSS_PROFILE_ACTIVITIES" />
<!-- permissions required for CTS test - PhoneStateListenerTest -->
<uses-permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH" />
<!-- Permissions required for granting and logging -->
- <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
- <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
- <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"/>
- <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
+ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG" />
+ <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD" />
<!-- Permission required for CTS test - BatterySaverTest -->
- <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
+ <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE" />
<!-- Permission required for CTS test - UiModeManagerTest -->
- <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
- <uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
+ <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" />
+ <uses-permission android:name="android.permission.READ_PROJECTION_STATE" />
<!-- Permission required for CTS tests - UiModeManagerTest, CarModeInCallServiceTest -->
- <uses-permission android:name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION"/>
+ <uses-permission android:name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION" />
<!-- Permission required for CTS test - SystemConfigTest -->
- <uses-permission android:name="android.permission.READ_CARRIER_APP_INFO"/>
+ <uses-permission android:name="android.permission.READ_CARRIER_APP_INFO" />
<!-- Permission required for CTS test - CarModeInCallServiceTest -->
- <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+ <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
<!-- Permission requried for CTS test - CellBroadcastIntentsTest -->
- <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"/>
+ <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS" />
<!-- Permission required for CTS test - TetheringManagerTest -->
- <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/>
+ <uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
<!-- Permission required for CTS test - CtsOsTestCases -->
- <uses-permission android:name="android.permission.MANAGE_CRATES"/>
+ <uses-permission android:name="android.permission.MANAGE_CRATES" />
<!-- Allows setting brightness from the shell -->
- <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS"/>
+ <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
<!-- Permission required for CTS test - ShortcutManagerUsageTest -->
- <uses-permission android:name="android.permission.ACCESS_SHORTCUTS"/>
+ <uses-permission android:name="android.permission.ACCESS_SHORTCUTS" />
<!-- Permissions required for CTS test - UsageStatsTest -->
- <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
- <uses-permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS" />
+ <uses-permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS" />
<!-- Permission needed for CTS test - MusicRecognitionManagerTest -->
<uses-permission android:name="android.permission.MANAGE_MUSIC_RECOGNITION" />
@@ -442,8 +442,8 @@
<uses-permission android:name="android.permission.MANAGE_SPEECH_RECOGNITION" />
<!-- Permissions required to test ambient display. -->
- <uses-permission android:name="android.permission.READ_DREAM_STATE"/>
- <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
+ <uses-permission android:name="android.permission.READ_DREAM_STATE" />
+ <uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
<!-- Permission required for CTS test - CtsLightsManagerTest -->
<uses-permission android:name="android.permission.CONTROL_DEVICE_LIGHTS" />
@@ -470,7 +470,7 @@
<uses-permission android:name="android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE" />
<!-- Permission required for testing system audio effect APIs. -->
- <uses-permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"/>
+ <uses-permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS" />
<!-- Permission required for running networking unit tests -->
<uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
@@ -495,7 +495,7 @@
<uses-permission android:name="android.permission.TV_INPUT_HARDWARE" />
<uses-permission android:name="android.permission.TIS_EXTENSION_INTERFACE" />
<uses-permission android:name="com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS" />
- <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA"/>
+ <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
<!-- Permission needed for CTS test - PrivilegedLocationPermissionTest -->
<uses-permission android:name="android.permission.LOCATION_HARDWARE" />
@@ -560,14 +560,14 @@
<uses-permission android:name="android.permission.BIND_CARRIER_SERVICES" />
<!-- Allows overriding the system's device state from the shell -->
- <uses-permission android:name="android.permission.CONTROL_DEVICE_STATE"/>
+ <uses-permission android:name="android.permission.CONTROL_DEVICE_STATE" />
<!-- Permissions required for CTS tests to close system dialogs -->
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
<!-- Permissions required for CTS test - HideOverlayWindowsTest -->
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
- <uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY"/>
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
<!-- Permission required for CTS test - CtsHdmiCecHostTestCases -->
<uses-permission android:name="android.permission.HDMI_CEC" />
@@ -630,21 +630,21 @@
<uses-permission android:name="android.permission.UPDATE_FONTS" />
<!-- Permission required for Launcher testing - DigitalWellbeingToastTest -->
- <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"/>
+ <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" />
<!-- Permission required for hotword detection service CTS tests -->
<uses-permission android:name="android.permission.MANAGE_HOTWORD_DETECTION" />
<uses-permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
<!-- Permission required for CTS test - CtsVoiceInteractionTestCases -->
- <uses-permission android:name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"/>
+ <uses-permission android:name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER" />
<uses-permission android:name="android.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE" />
<!-- Permission required for CTS test - KeyguardLockedStateApiTest -->
<uses-permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" />
- <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/>
+ <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION" />
<!-- Permission required for CTS test - MediaCodecResourceTest -->
<uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID" />
@@ -820,8 +820,8 @@
<uses-permission android:name="android.permission.DELETE_STAGED_HEALTH_CONNECT_REMOTE_DATA" />
<uses-permission android:name="android.permission.STAGE_HEALTH_CONNECT_REMOTE_DATA" />
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
<!-- Permissions required for CTS test - CtsBroadcastRadioTestCases -->
<uses-permission android:name="android.permission.ACCESS_BROADCAST_RADIO" />
@@ -832,12 +832,17 @@
<!-- Permission required for CTS test - CtsTelephonyProviderTestCases -->
<uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
- <uses-permission android:name="android.permission.LOG_FOREGROUND_RESOURCE_USE"/>
+ <uses-permission android:name="android.permission.LOG_FOREGROUND_RESOURCE_USE" />
+ <!-- Permission required for GTS test - GtsAttestationVerificationDeviceSideTestCases -->
+ <uses-permission android:name="android.permission.USE_ATTESTATION_VERIFICATION_SERVICE" />
+ <!-- Permission required for GTS test - GtsCredentialsTestCases -->
+ <uses-permission android:name="android.permission.LAUNCH_CREDENTIAL_SELECTOR" />
- <application android:label="@string/app_label"
- android:theme="@android:style/Theme.DeviceDefault.DayNight"
- android:defaultToDeviceProtectedStorage="true"
- android:directBootAware="true">
+ <application
+ android:label="@string/app_label"
+ android:theme="@android:style/Theme.DeviceDefault.DayNight"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.android.shell"
@@ -860,10 +865,11 @@
</intent-filter>
</provider>
- <provider android:name=".HeapDumpProvider"
- android:authorities="com.android.shell.heapdump"
- android:grantUriPermissions="true"
- android:exported="false" />
+ <provider
+ android:name=".HeapDumpProvider"
+ android:authorities="com.android.shell.heapdump"
+ android:grantUriPermissions="true"
+ android:exported="false" />
<activity
android:name=".BugreportWarningActivity"
@@ -872,13 +878,14 @@
android:excludeFromRecents="true"
android:exported="false" />
- <activity android:name=".HeapDumpActivity"
- android:theme="@*android:style/Theme.Translucent.NoTitleBar"
- android:label="@*android:string/dump_heap_title"
- android:finishOnCloseSystemDialogs="true"
- android:noHistory="true"
- android:excludeFromRecents="true"
- android:exported="false" />
+ <activity
+ android:name=".HeapDumpActivity"
+ android:theme="@*android:style/Theme.Translucent.NoTitleBar"
+ android:label="@*android:string/dump_heap_title"
+ android:finishOnCloseSystemDialogs="true"
+ android:noHistory="true"
+ android:excludeFromRecents="true"
+ android:exported="false" />
<receiver
android:name=".BugreportRequestedReceiver"
@@ -903,7 +910,7 @@
<receiver
android:name=".ProfcollectUploadReceiver"
android:exported="true"
- android:permission="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD" >
+ android:permission="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD">
<intent-filter>
<action android:name="com.android.shell.action.PROFCOLLECT_UPLOAD" />
</intent-filter>
@@ -912,6 +919,6 @@
<service
android:name=".BugreportProgressService"
android:foregroundServiceType="systemExempted"
- android:exported="false"/>
+ android:exported="false" />
</application>
</manifest>
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index 5b5871f..8eb012d 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -43,6 +43,7 @@
"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 94b3740..4037fd4 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 42a8636..48dd08f 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
deleted file mode 100644
index 9dbb920..0000000
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 8da87feb..0000000
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * 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 3417ffd..142fd21 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.systemui.animation.Interpolators.LINEAR
+import com.android.app.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 58ffef2..8e79e3c 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
@@ -25,6 +25,7 @@
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 f3d8b17..dd32851 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.systemui.animation.Interpolators
+import com.android.app.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 941a925..8dd2c39 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
@@ -28,9 +28,9 @@
import android.util.AttributeSet
import android.util.MathUtils.constrainedMap
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.log.LogBuffer
diff --git a/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml b/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml
index d123caf..cff2839 100644
--- a/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml
+++ b/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml
@@ -2,11 +2,11 @@
android:viewportWidth="22" android:width="20.166666dp" xmlns:android="http://schemas.android.com/apk/res/android">
<group>
<clip-path android:pathData="M0,0.5h22v11h-22z"/>
- <path android:fillColor="#231F20" android:pathData="M6.397,9.908H0V11.5H6.397V9.908Z"/>
- <path android:fillColor="#231F20" android:pathData="M14.199,9.908H7.801V11.5H14.199V9.908Z"/>
- <path android:fillColor="#231F20" android:pathData="M11.858,0.5H10.142V6.434H11.858V0.5Z"/>
- <path android:fillColor="#231F20" android:pathData="M8.348,7.129L3.885,2.975L3.823,2.932L2.668,4.003L2.621,4.046L7.084,8.2L7.146,8.243L8.301,7.172L8.348,7.129Z"/>
- <path android:fillColor="#231F20" android:pathData="M18.224,2.975L18.177,2.932L13.653,7.129L14.807,8.2L14.854,8.243L19.379,4.046L18.224,2.975Z"/>
- <path android:fillColor="#231F20" android:pathData="M22,9.908H15.603V11.5H22V9.908Z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M6.397,9.908H0V11.5H6.397V9.908Z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M14.199,9.908H7.801V11.5H14.199V9.908Z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M11.858,0.5H10.142V6.434H11.858V0.5Z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M8.348,7.129L3.885,2.975L3.823,2.932L2.668,4.003L2.621,4.046L7.084,8.2L7.146,8.243L8.301,7.172L8.348,7.129Z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M18.224,2.975L18.177,2.932L13.653,7.129L14.807,8.2L14.854,8.243L19.379,4.046L18.224,2.975Z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M22,9.908H15.603V11.5H22V9.908Z"/>
</group>
</vector>
diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml
index 441f963..386c9d6 100644
--- a/packages/SystemUI/res/layout/combined_qs_header.xml
+++ b/packages/SystemUI/res/layout/combined_qs_header.xml
@@ -14,12 +14,17 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
+
+<!--
+keep split_shade_status_bar height constant to avoid requestLayout calls on each
+frame when animating QS <-> QQS transition
+-->
<com.android.systemui.util.NoRemeasureMotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/split_shade_status_bar"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/qs_header_height"
android:minHeight="@dimen/large_screen_shade_header_min_height"
android:clickable="false"
android:focusable="true"
@@ -30,6 +35,14 @@
app:layoutDescription="@xml/combined_qs_header_scene">
<androidx.constraintlayout.widget.Guideline
+ android:id="@+id/qqs_header_bottom_guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ app:layout_constraintGuide_begin="@dimen/large_screen_shade_header_min_height"
+ />
+
+ <androidx.constraintlayout.widget.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/begin_guide"
diff --git a/packages/SystemUI/res/layout/smart_action_button.xml b/packages/SystemUI/res/layout/smart_action_button.xml
index 488be3a..4e5785d 100644
--- a/packages/SystemUI/res/layout/smart_action_button.xml
+++ b/packages/SystemUI/res/layout/smart_action_button.xml
@@ -29,8 +29,8 @@
android:textSize="@dimen/smart_reply_button_font_size"
android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
android:textColor="@color/smart_reply_button_text"
- android:paddingLeft="@dimen/smart_reply_button_action_padding_left"
- android:paddingRight="@dimen/smart_reply_button_padding_horizontal"
+ android:paddingStart="@dimen/smart_reply_button_action_padding_left"
+ android:paddingEnd="@dimen/smart_reply_button_padding_horizontal"
android:drawablePadding="@dimen/smart_action_button_icon_padding"
android:textStyle="normal"
android:ellipsize="none"/>
diff --git a/packages/SystemUI/res/layout/smart_reply_button.xml b/packages/SystemUI/res/layout/smart_reply_button.xml
index ddf16e0..b24362f 100644
--- a/packages/SystemUI/res/layout/smart_reply_button.xml
+++ b/packages/SystemUI/res/layout/smart_reply_button.xml
@@ -31,7 +31,7 @@
android:textSize="@dimen/smart_reply_button_font_size"
android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
android:textColor="@color/smart_reply_button_text"
- android:paddingLeft="@dimen/smart_reply_button_padding_horizontal"
- android:paddingRight="@dimen/smart_reply_button_padding_horizontal"
+ android:paddingStart="@dimen/smart_reply_button_padding_horizontal"
+ android:paddingEnd="@dimen/smart_reply_button_padding_horizontal"
android:textStyle="normal"
android:ellipsize="none"/>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index cb8c2a7..db7eb7a 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -207,11 +207,6 @@
<color name="controls_task_view_bg">#CC191C1D</color>
<color name="control_popup_dim">#8A000000</color>
- <!-- Keyboard backlight indicator-->
- <color name="backlight_indicator_step_filled">#F6E388</color>
- <color name="backlight_indicator_step_empty">#494740</color>
- <color name="backlight_indicator_background">#32302A</color>
-
<!-- Docked misalignment message -->
<color name="misalignment_text_color">#F28B82</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 1602189..1252695 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -889,4 +889,8 @@
-->
<dimen name="shade_swipe_collapse_threshold">0.5</dimen>
<!-- [END] MULTI SHADE -->
+
+ <!-- Time (in ms) to delay the bouncer views from showing when passive auth may be used for
+ device entry. -->
+ <integer name="primary_bouncer_passive_auth_delay">250</integer>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0aa880f..aff0e80 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -615,6 +615,7 @@
<dimen name="qs_header_carrier_separator_width">6dp</dimen>
<dimen name="qs_carrier_margin_width">4dp</dimen>
<dimen name="qs_footer_icon_size">20dp</dimen>
+ <dimen name="qs_header_height">120dp</dimen>
<dimen name="qs_header_row_min_height">48dp</dimen>
<dimen name="qs_header_non_clickable_element_height">24dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 499dfa4..eaeaabe8 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -198,6 +198,9 @@
<item type="id" name="pm_lite"/>
<item type="id" name="settings_button_container"/>
+ <!--Keyboard Backlight Dialog -->
+ <item type="id" name="keyboard_backlight_dialog_container"/>
+
<item type="id" name="log_access_dialog_allow_button" />
<item type="id" name="log_access_dialog_deny_button" />
</resources>
diff --git a/packages/SystemUI/res/xml/qqs_header.xml b/packages/SystemUI/res/xml/qqs_header.xml
index 00a0444..1950965 100644
--- a/packages/SystemUI/res/xml/qqs_header.xml
+++ b/packages/SystemUI/res/xml/qqs_header.xml
@@ -28,7 +28,7 @@
android:layout_height="@dimen/large_screen_shade_header_min_height"
app:layout_constraintStart_toStartOf="@id/begin_guide"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
app:layout_constraintEnd_toStartOf="@id/date"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
@@ -62,7 +62,7 @@
app:layout_constraintStart_toEndOf="@id/date"
app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintHorizontal_chainStyle="packed"
/>
@@ -77,7 +77,7 @@
app:layout_constraintStart_toEndOf="@id/statusIcons"
app:layout_constraintEnd_toEndOf="@id/end_guide"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintHorizontal_chainStyle="packed"
/>
@@ -105,7 +105,7 @@
app:layout_constraintStart_toEndOf="@id/date"
app:layout_constraintEnd_toEndOf="@id/end_guide"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
app:layout_constraintHorizontal_bias="1"
/>
</Constraint>
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
index 62f4f22..a82f0e3 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
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.TITLE
/** Displays security messages for the keyguard bouncer. */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 4629e8b..644a9bc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -15,12 +15,13 @@
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.log.LogBuffer;
import com.android.systemui.log.LogLevel;
import com.android.systemui.plugins.ClockController;
+import com.android.systemui.shared.clocks.DefaultClockController;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -46,6 +47,9 @@
public static final int LARGE = 0;
public static final int SMALL = 1;
+ // compensate for translation of parents subject to device screen
+ // In this case, the translation comes from KeyguardStatusView
+ public int screenOffsetYPadding = 0;
/** Returns a region for the large clock to position itself, based on the given parent. */
public static Rect getLargeClockRegion(ViewGroup parent) {
@@ -161,8 +165,18 @@
}
if (mLargeClockFrame.isLaidOut()) {
- mClock.getLargeClock().getEvents().onTargetRegionChanged(
- getLargeClockRegion(mLargeClockFrame));
+ Rect targetRegion = getLargeClockRegion(mLargeClockFrame);
+ if (mClock instanceof DefaultClockController) {
+ mClock.getLargeClock().getEvents().onTargetRegionChanged(
+ targetRegion);
+ } else {
+ mClock.getLargeClock().getEvents().onTargetRegionChanged(
+ new Rect(
+ targetRegion.left,
+ targetRegion.top - screenOffsetYPadding,
+ targetRegion.right,
+ targetRegion.bottom - screenOffsetYPadding));
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 50dac32..d8bf570 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -169,6 +169,16 @@
}
/**
+ * Used for status view to pass the screen offset from parent view
+ */
+ public void setLockscreenClockY(int clockY) {
+ if (mView.screenOffsetYPadding != clockY) {
+ mView.screenOffsetYPadding = clockY;
+ mView.updateClockTargetRegions();
+ }
+ }
+
+ /**
* Attach the controller to the view it relates to.
*/
@Override
@@ -394,13 +404,6 @@
PropertyAnimator.setProperty(mStatusArea, AnimatableProperty.TRANSLATION_X,
x, props, animate);
}
-
- }
-
- void updateKeyguardStatusViewOffset() {
- // updateClockTargetRegions will call onTargetRegionChanged
- // which will require the correct translationY property of keyguardStatusView after updating
- mView.updateClockTargetRegions();
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 0394754..58807e4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_APPEAR;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
@@ -32,9 +33,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;
/**
@@ -184,6 +185,7 @@
}
mAppearAnimator.setDuration(ANIMATION_DURATION);
mAppearAnimator.addUpdateListener(animation -> animate(animation.getAnimatedFraction()));
+ mAppearAnimator.addListener(getAnimationListener(CUJ_LOCKSCREEN_PIN_APPEAR));
mAppearAnimator.start();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 33bea02..1d7c35d 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 0a91150..b4ddc9a 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 b88d85c..5cc0547 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.systemui.animation.InterpolatorsAndroidX.DECELERATE_QUINT;
+import static com.android.app.animation.InterpolatorsAndroidX.DECELERATE_QUINT;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
import static java.lang.Integer.max;
@@ -87,6 +87,7 @@
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,7 +98,6 @@
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 c9128e5..96ac8ad 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 65a7166..b4f124a 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 0826f8a..794eeda 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;
@@ -215,6 +215,15 @@
}
/**
+ * Pass top margin from ClockPositionAlgorithm in NotificationPanelViewController
+ * Use for clock view in LS to compensate for top margin to align to the screen
+ * Regardless of translation from AOD and unlock gestures
+ */
+ public void setLockscreenClockY(int clockY) {
+ mKeyguardClockSwitchController.setLockscreenClockY(clockY);
+ }
+
+ /**
* Set whether the view accessibility importance mode.
*/
public void setStatusAccessibilityImportance(int mode) {
@@ -230,7 +239,6 @@
* Update position of the view with an optional animation
*/
public void updatePosition(int x, int y, float scale, boolean animate) {
- float oldY = mView.getY();
setProperty(AnimatableProperty.Y, y, animate);
ClockController clock = mKeyguardClockSwitchController.getClock();
@@ -246,10 +254,6 @@
setProperty(AnimatableProperty.SCALE_X, 1f, animate);
setProperty(AnimatableProperty.SCALE_Y, 1f, animate);
}
-
- if (oldY != y) {
- mKeyguardClockSwitchController.updateKeyguardStatusViewOffset();
- }
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 7d7b276..c1f70fb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2884,7 +2884,19 @@
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
+ /**
+ * If the current state of the device allows for triggering active unlock. This does not
+ * include active unlock availability.
+ */
+ public boolean canTriggerActiveUnlockBasedOnDeviceState() {
+ return shouldTriggerActiveUnlock(/* shouldLog */ false);
+ }
+
private boolean shouldTriggerActiveUnlock() {
+ return shouldTriggerActiveUnlock(/* shouldLog */ true);
+ }
+
+ private boolean shouldTriggerActiveUnlock(boolean shouldLog) {
// Triggers:
final boolean triggerActiveUnlockForAssistant = shouldTriggerActiveUnlockForAssistant();
final boolean awakeKeyguard = mPrimaryBouncerFullyShown || mAlternateBouncerShowing
@@ -2914,19 +2926,21 @@
&& !mKeyguardGoingAway
&& !mSecureCameraLaunched;
- // Aggregate relevant fields for debug logging.
- logListenerModelData(
- new KeyguardActiveUnlockModel(
- System.currentTimeMillis(),
- user,
- shouldTriggerActiveUnlock,
- awakeKeyguard,
- mAuthInterruptActive,
- fpLockedOut,
- primaryAuthRequired,
- mSwitchingUser,
- triggerActiveUnlockForAssistant,
- userCanDismissLockScreen));
+ if (shouldLog) {
+ // Aggregate relevant fields for debug logging.
+ logListenerModelData(
+ new KeyguardActiveUnlockModel(
+ System.currentTimeMillis(),
+ user,
+ shouldTriggerActiveUnlock,
+ awakeKeyguard,
+ mAuthInterruptActive,
+ fpLockedOut,
+ primaryAuthRequired,
+ mSwitchingUser,
+ triggerActiveUnlockForAssistant,
+ userCanDismissLockScreen));
+ }
return shouldTriggerActiveUnlock;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index d8568ba..61af722 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.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.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 c6c7113..7d76f12 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -37,7 +37,7 @@
import androidx.annotation.StyleRes;
-import com.android.systemui.animation.Interpolators;
+import com.android.app.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 4aeab97..4557b34 100644
--- a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
@@ -37,9 +37,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/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
index de82ca0..c1871e0 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.systemui.animation.Interpolators
+import com.android.app.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 48805be..76086df 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.systemui.animation.Interpolators
+import com.android.app.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 aa94ad9..99d4662 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;
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
index d6f0b59..d491975 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 0002ae9..2aac056 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 b386bc9..ce85124 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 55f6d07..6f0f633 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.systemui.animation.Interpolators
+import com.android.app.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 b007134..5ede16d 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.systemui.animation.Interpolators
+import com.android.app.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 ef7dcb7..1dbafc6 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.systemui.animation.Interpolators
+import com.android.app.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 ba8e60a..52db4ab 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 935de02..9f5669f 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 e2d36dc..9292bd7 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 11ef749..7bf8f4d 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 8d0edf8..b447d66 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.systemui.animation.Interpolators
+import com.android.app.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 6a9aaf8..e6361f4 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.systemui.animation.Interpolators
+import com.android.app.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 fa36eee..1461135 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.systemui.animation.Interpolators
+import com.android.app.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/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 89c45d7..17cf808 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -69,6 +69,7 @@
import com.android.systemui.qs.QSFragmentStartableModule;
import com.android.systemui.qs.footer.dagger.FooterActionsModule;
import com.android.systemui.recents.Recents;
+import com.android.systemui.retail.dagger.RetailModeModule;
import com.android.systemui.screenrecord.ScreenRecordModule;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.security.data.repository.SecurityRepositoryModule;
@@ -179,6 +180,7 @@
PrivacyModule.class,
QRCodeScannerModule.class,
QSFragmentStartableModule.class,
+ RetailModeModule.class,
ScreenshotModule.class,
SensorModule.class,
SecurityRepositoryModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index df46e07e..c5e7e0d 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -25,8 +25,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 15a32d2..c22019e 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/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 1fafa3d..d1d53cc 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -702,6 +702,5 @@
// TODO(b/278761837): Tracking Bug
@JvmField
- val USE_NEW_ACTIVITY_STARTER = unreleasedFlag(2801, name = "use_new_activity_starter",
- teamfood = true)
+ val USE_NEW_ACTIVITY_STARTER = releasedFlag(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 f64ed60..2807107 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -97,6 +97,7 @@
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;
@@ -116,7 +117,6 @@
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/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
index 2ef5e19..6bc763c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyboard.backlight.ui.view
+import android.annotation.AttrRes
import android.annotation.ColorInt
import android.app.Dialog
import android.content.Context
@@ -31,6 +32,7 @@
import android.widget.LinearLayout
import android.widget.LinearLayout.LayoutParams
import android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
+import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.util.children
@@ -38,7 +40,7 @@
context: Context,
initialCurrentLevel: Int,
initialMaxLevel: Int,
-) : Dialog(context) {
+) : Dialog(context, R.style.Theme_SystemUI_Dialog) {
private data class RootProperties(
val cornerRadius: Float,
@@ -69,9 +71,14 @@
private lateinit var rootProperties: RootProperties
private lateinit var iconProperties: BacklightIconProperties
private lateinit var stepProperties: StepViewProperties
- @ColorInt var filledRectangleColor: Int = 0
- @ColorInt var emptyRectangleColor: Int = 0
- @ColorInt var backgroundColor: Int = 0
+ @ColorInt
+ var filledRectangleColor = getColorFromStyle(com.android.internal.R.attr.materialColorPrimary)
+ @ColorInt
+ var emptyRectangleColor =
+ getColorFromStyle(com.android.internal.R.attr.materialColorOutlineVariant)
+ @ColorInt
+ var backgroundColor = getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceBright)
+ @ColorInt var iconColor = getColorFromStyle(com.android.internal.R.attr.materialColorOnPrimary)
init {
currentLevel = initialCurrentLevel
@@ -90,9 +97,6 @@
private fun updateResources() {
context.resources.apply {
- filledRectangleColor = getColor(R.color.backlight_indicator_step_filled, context.theme)
- emptyRectangleColor = getColor(R.color.backlight_indicator_step_empty, context.theme)
- backgroundColor = getColor(R.color.backlight_indicator_background, context.theme)
rootProperties =
RootProperties(
cornerRadius =
@@ -126,6 +130,11 @@
}
}
+ @ColorInt
+ fun getColorFromStyle(@AttrRes colorId: Int): Int {
+ return Utils.getColorAttrDefaultColor(context, colorId)
+ }
+
fun updateState(current: Int, max: Int, forceRefresh: Boolean = false) {
if (maxLevel != max || forceRefresh) {
maxLevel = max
@@ -159,6 +168,7 @@
private fun buildRootView(): LinearLayout {
val linearLayout =
LinearLayout(context).apply {
+ id = R.id.keyboard_backlight_dialog_container
orientation = LinearLayout.HORIZONTAL
layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
setPadding(
@@ -214,6 +224,7 @@
private fun createBacklightIconView(): ImageView {
return ImageView(context).apply {
setImageResource(R.drawable.ic_keyboard_backlight)
+ setColorFilter(iconColor)
layoutParams =
FrameLayout.LayoutParams(iconProperties.width, iconProperties.height).apply {
gravity = Gravity.CENTER
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 2925d8d..9844ca0 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.systemui.animation.Interpolators
+import com.android.app.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 1a126d7..2854de0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -98,6 +98,7 @@
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;
@@ -121,7 +122,6 @@
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/data/repository/KeyguardFaceAuthModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt
index ef8b401..ee0eb2d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt
@@ -46,8 +46,6 @@
impl: SystemUIKeyguardFaceAuthInteractor
): KeyguardFaceAuthInteractor
- @Binds fun trustRepository(impl: TrustRepositoryImpl): TrustRepository
-
companion object {
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index f27f899..e7b9af6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -45,4 +45,6 @@
@Binds
fun keyguardBouncerRepository(impl: KeyguardBouncerRepositoryImpl): KeyguardBouncerRepository
+
+ @Binds fun trustRepository(impl: TrustRepositoryImpl): TrustRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
index d90f328..74c5520 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
@@ -28,7 +28,9 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
@@ -40,6 +42,9 @@
interface TrustRepository {
/** Flow representing whether the current user is trusted. */
val isCurrentUserTrusted: Flow<Boolean>
+
+ /** Flow representing whether active unlock is available for the current user. */
+ val isCurrentUserActiveUnlockAvailable: StateFlow<Boolean>
}
@SysUISingleton
@@ -89,11 +94,13 @@
}
.shareIn(applicationScope, started = SharingStarted.Eagerly, replay = 1)
- override val isCurrentUserTrusted: Flow<Boolean>
- get() =
- combine(trust, userRepository.selectedUserInfo, ::Pair)
- .map { latestTrustModelForUser[it.second.id]?.isTrusted ?: false }
- .distinctUntilChanged()
- .onEach { logger.isCurrentUserTrusted(it) }
- .onStart { emit(false) }
+ override val isCurrentUserTrusted: Flow<Boolean> =
+ combine(trust, userRepository.selectedUserInfo, ::Pair)
+ .map { latestTrustModelForUser[it.second.id]?.isTrusted ?: false }
+ .distinctUntilChanged()
+ .onEach { logger.isCurrentUserTrusted(it) }
+ .onStart { emit(false) }
+
+ // TODO: Implement based on TrustManager callback b/267322286
+ override val isCurrentUserActiveUnlockAvailable: StateFlow<Boolean> = MutableStateFlow(true)
}
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 e6568f2..cde67f9 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.systemui.animation.Interpolators
+import com.android.app.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 c2d139c..7e9cbc1 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.systemui.animation.Interpolators
+import com.android.app.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 86f65dde..aca4019 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.systemui.animation.Interpolators
+import com.android.app.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 3beac0b..fc7bfb4 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.systemui.animation.Interpolators
+import com.android.app.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 b5bcd45..39c630b 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.systemui.animation.Interpolators
+import com.android.app.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 87f3164..0505d37 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.systemui.animation.Interpolators
+import com.android.app.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 c0d5abc..47846d1 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.systemui.animation.Interpolators
+import com.android.app.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 a681c43..bc55bd4 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/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
index 970d004..110bcd7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
@@ -32,14 +32,16 @@
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.BouncerView
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
+import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.shared.system.SysUiStatsLog
-import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.KeyguardStateController
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -56,28 +58,21 @@
class PrimaryBouncerInteractor
@Inject
constructor(
- private val repository: KeyguardBouncerRepository,
- private val primaryBouncerView: BouncerView,
- @Main private val mainHandler: Handler,
- private val keyguardStateController: KeyguardStateController,
- private val keyguardSecurityModel: KeyguardSecurityModel,
- private val primaryBouncerCallbackInteractor: PrimaryBouncerCallbackInteractor,
- private val falsingCollector: FalsingCollector,
- private val dismissCallbackRegistry: DismissCallbackRegistry,
- private val context: Context,
- private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
- keyguardBypassController: KeyguardBypassController,
+ private val repository: KeyguardBouncerRepository,
+ private val primaryBouncerView: BouncerView,
+ @Main private val mainHandler: Handler,
+ private val keyguardStateController: KeyguardStateController,
+ private val keyguardSecurityModel: KeyguardSecurityModel,
+ private val primaryBouncerCallbackInteractor: PrimaryBouncerCallbackInteractor,
+ private val falsingCollector: FalsingCollector,
+ private val dismissCallbackRegistry: DismissCallbackRegistry,
+ private val context: Context,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val trustRepository: TrustRepository,
+ private val featureFlags: FeatureFlags,
) {
- /** Whether we want to wait for face auth. */
- private val primaryBouncerFaceDelay =
- keyguardStateController.isFaceAuthEnabled &&
- !keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
- KeyguardUpdateMonitor.getCurrentUser()
- ) &&
- !needsFullscreenBouncer() &&
- keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE) &&
- !keyguardBypassController.bypassEnabled
-
+ private val passiveAuthBouncerDelay = context.resources.getInteger(
+ R.integer.primary_bouncer_passive_auth_delay).toLong()
/** Runnable to show the primary bouncer. */
val showRunnable = Runnable {
repository.setPrimaryShow(true)
@@ -160,8 +155,9 @@
}
repository.setPrimaryShowingSoon(true)
- if (primaryBouncerFaceDelay) {
- mainHandler.postDelayed(showRunnable, 1200L)
+ if (usePrimaryBouncerPassiveAuthDelay()) {
+ Log.d(TAG, "delay bouncer, passive auth may succeed")
+ mainHandler.postDelayed(showRunnable, passiveAuthBouncerDelay)
} else {
DejankUtils.postAfterTraversal(showRunnable)
}
@@ -377,6 +373,17 @@
return repository.primaryBouncerShow.value
}
+ /** Whether we want to wait to show the bouncer in case passive auth succeeds. */
+ private fun usePrimaryBouncerPassiveAuthDelay(): Boolean {
+ val canRunFaceAuth = keyguardStateController.isFaceAuthEnabled &&
+ keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE)
+ val canRunActiveUnlock = trustRepository.isCurrentUserActiveUnlockAvailable.value &&
+ keyguardUpdateMonitor.canTriggerActiveUnlockBasedOnDeviceState()
+ return featureFlags.isEnabled(Flags.DELAY_BOUNCER) &&
+ !needsFullscreenBouncer() &&
+ (canRunFaceAuth || canRunActiveUnlock)
+ }
+
companion object {
private const val TAG = "PrimaryBouncerInteractor"
}
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 38b9d50..9d7477c 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.systemui.animation.Interpolators.LINEAR
+import com.android.app.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 d96609c..c8d37a1 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 8d6545a4..2c9a9b3 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.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
-import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.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 f16827d..c135786 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.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.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 bc9dc4f..c6187dd 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.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.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 a60665a..d3ea89c 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.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.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 ddce516..6845c55 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.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.app.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 df93d23..68810f9 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.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.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/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index aec7b5f..c41f82b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -111,7 +111,7 @@
if (featureFlags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES)) {
component.emptyStateProvider
} else {
- super.createBlockerEmptyStateProvider()
+ object : EmptyStateProvider {}
}
override fun createListController(userHandle: UserHandle): ResolverListController =
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index 28adfbb..c9c2ea2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -79,6 +79,9 @@
// Indicates if user must review already-granted consent that the MediaProjection app is
// attempting to re-use.
private boolean mReviewGrantedConsentRequired = false;
+ // Indicates if the user has consented to record, but is continuing in another activity to
+ // select a particular task to capture.
+ private boolean mUserSelectingTask = false;
@Inject
public MediaProjectionPermissionActivity(FeatureFlags featureFlags,
@@ -296,6 +299,7 @@
// Start activity from the current foreground user to avoid creating a separate
// SystemUI process without access to recent tasks because it won't have
// WM Shell running inside.
+ mUserSelectingTask = true;
startActivityAsUser(intent, UserHandle.of(ActivityManager.getCurrentUser()));
}
} catch (RemoteException e) {
@@ -316,7 +320,10 @@
@Override
public void finish() {
// Default to cancelling recording when user needs to review consent.
- finish(RECORD_CANCEL, /* projection= */ null);
+ // Don't send cancel if the user has moved on to the next activity.
+ if (!mUserSelectingTask) {
+ finish(RECORD_CANCEL, /* projection= */ null);
+ }
}
private void finish(@ReviewGrantedConsentResult int consentResult,
@@ -328,7 +335,7 @@
private void onDialogDismissedOrCancelled(DialogInterface dialogInterface) {
if (!isFinishing()) {
- finish(RECORD_CANCEL, /* projection= */ null);
+ finish();
}
}
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 37d956b..e38abc2 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 3669493..b46ebb2 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 dd5c2bf..937a618 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 40027a1..f9d3094 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,6 +72,7 @@
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;
@@ -82,7 +83,6 @@
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 49e1665..fe8ebaf 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 e9b2cf2..583c626 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 78082c3..77ff036 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.systemui.animation.Interpolators
+import com.android.app.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/mediaprojection/appselector/MediaProjectionAppSelectorController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
index 219629b..1d8fe72 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
@@ -19,7 +19,6 @@
import android.content.ComponentName
import android.os.UserHandle
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.mediaprojection.appselector.data.RecentTask
import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
import javax.inject.Inject
@@ -59,13 +58,7 @@
* Removes all recent tasks that are different from the profile of the host app to avoid any
* cross-profile sharing
*/
- private fun List<RecentTask>.filterDevicePolicyRestrictedTasks(): List<RecentTask> =
- if (flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES)) {
- // TODO(b/263950746): filter tasks based on the enterprise policies
- this
- } else {
- filter { UserHandle.of(it.userId) == hostUserHandle }
- }
+ private fun List<RecentTask>.filterDevicePolicyRestrictedTasks(): List<RecentTask> = this
private fun List<RecentTask>.filterAppSelector(): List<RecentTask> = filter {
// Only take tasks that is not the app selector
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 94f01b8..146b5f5 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 0218016..10084bd 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.systemui.animation.Interpolators.LINEAR;
+import static com.android.app.animation.Interpolators.LINEAR;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -24,9 +24,6 @@
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 590efbb..ff22398 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 a7aac5a..463c79c 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.systemui.animation.Interpolators;
+import com.android.app.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/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index 0d29a1a..85f557b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -27,6 +27,7 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qs.dagger.QSScope;
+import com.android.systemui.retail.domain.interactor.RetailModeInteractor;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.ViewController;
@@ -45,18 +46,22 @@
private final View mEditButton;
private final FalsingManager mFalsingManager;
private final ActivityStarter mActivityStarter;
+ private final RetailModeInteractor mRetailModeInteractor;
@Inject
QSFooterViewController(QSFooterView view,
UserTracker userTracker,
FalsingManager falsingManager,
ActivityStarter activityStarter,
- QSPanelController qsPanelController) {
+ QSPanelController qsPanelController,
+ RetailModeInteractor retailModeInteractor
+ ) {
super(view);
mUserTracker = userTracker;
mQsPanelController = qsPanelController;
mFalsingManager = falsingManager;
mActivityStarter = activityStarter;
+ mRetailModeInteractor = retailModeInteractor;
mBuildText = mView.findViewById(R.id.build);
mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
@@ -96,6 +101,8 @@
@Override
public void setVisibility(int visibility) {
mView.setVisibility(visibility);
+ mEditButton
+ .setVisibility(mRetailModeInteractor.isInRetailMode() ? View.GONE : View.VISIBLE);
mEditButton.setClickable(visibility == View.VISIBLE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index fd3f701..b8c2fad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -44,10 +44,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;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt
index 595b29a9..3b2362f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt
@@ -20,6 +20,7 @@
import android.content.res.Resources
import android.database.ContentObserver
import android.provider.Settings
+import com.android.systemui.R
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -27,12 +28,16 @@
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
+import com.android.systemui.retail.data.repository.RetailModeRepository
import com.android.systemui.util.settings.SecureSettings
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -84,6 +89,9 @@
* [Settings.Secure.QS_TILES].
*
* All operations against [Settings] will be performed in a background thread.
+ *
+ * If the device is in retail mode, the tiles are fixed to the value of
+ * [R.string.quick_settings_tiles_retail_mode].
*/
@SysUISingleton
class TileSpecSettingsRepository
@@ -92,9 +100,31 @@
private val secureSettings: SecureSettings,
@Main private val resources: Resources,
private val logger: QSPipelineLogger,
+ private val retailModeRepository: RetailModeRepository,
@Background private val backgroundDispatcher: CoroutineDispatcher,
) : TileSpecRepository {
+
+ private val retailModeTiles by lazy {
+ resources
+ .getString(R.string.quick_settings_tiles_retail_mode)
+ .split(DELIMITER)
+ .map(TileSpec::create)
+ .filter { it !is TileSpec.Invalid }
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
override fun tilesSpecs(userId: Int): Flow<List<TileSpec>> {
+ return retailModeRepository.retailMode.flatMapLatest { inRetailMode ->
+ if (inRetailMode) {
+ logger.logUsingRetailTiles()
+ flowOf(retailModeTiles)
+ } else {
+ settingsTiles(userId)
+ }
+ }
+ }
+
+ private fun settingsTiles(userId: Int): Flow<List<TileSpec>> {
return conflatedCallbackFlow {
val observer =
object : ContentObserver(null) {
@@ -157,6 +187,10 @@
}
private suspend fun storeTiles(@UserIdInt forUser: Int, tiles: List<TileSpec>) {
+ if (retailModeRepository.inRetailMode) {
+ // No storing tiles when in retail mode
+ return
+ }
val toStore =
tiles
.filter { it !is TileSpec.Invalid }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
index b564334..ff7d206 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
@@ -120,6 +120,10 @@
)
}
+ fun logUsingRetailTiles() {
+ tileListLogBuffer.log(TILE_LIST_TAG, LogLevel.DEBUG, {}, { "Using retail tiles" })
+ }
+
/** Reasons for destroying an existing tile. */
enum class TileDestroyedReason(val readable: String) {
TILE_REMOVED("Tile removed from current set"),
diff --git a/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt b/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt
new file mode 100644
index 0000000..e863949
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.retail.dagger
+
+import com.android.systemui.retail.data.repository.RetailModeRepository
+import com.android.systemui.retail.data.repository.RetailModeSettingsRepository
+import com.android.systemui.retail.domain.interactor.RetailModeInteractor
+import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl
+import dagger.Binds
+import dagger.Module
+
+@Module
+abstract class RetailModeModule {
+
+ @Binds
+ abstract fun bindsRetailModeRepository(impl: RetailModeSettingsRepository): RetailModeRepository
+
+ @Binds
+ abstract fun bindsRetailModeInteractor(impl: RetailModeInteractorImpl): RetailModeInteractor
+}
diff --git a/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt b/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt
new file mode 100644
index 0000000..3c0aa38
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.retail.data.repository
+
+import android.database.ContentObserver
+import android.provider.Settings
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.settings.GlobalSettings
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+
+/** Repository to track if the device is in Retail mode */
+interface RetailModeRepository {
+ /** Flow of whether the device is currently in retail mode. */
+ val retailMode: StateFlow<Boolean>
+
+ /** Last value of whether the device is in retail mode. */
+ val inRetailMode: Boolean
+ get() = retailMode.value
+}
+
+/**
+ * Tracks [Settings.Global.DEVICE_DEMO_MODE].
+ *
+ * @see UserManager.isDeviceInDemoMode
+ */
+@SysUISingleton
+class RetailModeSettingsRepository
+@Inject
+constructor(
+ globalSettings: GlobalSettings,
+ @Background backgroundDispatcher: CoroutineDispatcher,
+ @Application scope: CoroutineScope,
+) : RetailModeRepository {
+ override val retailMode =
+ conflatedCallbackFlow {
+ val observer =
+ object : ContentObserver(null) {
+ override fun onChange(selfChange: Boolean) {
+ trySend(Unit)
+ }
+ }
+
+ globalSettings.registerContentObserver(RETAIL_MODE_SETTING, observer)
+
+ awaitClose { globalSettings.unregisterContentObserver(observer) }
+ }
+ .onStart { emit(Unit) }
+ .map { globalSettings.getInt(RETAIL_MODE_SETTING, 0) != 0 }
+ .flowOn(backgroundDispatcher)
+ .stateIn(scope, SharingStarted.Eagerly, false)
+
+ companion object {
+ private const val RETAIL_MODE_SETTING = Settings.Global.DEVICE_DEMO_MODE
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
new file mode 100644
index 0000000..eea452c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.retail.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.retail.data.repository.RetailModeRepository
+import javax.inject.Inject
+
+/** Interactor to determine if the device is currently in retail mode */
+interface RetailModeInteractor {
+ /** Whether the device is currently in retail mode */
+ val isInRetailMode: Boolean
+}
+
+@SysUISingleton
+class RetailModeInteractorImpl
+@Inject
+constructor(
+ private val repository: RetailModeRepository,
+) : RetailModeInteractor {
+ override val isInRetailMode: Boolean
+ get() = repository.inRetailMode
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 137a99ef..926ede9 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,6 +88,7 @@
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;
@@ -111,7 +112,6 @@
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;
@@ -1513,6 +1513,8 @@
mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
mKeyguardStatusViewController.isClockTopAligned());
mClockPositionAlgorithm.run(mClockPositionResult);
+ mKeyguardStatusViewController.setLockscreenClockY(
+ mClockPositionAlgorithm.getExpandedPreferredClockY());
mKeyguardBottomAreaInteractor.setClockPosition(
mClockPositionResult.clockX, mClockPositionResult.clockY);
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index fb7c5c2..31b361f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -18,7 +18,6 @@
import android.view.View
import android.view.ViewGroup
-import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.WindowInsets
import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.widget.ConstraintSet
@@ -62,6 +61,7 @@
private var isQSCustomizing = false
private var isQSCustomizerAnimating = false
+ private var shadeHeaderHeight = 0
private var largeScreenShadeHeaderHeight = 0
private var largeScreenShadeHeaderActive = false
private var notificationsBottomMargin = 0
@@ -146,6 +146,8 @@
R.dimen.notification_panel_margin_bottom)
largeScreenShadeHeaderHeight =
resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height)
+ shadeHeaderHeight =
+ resources.getDimensionPixelSize(R.dimen.qs_header_height)
panelMarginHorizontal = resources.getDimensionPixelSize(
R.dimen.notification_panel_margin_horizontal)
topMargin = if (largeScreenShadeHeaderActive) {
@@ -245,7 +247,7 @@
if (largeScreenShadeHeaderActive) {
constraintSet.constrainHeight(R.id.split_shade_status_bar, largeScreenShadeHeaderHeight)
} else {
- constraintSet.constrainHeight(R.id.split_shade_status_bar, WRAP_CONTENT)
+ constraintSet.constrainHeight(R.id.split_shade_status_bar, shadeHeaderHeight)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index a1fa8fbf..abdd1a9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -50,6 +50,7 @@
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;
@@ -59,7 +60,6 @@
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 86ae4ec..f080d3d 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 63179da..c1ebf12 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 54b341f..1a32d70 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/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 9421524..823bb35 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.systemui.animation.Interpolators
+import com.android.app.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 7f016f3..b61f243 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.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.biometrics.UdfpsKeyguardViewController
import com.android.systemui.classifier.Classifier
import com.android.systemui.classifier.FalsingCollector
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 72ae16e..fb88a96 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 a3bd247..0e20df6 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.systemui.animation.Interpolators
+import com.android.app.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 49c7950..9d7f3be 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 821a172..fc6eaa8 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.systemui.animation.Interpolators
+import com.android.app.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 575f354..f1e51e2 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.systemui.animation.Interpolators
+import com.android.app.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 572c0e0..3d574ca 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.systemui.animation.Interpolators
+import com.android.app.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 7755003..91c08a0 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 79d01b4a..d6a14604 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -42,6 +42,7 @@
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;
@@ -49,7 +50,6 @@
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 2fa27ee..67ab060 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 bfc4e9c..eddb683 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.systemui.animation.Interpolators
+import com.android.app.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 0446165..b09b9f4 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 c22dbf6..785e65d 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.systemui.animation.Interpolators
+import com.android.app.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 c22cd1b..5a14200 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 3fc7b13..a045698 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 fe0b28d..9ba2199 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.systemui.animation.Interpolators
-import com.android.systemui.animation.InterpolatorsAndroidX
+import com.android.app.animation.Interpolators
+import com.android.app.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 5d07cac..57d20246 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.systemui.animation.Interpolators;
+import com.android.app.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 9f9fba4..90eb630 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 dc16274..16f1a45 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.systemui.animation.Interpolators
+import com.android.app.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 285dd97..8af488e 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 1dc58b5..ba8a5f3 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,6 +64,7 @@
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;
@@ -72,7 +73,6 @@
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 b56bae1..7a2bee9 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 3e01dd3..f0e15c2 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/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 4522e41..b4bfded 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -966,7 +966,7 @@
@Override
public ApplicationInfo getApplicationInfo() {
- ApplicationInfo applicationInfo = super.getApplicationInfo();
+ ApplicationInfo applicationInfo = new ApplicationInfo(super.getApplicationInfo());
applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL;
return applicationInfo;
}
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 f21db0b..9bc0333 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.systemui.animation.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.app.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 596bdc0..047db20 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/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 8a50f2f..99a7755 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.systemui.animation.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.app.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 bafc474..5a129fc 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 5f4c926..d5d7f75 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 5aaf63f..b24cec1 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 2c59c2e..ef5e86f06 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 7f3381c..d73bbeb 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 0b435fe..9a33a94 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.systemui.animation.Interpolators;
+import com.android.app.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 edff877..cf051fb 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,6 +75,7 @@
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;
@@ -86,7 +87,6 @@
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;
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 ee72943..f07dd00 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 d07da38..f4605be 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/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 9dce332..4590712 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/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 90a6d0f..561bd91 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;
@@ -239,7 +239,11 @@
}
}
- private int getExpandedPreferredClockY() {
+ /**
+ * give the static topMargin, used for lockscreen clocks to get the initial translationY
+ * to do counter translation
+ */
+ public int getExpandedPreferredClockY() {
if (mIsSplitShade) {
return mSplitShadeTargetTopMargin;
} else {
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 9d30cb4..61c1cc8 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 13566ef..720eeba 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 12ed71b..4d716c2 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.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 6bf5443..7bc4fc3 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 cc4f901..46a2457 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 55dc188..560ea8a 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 006a029d..bef422c 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 5e5317d7..07a6d0a 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.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
public class SettingsButton extends AlphaOptimizedImageView {
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 8fa803e..cdf6652 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.systemui.animation.Interpolators
+import com.android.app.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 620d282..5af8932 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
@@ -40,10 +40,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 4dd63be..e1ec94f 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 928e011..66b5256 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -31,6 +31,7 @@
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;
@@ -38,7 +39,6 @@
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 850a4b4..363b06a 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 403a7e8..e311bad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -73,6 +73,7 @@
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;
@@ -80,7 +81,6 @@
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/statusbar/policy/SmartReplyStateInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
index b563d86..21d0338 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
@@ -311,7 +311,7 @@
setBounds(0, 0, newIconSize, newIconSize)
}
// Add the action icon to the Smart Action button.
- setCompoundDrawables(iconDrawable, null, null, null)
+ setCompoundDrawablesRelative(iconDrawable, null, null, null)
val onClickListener = View.OnClickListener {
onSmartActionClick(entry, smartActions, actionIndex, action)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 9e88ceb..fb6ba85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -588,15 +588,15 @@
}
/**
- * Returns the combined width of the left drawable (the action icon) and the padding between the
- * drawable and the button text.
+ * Returns the combined width of the start drawable (the action icon) and the padding between
+ * the drawable and the button text.
*/
- private int getLeftCompoundDrawableWidthWithPadding(Button button) {
- Drawable[] drawables = button.getCompoundDrawables();
- Drawable leftDrawable = drawables[0];
- if (leftDrawable == null) return 0;
+ private int getStartCompoundDrawableWidthWithPadding(Button button) {
+ Drawable[] drawables = button.getCompoundDrawablesRelative();
+ Drawable startDrawable = drawables[0];
+ if (startDrawable == null) return 0;
- return leftDrawable.getBounds().width() + button.getCompoundDrawablePadding();
+ return startDrawable.getBounds().width() + button.getCompoundDrawablePadding();
}
private int squeezeButtonToTextWidth(Button button, int heightMeasureSpec, int textWidth) {
@@ -605,8 +605,8 @@
// Re-measure the squeezed smart reply button.
clearLayoutLineCount(button);
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
- button.getPaddingLeft() + button.getPaddingRight() + textWidth
- + getLeftCompoundDrawableWidthWithPadding(button), MeasureSpec.AT_MOST);
+ button.getPaddingStart() + button.getPaddingEnd() + textWidth
+ + getStartCompoundDrawableWidthWithPadding(button), MeasureSpec.AT_MOST);
button.measure(widthMeasureSpec, heightMeasureSpec);
if (button.getLayout() == null) {
Log.wtf(TAG, "Button layout is null after measure.");
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 1612388..46954b5 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.systemui.animation.Interpolators
+import com.android.app.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 e819f94..4fbbc89 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/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
index f0fa779..58f2246 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
+++ b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
@@ -51,6 +51,7 @@
Pair.create("surface_variant", MDC.surfaceVariant()),
Pair.create("on_surface_variant", MDC.onSurfaceVariant()),
Pair.create("outline", MDC.outline()),
+ Pair.create("outline_variant", MDC.outlineVariant()),
Pair.create("error", MDC.error()),
Pair.create("on_error", MDC.onError()),
Pair.create("error_container", MDC.errorContainer()),
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 43d15bc..4b73d61 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -659,6 +659,10 @@
== mColorScheme.getNeutral1().getS500()
&& res.getColor(android.R.color.system_neutral2_500, theme)
== mColorScheme.getNeutral2().getS500()
+ && res.getColor(android.R.color.system_outline_variant_dark, theme)
+ == MaterialDynamicColors.outlineVariant().getArgb(mDynamicSchemeDark)
+ && res.getColor(android.R.color.system_outline_variant_light, theme)
+ == MaterialDynamicColors.outlineVariant().getArgb(mDynamicSchemeLight)
&& res.getColor(android.R.color.system_primary_container_dark, theme)
== MaterialDynamicColors.primaryContainer().getArgb(mDynamicSchemeDark)
&& res.getColor(android.R.color.system_primary_container_light, theme)
diff --git a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
index eb23b9d..d940a6b 100644
--- a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
+++ b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
@@ -16,8 +16,6 @@
syntax = "proto2";
-import "frameworks/base/libs/WindowManager/Shell/proto/wm_shell_trace.proto";
-
package com.android.systemui.tracing;
option java_multiple_files = true;
@@ -25,7 +23,6 @@
message SystemUiTraceProto {
optional EdgeBackGestureHandlerProto edge_back_gesture_handler = 1;
- optional com.android.wm.shell.WmShellTraceProto wm_shell = 2;
}
message EdgeBackGestureHandlerProto {
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 5d80292..db4ab7ed 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.systemui.animation.Interpolators
+import com.android.app.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 77210b7..91078dc 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -109,6 +109,7 @@
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;
@@ -119,7 +120,6 @@
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/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index e60f9b6..5144d19 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -362,9 +362,6 @@
@Override
public void writeToProto(SystemUiTraceProto proto) {
- if (proto.wmShell == null) {
- proto.wmShell = new WmShellTraceProto();
- }
// Dump to WMShell proto here
// TODO: Figure out how we want to synchronize while dumping to proto
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt
deleted file mode 100644
index 2c680be..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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 6ab54a3..da9ceb4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
@@ -19,6 +19,7 @@
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/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 6e37ee7..a361bbc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -68,7 +68,6 @@
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
-@Ignore("b/279650412")
@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
@@ -281,6 +280,7 @@
assertThat(authContainer!!.parent).isNull()
}
+ @Ignore("b/279650412")
@Test
fun testActionUseDeviceCredential_sendsOnDeviceCredentialPressed() {
val container = initializeFingerprintContainer(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
index 8bf32cf..8f6017c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
@@ -21,22 +21,23 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardSecurityModel
+import com.android.systemui.RoboPilotTest
import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.BouncerView
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepositoryImpl
+import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.RoboPilotTest
import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.time.SystemClock
@@ -94,7 +95,8 @@
mock(DismissCallbackRegistry::class.java),
context,
mKeyguardUpdateMonitor,
- mock(KeyguardBypassController::class.java),
+ mock(TrustRepository::class.java),
+ FakeFeatureFlags(),
)
mAlternateBouncerInteractor =
AlternateBouncerInteractor(
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 d0bfaa9..5afc405 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,8 +23,8 @@
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.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/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index 5da1a84..e261982 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -35,12 +35,12 @@
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -100,7 +100,8 @@
mock(DismissCallbackRegistry::class.java),
context,
keyguardUpdateMonitor,
- mock(KeyguardBypassController::class.java),
+ mock(TrustRepository::class.java),
+ FakeFeatureFlags(),
),
AlternateBouncerInteractor(
mock(StatusBarStateController::class.java),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
index 24a47b0..eed1e739 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.domain.interactor
-import android.os.Looper
+import android.hardware.biometrics.BiometricSourceType
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.testing.TestableResources
@@ -28,15 +28,17 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.BouncerView
import com.android.systemui.keyguard.data.BouncerViewDelegate
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
@@ -67,16 +69,23 @@
@Mock private lateinit var mPrimaryBouncerCallbackInteractor: PrimaryBouncerCallbackInteractor
@Mock private lateinit var falsingCollector: FalsingCollector
@Mock private lateinit var dismissCallbackRegistry: DismissCallbackRegistry
- @Mock private lateinit var keyguardBypassController: KeyguardBypassController
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
- private val mainHandler = FakeHandler(Looper.getMainLooper())
+ private lateinit var mainHandler: FakeHandler
private lateinit var underTest: PrimaryBouncerInteractor
private lateinit var resources: TestableResources
+ private lateinit var trustRepository: FakeTrustRepository
+ private lateinit var featureFlags: FakeFeatureFlags
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ whenever(keyguardSecurityModel.getSecurityMode(anyInt()))
+ .thenReturn(KeyguardSecurityModel.SecurityMode.PIN)
+
DejankUtils.setImmediate(true)
+ mainHandler = FakeHandler(android.os.Looper.getMainLooper())
+ trustRepository = FakeTrustRepository()
+ featureFlags = FakeFeatureFlags().apply { set(Flags.DELAY_BOUNCER, false) }
underTest =
PrimaryBouncerInteractor(
repository,
@@ -89,7 +98,8 @@
dismissCallbackRegistry,
context,
keyguardUpdateMonitor,
- keyguardBypassController,
+ trustRepository,
+ featureFlags,
)
whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
whenever(repository.primaryBouncerShow.value).thenReturn(false)
@@ -383,6 +393,55 @@
verify(repository).setSideFpsShowing(false)
}
+ @Test
+ fun delayBouncerWhenFaceAuthPossible() {
+ mainHandler.setMode(FakeHandler.Mode.QUEUEING)
+
+ // GIVEN bouncer should be delayed due to face auth
+ featureFlags.apply { set(Flags.DELAY_BOUNCER, true) }
+ whenever(keyguardStateController.isFaceAuthEnabled).thenReturn(true)
+ whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
+ .thenReturn(true)
+
+ // WHEN bouncer show is requested
+ underTest.show(true)
+
+ // THEN primary show & primary showing soon aren't updated immediately
+ verify(repository, never()).setPrimaryShow(true)
+ verify(repository, never()).setPrimaryShowingSoon(false)
+
+ // WHEN all queued messages are dispatched
+ mainHandler.dispatchQueuedMessages()
+
+ // THEN primary show & primary showing soon are updated
+ verify(repository).setPrimaryShow(true)
+ verify(repository).setPrimaryShowingSoon(false)
+ }
+
+ @Test
+ fun delayBouncerWhenActiveUnlockPossible() {
+ mainHandler.setMode(FakeHandler.Mode.QUEUEING)
+
+ // GIVEN bouncer should be delayed due to active unlock
+ featureFlags.apply { set(Flags.DELAY_BOUNCER, true) }
+ trustRepository.setCurrentUserActiveUnlockAvailable(true)
+ whenever(keyguardUpdateMonitor.canTriggerActiveUnlockBasedOnDeviceState()).thenReturn(true)
+
+ // WHEN bouncer show is requested
+ underTest.show(true)
+
+ // THEN primary show & primary showing soon were scheduled to update
+ verify(repository, never()).setPrimaryShow(true)
+ verify(repository, never()).setPrimaryShowingSoon(false)
+
+ // WHEN all queued messages are dispatched
+ mainHandler.dispatchQueuedMessages()
+
+ // THEN primary show & primary showing soon are updated
+ verify(repository).setPrimaryShow(true)
+ verify(repository).setPrimaryShowingSoon(false)
+ }
+
private fun updateSideFpsVisibilityParameters(
isVisible: Boolean,
sfpsEnabled: Boolean,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
index e35e971..5056b43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
@@ -25,9 +25,11 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.BouncerView
import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.utils.os.FakeHandler
@@ -37,6 +39,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito
import org.mockito.MockitoAnnotations
@SmallTest
@@ -71,7 +74,8 @@
dismissCallbackRegistry,
context,
keyguardUpdateMonitor,
- keyguardBypassController,
+ Mockito.mock(TrustRepository::class.java),
+ FakeFeatureFlags(),
)
}
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 a5b78b74..3efe382 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/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
index 0e9c99e..e9f1ac1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
@@ -24,9 +24,11 @@
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.BouncerView
import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
@@ -42,6 +44,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito
import org.mockito.MockitoAnnotations
@SmallTest
@@ -77,7 +80,8 @@
dismissCallbackRegistry,
context,
keyguardUpdateMonitor,
- keyguardBypassController,
+ Mockito.mock(TrustRepository::class.java),
+ FakeFeatureFlags(),
)
underTest = KeyguardBouncerViewModel(bouncerView, bouncerInteractor)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
index 4977775..f1bbd84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
@@ -132,7 +132,7 @@
}
@Test
- fun initRecentTasksWithAppSelectorTasks_enterprisePoliciesDisabled_bindsOnlyTasksWithHostProfile() {
+ fun initRecentTasksWithAppSelectorTasks_enterprisePoliciesDisabled_bindsAllTasks() {
givenEnterprisePoliciesFeatureFlag(enabled = false)
val tasks =
@@ -147,11 +147,15 @@
controller.init()
+ // TODO (b/263950746): Cross-profile filtering is removed for now. This should be brought
+ // back with the future fix
verify(view)
.bind(
listOf(
createRecentTask(taskId = 1, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 2, userId = otherUserHandle.identifier),
createRecentTask(taskId = 3, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 4, userId = otherUserHandle.identifier),
createRecentTask(taskId = 5, userId = hostUserHandle.identifier),
)
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index 26aa37d..d9db60d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -37,6 +37,8 @@
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.retail.data.repository.FakeRetailModeRepository;
+import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.utils.leaks.LeakCheckedTest;
@@ -67,6 +69,8 @@
@Mock
private ActivityStarter mActivityStarter;
+ private FakeRetailModeRepository mRetailModeRepository;
+
private QSFooterViewController mController;
private View mEditButton;
@@ -74,6 +78,9 @@
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
+ mRetailModeRepository = new FakeRetailModeRepository();
+ mRetailModeRepository.setRetailMode(false);
+
mEditButton = new View(mContext);
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
@@ -89,7 +96,8 @@
when(mView.findViewById(android.R.id.edit)).thenReturn(mEditButton);
mController = new QSFooterViewController(mView, mUserTracker, mFalsingManager,
- mActivityStarter, mQSPanelController);
+ mActivityStarter, mQSPanelController,
+ new RetailModeInteractorImpl(mRetailModeRepository));
mController.init();
}
@@ -132,4 +140,20 @@
captor.getValue().run();
verify(mQSPanelController).showEdit(mEditButton);
}
+
+ @Test
+ public void testEditButton_notRetailMode_visible() {
+ mRetailModeRepository.setRetailMode(false);
+
+ mController.setVisibility(View.VISIBLE);
+ assertThat(mEditButton.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void testEditButton_retailMode_notVisible() {
+ mRetailModeRepository.setRetailMode(true);
+
+ mController.setVisibility(View.VISIBLE);
+ assertThat(mEditButton.getVisibility()).isEqualTo(View.GONE);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
index 50a8d26..fda63ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
+import com.android.systemui.retail.data.repository.FakeRetailModeRepository
import com.android.systemui.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -44,6 +45,7 @@
class TileSpecSettingsRepositoryTest : SysuiTestCase() {
private lateinit var secureSettings: FakeSettings
+ private lateinit var retailModeRepository: FakeRetailModeRepository
@Mock private lateinit var logger: QSPipelineLogger
@@ -57,9 +59,12 @@
MockitoAnnotations.initMocks(this)
secureSettings = FakeSettings()
+ retailModeRepository = FakeRetailModeRepository()
+ retailModeRepository.setRetailMode(false)
with(context.orCreateTestableResources) {
addOverride(R.string.quick_settings_tiles_default, DEFAULT_TILES)
+ addOverride(R.string.quick_settings_tiles_retail_mode, RETAIL_TILES)
}
underTest =
@@ -67,6 +72,7 @@
secureSettings,
context.resources,
logger,
+ retailModeRepository,
testDispatcher,
)
}
@@ -346,6 +352,26 @@
assertThat(tiles).isEqualTo("b".toTileSpecs())
}
+ @Test
+ fun retailMode_usesRetailTiles() =
+ testScope.runTest {
+ retailModeRepository.setRetailMode(true)
+
+ val tiles by collectLastValue(underTest.tilesSpecs(0))
+
+ assertThat(tiles).isEqualTo(RETAIL_TILES.toTileSpecs())
+ }
+
+ @Test
+ fun retailMode_cannotModifyTiles() =
+ testScope.runTest {
+ retailModeRepository.setRetailMode(true)
+
+ underTest.setTiles(0, DEFAULT_TILES.toTileSpecs())
+
+ assertThat(loadTilesForUser(0)).isNull()
+ }
+
private fun getDefaultTileSpecs(): List<TileSpec> {
return QSHost.getDefaultSpecs(context.resources).map(TileSpec::create)
}
@@ -360,6 +386,7 @@
companion object {
private const val DEFAULT_TILES = "a,b,c"
+ private const val RETAIL_TILES = "d"
private const val SETTING = Settings.Secure.QS_TILES
private fun String.toTileSpecs(): List<TileSpec> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
new file mode 100644
index 0000000..d7682b2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.retail.data.repository
+
+import android.provider.Settings
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class RetailModeSettingsRepositoryTest : SysuiTestCase() {
+
+ private val globalSettings = FakeSettings()
+
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+
+ private val underTest =
+ RetailModeSettingsRepository(
+ globalSettings,
+ backgroundDispatcher = testDispatcher,
+ scope = testScope.backgroundScope,
+ )
+
+ @Test
+ fun retailMode_defaultFalse() =
+ testScope.runTest {
+ val value by collectLastValue(underTest.retailMode)
+
+ assertThat(value).isFalse()
+ assertThat(underTest.inRetailMode).isFalse()
+ }
+
+ @Test
+ fun retailMode_false() =
+ testScope.runTest {
+ val value by collectLastValue(underTest.retailMode)
+
+ globalSettings.putInt(SETTING, 0)
+
+ assertThat(value).isFalse()
+ assertThat(underTest.inRetailMode).isFalse()
+ }
+
+ @Test
+ fun retailMode_true() =
+ testScope.runTest {
+ val value by collectLastValue(underTest.retailMode)
+
+ globalSettings.putInt(SETTING, 1)
+
+ assertThat(value).isTrue()
+ assertThat(underTest.inRetailMode).isTrue()
+ }
+
+ companion object {
+ private const val SETTING = Settings.Global.DEVICE_DEMO_MODE
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
new file mode 100644
index 0000000..8f13169
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.retail.domain.interactor
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.retail.data.repository.FakeRetailModeRepository
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class RetailModeInteractorImplTest : SysuiTestCase() {
+
+ private val retailModeRepository = FakeRetailModeRepository()
+
+ private val underTest = RetailModeInteractorImpl(retailModeRepository)
+
+ @Test
+ fun retailMode_false() {
+ retailModeRepository.setRetailMode(false)
+
+ assertThat(underTest.isInRetailMode).isFalse()
+ }
+
+ @Test
+ fun retailMode_true() {
+ retailModeRepository.setRetailMode(true)
+
+ assertThat(underTest.isInRetailMode).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
index 31a33d4..cbd9dba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
@@ -30,6 +30,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assume.assumeFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -127,6 +128,9 @@
@Before
public void setUp() {
+ assumeFalse("Skip test: does not apply to watches",
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
+
MockitoAnnotations.initMocks(this);
mMainHandler = mContext.getMainThreadHandler();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt
new file mode 100644
index 0000000..d4751c8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.shade
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableResources
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.fragments.FragmentService
+import com.android.systemui.navigationbar.NavigationModeController
+import com.android.systemui.recents.OverviewProxyService
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
[email protected]
+@SmallTest
+class NotificationsQSContainerControllerTest : SysuiTestCase() {
+
+ @Mock lateinit var view: NotificationsQuickSettingsContainer
+ @Mock lateinit var navigationModeController: NavigationModeController
+ @Mock lateinit var overviewProxyService: OverviewProxyService
+ @Mock lateinit var shadeHeaderController: ShadeHeaderController
+ @Mock lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
+ @Mock lateinit var fragmentService: FragmentService
+
+ lateinit var underTest: NotificationsQSContainerController
+
+ private lateinit var fakeResources: TestableResources
+
+ private val delayableExecutor: DelayableExecutor = FakeExecutor(FakeSystemClock())
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ fakeResources = TestableResources(context.resources)
+
+ whenever(view.resources).thenReturn(fakeResources.resources)
+
+ underTest =
+ NotificationsQSContainerController(
+ view,
+ navigationModeController,
+ overviewProxyService,
+ shadeHeaderController,
+ shadeExpansionStateManager,
+ fragmentService,
+ delayableExecutor,
+ )
+ }
+
+ @Test
+ fun testSmallScreen_updateResources_splitShadeHeightIsSet() {
+ with(fakeResources) {
+ addOverride(R.bool.config_use_large_screen_shade_header, false)
+ addOverride(R.dimen.qs_header_height, 1)
+ addOverride(R.dimen.large_screen_shade_header_height, 2)
+ }
+
+ underTest.updateResources()
+
+ val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
+ verify(view).applyConstraints(capture(captor))
+ assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(1)
+ }
+
+ @Test
+ fun testLargeScreen_updateResources_splitShadeHeightIsSet() {
+ with(fakeResources) {
+ addOverride(R.bool.config_use_large_screen_shade_header, true)
+ addOverride(R.dimen.qs_header_height, 1)
+ addOverride(R.dimen.large_screen_shade_header_height, 2)
+ }
+
+ underTest.updateResources()
+
+ val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
+ verify(view).applyConstraints(capture(captor))
+ assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(2)
+ }
+}
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 9fe75ab..20da8a6 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/notification/PropertyAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
index a1168f8..f0abf2f 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/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index d9d8b63..3b0d512 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -585,8 +585,6 @@
// devices.
layout.setBaselineAligned(false);
- final boolean isRtl = mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-
// Add smart replies
Button previous = null;
SmartReplyView.SmartReplies smartReplies =
@@ -606,11 +604,7 @@
if (previous != null) {
ViewGroup.MarginLayoutParams lp =
(ViewGroup.MarginLayoutParams) previous.getLayoutParams();
- if (isRtl) {
- lp.leftMargin = mSpacing;
- } else {
- lp.rightMargin = mSpacing;
- }
+ lp.setMarginEnd(mSpacing);
}
layout.addView(current);
previous = current;
@@ -634,11 +628,7 @@
if (previous != null) {
ViewGroup.MarginLayoutParams lp =
(ViewGroup.MarginLayoutParams) previous.getLayoutParams();
- if (isRtl) {
- lp.leftMargin = mSpacing;
- } else {
- lp.rightMargin = mSpacing;
- }
+ lp.setMarginEnd(mSpacing);
}
layout.addView(current);
previous = current;
@@ -937,8 +927,8 @@
.collect(Collectors.toList());
Button singleLineButton = buttons.get(0);
Button doubleLineButton = buttons.get(1);
- Drawable singleLineDrawable = singleLineButton.getCompoundDrawables()[0]; // left drawable
- Drawable doubleLineDrawable = doubleLineButton.getCompoundDrawables()[0]; // left drawable
+ Drawable singleLineDrawable = singleLineButton.getCompoundDrawablesRelative()[0]; // start
+ Drawable doubleLineDrawable = doubleLineButton.getCompoundDrawablesRelative()[0]; // start
assertEquals(singleLineDrawable.getBounds().width(),
doubleLineDrawable.getBounds().width());
assertEquals(singleLineDrawable.getBounds().height(),
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 5b431e7..0983041 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,6 +14,8 @@
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/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
index 6690de8..f0dbc60 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
@@ -19,13 +19,23 @@
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
class FakeTrustRepository : TrustRepository {
private val _isCurrentUserTrusted = MutableStateFlow(false)
override val isCurrentUserTrusted: Flow<Boolean>
get() = _isCurrentUserTrusted
+ private val _isCurrentUserActiveUnlockAvailable = MutableStateFlow(false)
+ override val isCurrentUserActiveUnlockAvailable: StateFlow<Boolean> =
+ _isCurrentUserActiveUnlockAvailable.asStateFlow()
+
fun setCurrentUserTrusted(trust: Boolean) {
_isCurrentUserTrusted.value = trust
}
+
+ fun setCurrentUserActiveUnlockAvailable(available: Boolean) {
+ _isCurrentUserActiveUnlockAvailable.value = available
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/retail/data/repository/FakeRetailModeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/retail/data/repository/FakeRetailModeRepository.kt
new file mode 100644
index 0000000..75b29ca
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/retail/data/repository/FakeRetailModeRepository.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.retail.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeRetailModeRepository : RetailModeRepository {
+
+ private val _retailMode = MutableStateFlow(false)
+ override val retailMode: StateFlow<Boolean> = _retailMode.asStateFlow()
+
+ private var _retailModeValue = false
+ override val inRetailMode: Boolean
+ get() = _retailModeValue
+
+ fun setRetailMode(value: Boolean) {
+ _retailMode.value = value
+ _retailModeValue = value
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java b/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
index feae56e..b8bac61 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
@@ -157,6 +157,8 @@
if (sDebug) {
Log.d(TAG, "onSuccess Response: " + response);
}
+ fieldClassificationServiceCallbacks
+ .onClassificationRequestSuccess(response);
}
@Override
@@ -165,6 +167,8 @@
if (sDebug) {
Log.d(TAG, "onFailure");
}
+ fieldClassificationServiceCallbacks
+ .onClassificationRequestFailure(0, null);
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3736262..9e46d73 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -204,6 +204,10 @@
RemoteFieldClassificationService.FieldClassificationServiceCallbacks {
private static final String TAG = "AutofillSession";
+ // This should never be true in production. This is only for local debugging.
+ // Otherwise it will spam logcat.
+ private static final boolean DBG = false;
+
private static final String ACTION_DELAYED_FILL =
"android.service.autofill.action.DELAYED_FILL";
private static final String EXTRA_REQUEST_ID = "android.service.autofill.extra.REQUEST_ID";
@@ -1240,6 +1244,8 @@
@GuardedBy("mLock")
private void requestAssistStructureForPccLocked(int flags) {
+ if (!mClassificationState.shouldTriggerRequest()) return;
+ mClassificationState.updatePendingRequest();
// Get request id
int requestId;
// TODO(b/158623971): Update this to prevent possible overflow
@@ -1571,12 +1577,18 @@
// TODO(b/266379948): Ideally wait for PCC request to finish for a while more
// (say 100ms) before proceeding further on.
+ if (DBG) {
+ Slog.d(TAG, "DBG: Initial response: " + response);
+ }
synchronized (mLock) {
response = getEffectiveFillResponse(response);
if (isEmptyResponse(response)) {
// Treat it as a null response.
processNullResponseLocked(requestId, requestFlags);
}
+ if (DBG) {
+ Slog.d(TAG, "DBG: Processed response: " + response);
+ }
processResponseLocked(response, null, requestFlags);
}
}
@@ -1601,12 +1613,25 @@
DatasetComputationContainer autofillProviderContainer = new DatasetComputationContainer();
computeDatasetsForProviderAndUpdateContainer(response, autofillProviderContainer);
+ if (DBG) {
+ Slog.d(TAG, "DBG: computeDatasetsForProviderAndUpdateContainer: "
+ + autofillProviderContainer);
+ }
if (!mService.getMaster().isPccClassificationEnabled()) {
+ if (sVerbose) {
+ Slog.v(TAG, "PCC classification is disabled");
+ }
return createShallowCopy(response, autofillProviderContainer);
}
synchronized (mLock) {
if (mClassificationState.mState != ClassificationState.STATE_RESPONSE
|| mClassificationState.mLastFieldClassificationResponse == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "PCC classification no last response:"
+ + (mClassificationState.mLastFieldClassificationResponse == null)
+ + " ,ineligible state="
+ + (mClassificationState.mState != ClassificationState.STATE_RESPONSE));
+ }
return createShallowCopy(response, autofillProviderContainer);
}
if (!mClassificationState.processResponse()) return response;
@@ -1614,11 +1639,22 @@
boolean preferAutofillProvider = mService.getMaster().preferProviderOverPcc();
boolean shouldUseFallback = mService.getMaster().shouldUsePccFallback();
if (preferAutofillProvider && !shouldUseFallback) {
+ if (sVerbose) {
+ Slog.v(TAG, "preferAutofillProvider but no fallback");
+ }
return createShallowCopy(response, autofillProviderContainer);
}
+ if (DBG) {
+ synchronized (mLock) {
+ Slog.d(TAG, "DBG: ClassificationState: " + mClassificationState);
+ }
+ }
DatasetComputationContainer detectionPccContainer = new DatasetComputationContainer();
computeDatasetsForPccAndUpdateContainer(response, detectionPccContainer);
+ if (DBG) {
+ Slog.d(TAG, "DBG: computeDatasetsForPccAndUpdateContainer: " + detectionPccContainer);
+ }
DatasetComputationContainer resultContainer;
if (preferAutofillProvider) {
@@ -1692,6 +1728,20 @@
// FillResponse.
Set<Dataset> mDatasets = new LinkedHashSet<>();
ArrayMap<AutofillId, Set<Dataset>> mAutofillIdToDatasetMap = new ArrayMap<>();
+
+ public String toString() {
+ final StringBuilder builder = new StringBuilder("DatasetComputationContainer[");
+ if (mAutofillIds != null) {
+ builder.append(", autofillIds=").append(mAutofillIds);
+ }
+ if (mDatasets != null) {
+ builder.append(", mDatasets=").append(mDatasets);
+ }
+ if (mAutofillIdToDatasetMap != null) {
+ builder.append(", mAutofillIdToDatasetMap=").append(mAutofillIdToDatasetMap);
+ }
+ return builder.append(']').toString();
+ }
}
// Adds fallback datasets to the first container.
@@ -1843,7 +1893,6 @@
Dataset dataset = datasets.get(i);
if (dataset.getAutofillDatatypes() == null
|| dataset.getAutofillDatatypes().isEmpty()) continue;
- if (dataset.getFieldIds() != null && dataset.getFieldIds().size() > 0) continue;
ArrayList<AutofillId> fieldIds = new ArrayList<>();
ArrayList<AutofillValue> fieldValues = new ArrayList<>();
@@ -1852,9 +1901,10 @@
ArrayList<InlinePresentation> fieldInlinePresentations = new ArrayList<>();
ArrayList<InlinePresentation> fieldInlineTooltipPresentations = new ArrayList<>();
ArrayList<Dataset.DatasetFieldFilter> fieldFilters = new ArrayList<>();
+ Set<AutofillId> datasetAutofillIds = new ArraySet<>();
for (int j = 0; j < dataset.getAutofillDatatypes().size(); j++) {
- if (dataset.getAutofillDatatypes().get(0) == null) continue;
+ if (dataset.getAutofillDatatypes().get(j) == null) continue;
String hint = dataset.getAutofillDatatypes().get(j);
if (hintsToAutofillIdMap.containsKey(hint)) {
@@ -1863,6 +1913,7 @@
for (AutofillId autofillId : tempIds) {
eligibleAutofillIds.add(autofillId);
+ datasetAutofillIds.add(autofillId);
// For each of the field, copy over values.
fieldIds.add(autofillId);
fieldValues.add(dataset.getFieldValues().get(j));
@@ -1876,37 +1927,6 @@
dataset.getFieldInlineTooltipPresentation(j));
fieldFilters.add(dataset.getFilter(j));
}
-
- Dataset newDataset =
- new Dataset(
- fieldIds,
- fieldValues,
- fieldPresentations,
- fieldDialogPresentations,
- fieldInlinePresentations,
- fieldInlineTooltipPresentations,
- fieldFilters,
- new ArrayList<>(),
- dataset.getFieldContent(),
- null,
- null,
- null,
- null,
- dataset.getId(),
- dataset.getAuthentication());
- eligibleDatasets.add(newDataset);
-
- // Associate this dataset with all the ids that are represented with it.
- Set<Dataset> newDatasets;
- for (AutofillId autofillId : tempIds) {
- if (map.containsKey(autofillId)) {
- newDatasets = map.get(autofillId);
- } else {
- newDatasets = new ArraySet<>();
- }
- newDatasets.add(newDataset);
- map.put(autofillId, newDatasets);
- }
}
// TODO(b/266379948): handle the case:
// groupHintsToAutofillIdMap.containsKey(hint))
@@ -1914,6 +1934,34 @@
// TODO(b/266379948): also handle the case where there could be more types in
// the dataset, provided by the provider, however, they aren't applicable.
}
+ Dataset newDataset =
+ new Dataset(
+ fieldIds,
+ fieldValues,
+ fieldPresentations,
+ fieldDialogPresentations,
+ fieldInlinePresentations,
+ fieldInlineTooltipPresentations,
+ fieldFilters,
+ new ArrayList<>(),
+ dataset.getFieldContent(),
+ null,
+ null,
+ null,
+ null,
+ dataset.getId(),
+ dataset.getAuthentication());
+ eligibleDatasets.add(newDataset);
+ Set<Dataset> newDatasets;
+ for (AutofillId autofillId : datasetAutofillIds) {
+ if (map.containsKey(autofillId)) {
+ newDatasets = map.get(autofillId);
+ } else {
+ newDatasets = new ArraySet<>();
+ }
+ newDatasets.add(newDataset);
+ map.put(autofillId, newDatasets);
+ }
}
container.mAutofillIds = eligibleAutofillIds;
container.mDatasets = eligibleDatasets;
@@ -5319,6 +5367,26 @@
mState = STATE_PENDING_REQUEST;
mPendingFieldClassificationRequest = null;
}
+
+ @GuardedBy("mLock")
+ private boolean shouldTriggerRequest() {
+ return mState == STATE_INITIAL || mState == STATE_INVALIDATED;
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ public String toString() {
+ return "ClassificationState: ["
+ + "state=" + stateToString()
+ + ", mPendingFieldClassificationRequest=" + mPendingFieldClassificationRequest
+ + ", mLastFieldClassificationResponse=" + mLastFieldClassificationResponse
+ + ", mClassificationHintsMap=" + mClassificationHintsMap
+ + ", mClassificationGroupHintsMap=" + mClassificationGroupHintsMap
+ + ", mHintsToAutofillIdMap=" + mHintsToAutofillIdMap
+ + ", mGroupHintsToAutofillIdMap=" + mGroupHintsToAutofillIdMap
+ + "]";
+ }
+
}
@Override
@@ -5843,7 +5911,7 @@
return serviceInfo == null ? Process.INVALID_UID : serviceInfo.applicationInfo.uid;
}
- // DetectionServiceCallbacks
+ // FieldClassificationServiceCallbacks
public void onClassificationRequestSuccess(@Nullable FieldClassificationResponse response) {
mClassificationState.updateResponseReceived(response);
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
index 6f99d86..e436e93 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
@@ -128,9 +128,9 @@
private static final class CallMetadataSyncConnectionIdentifier {
private final int mAssociationId;
- private final long mCallId;
+ private final String mCallId;
- CallMetadataSyncConnectionIdentifier(int associationId, long callId) {
+ CallMetadataSyncConnectionIdentifier(int associationId, String callId) {
mAssociationId = associationId;
mCallId = callId;
}
@@ -139,7 +139,7 @@
return mAssociationId;
}
- public long getCallId() {
+ public String getCallId() {
return mCallId;
}
@@ -161,9 +161,7 @@
private abstract static class CallMetadataSyncConnectionCallback {
- abstract void sendCallAction(int associationId, long callId, int action);
-
- abstract void sendStateChange(int associationId, long callId, int newState);
+ abstract void sendCallAction(int associationId, String callId, int action);
}
private static class CallMetadataSyncConnection extends Connection {
@@ -184,7 +182,7 @@
mCallback = callback;
}
- public long getCallId() {
+ public String getCallId() {
return mCall.getId();
}
@@ -205,22 +203,22 @@
}
final Bundle extras = new Bundle();
- extras.putLong(CrossDeviceCall.EXTRA_CALL_ID, mCall.getId());
+ extras.putString(CrossDeviceCall.EXTRA_CALL_ID, mCall.getId());
putExtras(extras);
int capabilities = getConnectionCapabilities();
- if (mCall.hasControl(android.companion.Telecom.Call.PUT_ON_HOLD)) {
+ if (mCall.hasControl(android.companion.Telecom.PUT_ON_HOLD)) {
capabilities |= CAPABILITY_HOLD;
} else {
capabilities &= ~CAPABILITY_HOLD;
}
- if (mCall.hasControl(android.companion.Telecom.Call.MUTE)) {
+ if (mCall.hasControl(android.companion.Telecom.MUTE)) {
capabilities |= CAPABILITY_MUTE;
} else {
capabilities &= ~CAPABILITY_MUTE;
}
mAudioManager.setMicrophoneMute(
- mCall.hasControl(android.companion.Telecom.Call.UNMUTE));
+ mCall.hasControl(android.companion.Telecom.UNMUTE));
if (capabilities != getConnectionCapabilities()) {
setConnectionCapabilities(capabilities);
}
@@ -248,8 +246,8 @@
int capabilities = getConnectionCapabilities();
final boolean hasHoldControl = mCall.hasControl(
- android.companion.Telecom.Call.PUT_ON_HOLD)
- || mCall.hasControl(android.companion.Telecom.Call.TAKE_OFF_HOLD);
+ android.companion.Telecom.PUT_ON_HOLD)
+ || mCall.hasControl(android.companion.Telecom.TAKE_OFF_HOLD);
if (hasHoldControl != ((getConnectionCapabilities() & CAPABILITY_HOLD)
== CAPABILITY_HOLD)) {
if (hasHoldControl) {
@@ -258,7 +256,7 @@
capabilities &= ~CAPABILITY_HOLD;
}
}
- final boolean hasMuteControl = mCall.hasControl(android.companion.Telecom.Call.MUTE);
+ final boolean hasMuteControl = mCall.hasControl(android.companion.Telecom.MUTE);
if (hasMuteControl != ((getConnectionCapabilities() & CAPABILITY_MUTE)
== CAPABILITY_MUTE)) {
if (hasMuteControl) {
@@ -268,7 +266,7 @@
}
}
mAudioManager.setMicrophoneMute(
- mCall.hasControl(android.companion.Telecom.Call.UNMUTE));
+ mCall.hasControl(android.companion.Telecom.UNMUTE));
if (capabilities != getConnectionCapabilities()) {
setConnectionCapabilities(capabilities);
}
@@ -276,12 +274,12 @@
@Override
public void onAnswer(int videoState) {
- sendCallAction(android.companion.Telecom.Call.ACCEPT);
+ sendCallAction(android.companion.Telecom.ACCEPT);
}
@Override
public void onReject() {
- sendCallAction(android.companion.Telecom.Call.REJECT);
+ sendCallAction(android.companion.Telecom.REJECT);
}
@Override
@@ -296,33 +294,28 @@
@Override
public void onSilence() {
- sendCallAction(android.companion.Telecom.Call.SILENCE);
+ sendCallAction(android.companion.Telecom.SILENCE);
}
@Override
public void onHold() {
- sendCallAction(android.companion.Telecom.Call.PUT_ON_HOLD);
+ sendCallAction(android.companion.Telecom.PUT_ON_HOLD);
}
@Override
public void onUnhold() {
- sendCallAction(android.companion.Telecom.Call.TAKE_OFF_HOLD);
+ sendCallAction(android.companion.Telecom.TAKE_OFF_HOLD);
}
@Override
public void onMuteStateChanged(boolean isMuted) {
- sendCallAction(isMuted ? android.companion.Telecom.Call.MUTE
- : android.companion.Telecom.Call.UNMUTE);
+ sendCallAction(isMuted ? android.companion.Telecom.MUTE
+ : android.companion.Telecom.UNMUTE);
}
@Override
public void onDisconnect() {
- sendCallAction(android.companion.Telecom.Call.END);
- }
-
- @Override
- public void onStateChanged(int state) {
- mCallback.sendStateChange(mAssociationId, mCall.getId(), state);
+ sendCallAction(android.companion.Telecom.END);
}
private void sendCallAction(int action) {
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java
index 1e4bb9a..5b0c745 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java
@@ -33,14 +33,14 @@
/** A read-only snapshot of an {@link ContextSyncMessage}. */
class CallMetadataSyncData {
- final Map<Long, CallMetadataSyncData.Call> mCalls = new HashMap<>();
+ final Map<String, CallMetadataSyncData.Call> mCalls = new HashMap<>();
final List<CallMetadataSyncData.Call> mRequests = new ArrayList<>();
public void addCall(CallMetadataSyncData.Call call) {
mCalls.put(call.getId(), call);
}
- public boolean hasCall(long id) {
+ public boolean hasCall(String id) {
return mCalls.containsKey(id);
}
@@ -57,7 +57,7 @@
}
public static class Call implements Parcelable {
- private long mId;
+ private String mId;
private String mCallerId;
private byte[] mAppIcon;
private String mAppName;
@@ -67,7 +67,7 @@
public static Call fromParcel(Parcel parcel) {
final Call call = new Call();
- call.setId(parcel.readLong());
+ call.setId(parcel.readString());
call.setCallerId(parcel.readString());
call.setAppIcon(parcel.readBlob());
call.setAppName(parcel.readString());
@@ -82,7 +82,7 @@
@Override
public void writeToParcel(Parcel parcel, int parcelableFlags) {
- parcel.writeLong(mId);
+ parcel.writeString(mId);
parcel.writeString(mCallerId);
parcel.writeBlob(mAppIcon);
parcel.writeString(mAppName);
@@ -94,7 +94,7 @@
}
}
- void setId(long id) {
+ void setId(String id) {
mId = id;
}
@@ -122,7 +122,7 @@
mControls.add(control);
}
- long getId() {
+ String getId() {
return mId;
}
@@ -157,7 +157,7 @@
@Override
public boolean equals(Object other) {
if (other instanceof CallMetadataSyncData.Call) {
- return ((Call) other).getId() == getId();
+ return mId != null && mId.equals(((Call) other).getId());
}
return false;
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
index 443a732..0c23730 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
@@ -41,7 +41,6 @@
public class CallMetadataSyncInCallService extends InCallService {
private static final String TAG = "CallMetadataIcs";
- private static final long NOT_VALID = -1L;
private CompanionDeviceManagerServiceInternal mCdmsi;
@@ -71,7 +70,7 @@
callMetadataSyncData.getRequests().iterator();
while (iterator.hasNext()) {
final CallMetadataSyncData.Call call = iterator.next();
- if (call.getId() != 0) {
+ if (call.getId() != null) {
// The call is already assigned an id; treat as control invocations.
for (int control : call.getControls()) {
processCallControlAction(call.getId(), control);
@@ -81,41 +80,41 @@
}
}
- private void processCallControlAction(long crossDeviceCallId,
+ private void processCallControlAction(String crossDeviceCallId,
int callControlAction) {
final CrossDeviceCall crossDeviceCall = getCallForId(crossDeviceCallId,
mCurrentCalls.values());
switch (callControlAction) {
- case android.companion.Telecom.Call.ACCEPT:
+ case android.companion.Telecom.ACCEPT:
if (crossDeviceCall != null) {
crossDeviceCall.doAccept();
}
break;
- case android.companion.Telecom.Call.REJECT:
+ case android.companion.Telecom.REJECT:
if (crossDeviceCall != null) {
crossDeviceCall.doReject();
}
break;
- case android.companion.Telecom.Call.SILENCE:
+ case android.companion.Telecom.SILENCE:
doSilence();
break;
- case android.companion.Telecom.Call.MUTE:
+ case android.companion.Telecom.MUTE:
doMute();
break;
- case android.companion.Telecom.Call.UNMUTE:
+ case android.companion.Telecom.UNMUTE:
doUnmute();
break;
- case android.companion.Telecom.Call.END:
+ case android.companion.Telecom.END:
if (crossDeviceCall != null) {
crossDeviceCall.doEnd();
}
break;
- case android.companion.Telecom.Call.PUT_ON_HOLD:
+ case android.companion.Telecom.PUT_ON_HOLD:
if (crossDeviceCall != null) {
crossDeviceCall.doPutOnHold();
}
break;
- case android.companion.Telecom.Call.TAKE_OFF_HOLD:
+ case android.companion.Telecom.TAKE_OFF_HOLD:
if (crossDeviceCall != null) {
crossDeviceCall.doTakeOffHold();
}
@@ -171,12 +170,12 @@
@Nullable
@VisibleForTesting
- CrossDeviceCall getCallForId(long crossDeviceCallId, Collection<CrossDeviceCall> calls) {
- if (crossDeviceCallId == NOT_VALID) {
+ CrossDeviceCall getCallForId(String crossDeviceCallId, Collection<CrossDeviceCall> calls) {
+ if (crossDeviceCallId == null) {
return null;
}
for (CrossDeviceCall crossDeviceCall : calls) {
- if (crossDeviceCall.getId() == crossDeviceCallId) {
+ if (crossDeviceCallId.equals(crossDeviceCall.getId())) {
return crossDeviceCall;
}
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
index ac981d4..168068e 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
@@ -23,7 +23,6 @@
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Bundle;
import android.telecom.Call;
import android.telecom.CallAudioState;
import android.telecom.VideoProfile;
@@ -34,7 +33,7 @@
import java.io.ByteArrayOutputStream;
import java.util.HashSet;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicLong;
+import java.util.UUID;
/** Data holder for a telecom call and additional metadata. */
public class CrossDeviceCall {
@@ -45,9 +44,7 @@
"com.android.companion.datatransfer.contextsync.extra.CALL_ID";
private static final int APP_ICON_BITMAP_DIMENSION = 256;
- private static final AtomicLong sNextId = new AtomicLong(1);
-
- private final long mId;
+ private final String mId;
private Call mCall;
@VisibleForTesting boolean mIsEnterprise;
@VisibleForTesting boolean mIsOtt;
@@ -64,14 +61,14 @@
CallAudioState callAudioState) {
this(packageManager, call.getDetails(), callAudioState);
mCall = call;
- final Bundle extras = new Bundle();
- extras.putLong(EXTRA_CALL_ID, mId);
- call.putExtras(extras);
+ call.putExtra(EXTRA_CALL_ID, mId);
}
CrossDeviceCall(PackageManager packageManager, Call.Details callDetails,
CallAudioState callAudioState) {
- mId = sNextId.getAndIncrement();
+ final String predefinedId = callDetails.getIntentExtras() != null
+ ? callDetails.getIntentExtras().getString(EXTRA_CALL_ID) : null;
+ mId = predefinedId != null ? predefinedId : UUID.randomUUID().toString();
mCallingAppPackageName =
callDetails.getAccountHandle().getComponentName().getPackageName();
mIsOtt = (callDetails.getCallCapabilities() & Call.Details.PROPERTY_SELF_MANAGED)
@@ -145,7 +142,7 @@
if (mStatus == android.companion.Telecom.Call.RINGING) {
mStatus = android.companion.Telecom.Call.RINGING_SILENCED;
}
- mControls.remove(android.companion.Telecom.Call.SILENCE);
+ mControls.remove(android.companion.Telecom.SILENCE);
}
@VisibleForTesting
@@ -156,26 +153,26 @@
mControls.clear();
if (mStatus == android.companion.Telecom.Call.RINGING
|| mStatus == android.companion.Telecom.Call.RINGING_SILENCED) {
- mControls.add(android.companion.Telecom.Call.ACCEPT);
- mControls.add(android.companion.Telecom.Call.REJECT);
+ mControls.add(android.companion.Telecom.ACCEPT);
+ mControls.add(android.companion.Telecom.REJECT);
if (mStatus == android.companion.Telecom.Call.RINGING) {
- mControls.add(android.companion.Telecom.Call.SILENCE);
+ mControls.add(android.companion.Telecom.SILENCE);
}
}
if (mStatus == android.companion.Telecom.Call.ONGOING
|| mStatus == android.companion.Telecom.Call.ON_HOLD) {
- mControls.add(android.companion.Telecom.Call.END);
+ mControls.add(android.companion.Telecom.END);
if (callDetails.can(Call.Details.CAPABILITY_HOLD)) {
mControls.add(
mStatus == android.companion.Telecom.Call.ON_HOLD
- ? android.companion.Telecom.Call.TAKE_OFF_HOLD
- : android.companion.Telecom.Call.PUT_ON_HOLD);
+ ? android.companion.Telecom.TAKE_OFF_HOLD
+ : android.companion.Telecom.PUT_ON_HOLD);
}
}
if (mStatus == android.companion.Telecom.Call.ONGOING && callDetails.can(
Call.Details.CAPABILITY_MUTE)) {
- mControls.add(mIsMuted ? android.companion.Telecom.Call.UNMUTE
- : android.companion.Telecom.Call.MUTE);
+ mControls.add(mIsMuted ? android.companion.Telecom.UNMUTE
+ : android.companion.Telecom.MUTE);
}
}
@@ -212,7 +209,7 @@
}
}
- public long getId() {
+ public String getId() {
return mId;
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
index adc5faf..e5ab963 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
@@ -270,7 +270,7 @@
while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pis.getFieldNumber()) {
case (int) Telecom.Call.ID:
- call.setId(pis.readLong(Telecom.Call.ID));
+ call.setId(pis.readString(Telecom.Call.ID));
break;
case (int) Telecom.Call.ORIGIN:
final long originToken = pis.start(Telecom.Call.ORIGIN);
@@ -336,7 +336,7 @@
}
/** Create a call control message. */
- public static byte[] createCallControlMessage(long callId, int control) {
+ public static byte[] createCallControlMessage(String callId, int control) {
final ProtoOutputStream pos = new ProtoOutputStream();
pos.write(ContextSyncMessage.VERSION, CURRENT_VERSION);
final long telecomToken = pos.start(ContextSyncMessage.TELECOM);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1a5d425..a992765 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16060,6 +16060,8 @@
final int procState = uidRec != null
? uidRec.getSetProcState() : PROCESS_STATE_NONEXISTENT;
+ final int procAdj = uidRec != null
+ ? uidRec.getMinProcAdj() : ProcessList.INVALID_ADJ;
final long procStateSeq = uidRec != null ? uidRec.curProcStateSeq : 0;
final int capability = uidRec != null ? uidRec.getSetCapability() : 0;
final boolean ephemeral = uidRec != null ? uidRec.isEphemeral() : isEphemeralLocked(uid);
@@ -16075,7 +16077,7 @@
}
final int enqueuedChange = mUidObserverController.enqueueUidChange(
uidRec == null ? null : uidRec.pendingChange,
- uid, change, procState, procStateSeq, capability, ephemeral);
+ uid, change, procState, procAdj, procStateSeq, capability, ephemeral);
if (uidRec != null) {
uidRec.setLastReportedChange(enqueuedChange);
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
index 5a4d315..4a69f90 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
@@ -67,7 +67,6 @@
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
-import android.os.UserManager;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.IndentingPrintWriter;
@@ -78,6 +77,7 @@
import com.android.internal.os.TimeoutRecord;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
+import com.android.server.pm.UserJourneyLogger;
import com.android.server.pm.UserManagerInternal;
import dalvik.annotation.optimization.NeverCompile;
@@ -1518,7 +1518,7 @@
final UserInfo userInfo =
(umInternal != null) ? umInternal.getUserInfo(r.userId) : null;
if (userInfo != null) {
- userType = UserManager.getUserTypeForStatsd(userInfo.userType);
+ userType = UserJourneyLogger.getUserTypeForStatsd(userInfo.userType);
}
Slog.i(TAG_BROADCAST,
"BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED action:"
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 438a08c..0417b8c 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -644,6 +644,11 @@
}
}
+ @GuardedBy({"mService", "mProcLock"})
+ int getSetAdj() {
+ return mState.getSetAdj();
+ }
+
@GuardedBy(anyOf = {"mService", "mProcLock"})
IApplicationThread getThread() {
return mThread;
diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java
index 51cb987..790cc7b 100644
--- a/services/core/java/com/android/server/am/UidObserverController.java
+++ b/services/core/java/com/android/server/am/UidObserverController.java
@@ -96,7 +96,7 @@
}
int enqueueUidChange(@Nullable ChangeRecord currentRecord, int uid, int change, int procState,
- long procStateSeq, int capability, boolean ephemeral) {
+ int procAdj, long procStateSeq, int capability, boolean ephemeral) {
synchronized (mLock) {
if (mPendingUidChanges.size() == 0) {
if (DEBUG_UID_OBSERVERS) {
@@ -117,6 +117,7 @@
changeRecord.uid = uid;
changeRecord.change = change;
changeRecord.procState = procState;
+ changeRecord.procAdj = procAdj;
changeRecord.procStateSeq = procStateSeq;
changeRecord.capability = capability;
changeRecord.ephemeral = ephemeral;
@@ -344,7 +345,7 @@
}
if ((reg.mWhich & ActivityManager.UID_OBSERVER_PROC_OOM_ADJ) != 0
&& (change & UidRecord.CHANGE_PROCADJ) != 0) {
- observer.onUidProcAdjChanged(item.uid);
+ observer.onUidProcAdjChanged(item.uid, item.procAdj);
}
}
final int duration = (int) (SystemClock.uptimeMillis() - start);
@@ -426,6 +427,7 @@
public int uid;
public int change;
public int procState;
+ public int procAdj;
public int capability;
public boolean ephemeral;
public long procStateSeq;
@@ -435,6 +437,7 @@
changeRecord.uid = uid;
changeRecord.change = change;
changeRecord.procState = procState;
+ changeRecord.procAdj = procAdj;
changeRecord.capability = capability;
changeRecord.ephemeral = ephemeral;
changeRecord.procStateSeq = procStateSeq;
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index e39ac2b..993088e 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -51,6 +51,12 @@
private boolean mProcAdjChanged;
@CompositeRWLock({"mService", "mProcLock"})
+ private int mCurAdj;
+
+ @CompositeRWLock({"mService", "mProcLock"})
+ private int mSetAdj;
+
+ @CompositeRWLock({"mService", "mProcLock"})
private int mCurCapability;
@CompositeRWLock({"mService", "mProcLock"})
@@ -201,12 +207,24 @@
mProcAdjChanged = false;
}
- @GuardedBy({"mService", "mProcLock"})
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
boolean getProcAdjChanged() {
return mProcAdjChanged;
}
@GuardedBy(anyOf = {"mService", "mProcLock"})
+ int getMinProcAdj() {
+ int minAdj = ProcessList.UNKNOWN_ADJ;
+ for (int i = mProcRecords.size() - 1; i >= 0; i--) {
+ int adj = mProcRecords.valueAt(i).getSetAdj();
+ if (adj < minAdj) {
+ minAdj = adj;
+ }
+ }
+ return minAdj;
+ }
+
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
int getCurCapability() {
return mCurCapability;
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index b2fdee7..334c145 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -46,13 +46,24 @@
import static com.android.server.am.UserState.STATE_RUNNING_LOCKED;
import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKED;
import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKING;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_ABORTED;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_INVALID_SESSION_ID;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_BEGIN;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_FINISH;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_NONE;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_START;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_STOP;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_SWITCH_FG;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_SWITCH_UI;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_UNLOCKED_USER;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_UNLOCKING_USER;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED;
import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE;
import static com.android.server.pm.UserManagerInternal.USER_START_MODE_BACKGROUND_VISIBLE;
import static com.android.server.pm.UserManagerInternal.USER_START_MODE_FOREGROUND;
import static com.android.server.pm.UserManagerInternal.userAssignmentResultToString;
import static com.android.server.pm.UserManagerInternal.userStartModeToString;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -123,6 +134,8 @@
import com.android.server.SystemService.UserCompletedEventType;
import com.android.server.SystemServiceManager;
import com.android.server.am.UserState.KeyEvictedCallback;
+import com.android.server.pm.UserJourneyLogger;
+import com.android.server.pm.UserJourneyLogger.UserJourneySession;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
import com.android.server.pm.UserManagerInternal.UserStartMode;
@@ -138,7 +151,6 @@
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
-import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -221,75 +233,6 @@
// TODO(b/197344658): Increase to 10s or 15s once we have a switch-UX-is-done invocation too.
private static final int USER_COMPLETED_EVENT_DELAY_MS = 5 * 1000;
- // Used for statsd logging with UserLifecycleJourneyReported + UserLifecycleEventOccurred atoms
- private static final long INVALID_SESSION_ID = 0;
-
- // The various user journeys, defined in the UserLifecycleJourneyReported atom for statsd
- private static final int USER_JOURNEY_UNKNOWN =
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__UNKNOWN;
- private static final int USER_JOURNEY_USER_SWITCH_FG =
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_SWITCH_FG;
- private static final int USER_JOURNEY_USER_SWITCH_UI =
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_SWITCH_UI;
- private static final int USER_JOURNEY_USER_START =
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_START;
- private static final int USER_JOURNEY_USER_CREATE =
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE;
- private static final int USER_JOURNEY_USER_STOP =
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_STOP;
- @IntDef(prefix = { "USER_JOURNEY" }, value = {
- USER_JOURNEY_UNKNOWN,
- USER_JOURNEY_USER_SWITCH_FG,
- USER_JOURNEY_USER_SWITCH_UI,
- USER_JOURNEY_USER_START,
- USER_JOURNEY_USER_CREATE,
- USER_JOURNEY_USER_STOP
- })
- @interface UserJourney {}
-
- // The various user lifecycle events, defined in the UserLifecycleEventOccurred atom for statsd
- private static final int USER_LIFECYCLE_EVENT_UNKNOWN =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNKNOWN;
- private static final int USER_LIFECYCLE_EVENT_SWITCH_USER =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__SWITCH_USER;
- private static final int USER_LIFECYCLE_EVENT_START_USER =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__START_USER;
- private static final int USER_LIFECYCLE_EVENT_CREATE_USER =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__CREATE_USER;
- private static final int USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__USER_RUNNING_LOCKED;
- private static final int USER_LIFECYCLE_EVENT_UNLOCKING_USER =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNLOCKING_USER;
- private static final int USER_LIFECYCLE_EVENT_UNLOCKED_USER =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNLOCKED_USER;
- private static final int USER_LIFECYCLE_EVENT_STOP_USER =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__STOP_USER;
- @IntDef(prefix = { "USER_LIFECYCLE_EVENT" }, value = {
- USER_LIFECYCLE_EVENT_UNKNOWN,
- USER_LIFECYCLE_EVENT_SWITCH_USER,
- USER_LIFECYCLE_EVENT_START_USER,
- USER_LIFECYCLE_EVENT_CREATE_USER,
- USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED,
- USER_LIFECYCLE_EVENT_UNLOCKING_USER,
- USER_LIFECYCLE_EVENT_UNLOCKED_USER,
- USER_LIFECYCLE_EVENT_STOP_USER
- })
- @interface UserLifecycleEvent {}
-
- // User lifecyle event state, defined in the UserLifecycleEventOccurred atom for statsd
- private static final int USER_LIFECYCLE_EVENT_STATE_BEGIN =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__BEGIN;
- private static final int USER_LIFECYCLE_EVENT_STATE_FINISH =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__FINISH;
- private static final int USER_LIFECYCLE_EVENT_STATE_NONE =
- FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__NONE;
- @IntDef(prefix = { "USER_LIFECYCLE_EVENT_STATE" }, value = {
- USER_LIFECYCLE_EVENT_STATE_BEGIN,
- USER_LIFECYCLE_EVENT_STATE_FINISH,
- USER_LIFECYCLE_EVENT_STATE_NONE,
- })
- @interface UserLifecycleEventState {}
-
/**
* Maximum number of users we allow to be running at a time, including system user.
*
@@ -420,13 +363,6 @@
private final ArrayList<Integer> mLastActiveUsers = new ArrayList<>();
/**
- * {@link UserIdInt} to {@link UserJourneySession} mapping used for statsd logging for the
- * UserLifecycleJourneyReported and UserLifecycleEventOccurred atoms.
- */
- @GuardedBy("mUserIdToUserJourneyMap")
- private final SparseArray<UserJourneySession> mUserIdToUserJourneyMap = new SparseArray<>();
-
- /**
* Map of userId to {@link UserCompletedEventType} event flags, indicating which as-yet-
* unreported user-starting events have transpired for the given user.
*/
@@ -621,8 +557,9 @@
// but we might immediately step into RUNNING below if the user
// storage is already unlocked.
if (uss.setState(STATE_BOOTING, STATE_RUNNING_LOCKED)) {
- logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED,
- USER_LIFECYCLE_EVENT_STATE_NONE);
+ mInjector.getUserJourneyLogger()
+ .logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED,
+ EVENT_STATE_NONE);
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
// Do not report secondary users, runtime restarts or first boot/upgrade
if (userId == UserHandle.USER_SYSTEM
@@ -646,7 +583,10 @@
// user transitions to RUNNING_LOCKED. However, in "headless system user mode", the
// system user is explicitly started before the device has finished booting. In
// that case, we need to wait until onBootComplete() to send the broadcast.
- if (!(mInjector.isHeadlessSystemUserMode() && uss.mHandle.isSystem())) {
+ // Similarly, this occurs after a user switch, but in HSUM we switch to the main
+ // user before boot is complete, so again this should be delayed until
+ // onBootComplete if boot has not yet completed.
+ if (mAllowUserUnlocking) {
// ACTION_LOCKED_BOOT_COMPLETED
sendLockedBootCompletedBroadcast(resultTo, userId);
}
@@ -694,8 +634,9 @@
private boolean finishUserUnlocking(final UserState uss) {
final int userId = uss.mHandle.getIdentifier();
EventLog.writeEvent(EventLogTags.UC_FINISH_USER_UNLOCKING, userId);
- logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_UNLOCKING_USER,
- USER_LIFECYCLE_EVENT_STATE_BEGIN);
+ mInjector.getUserJourneyLogger()
+ .logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_UNLOCKING_USER,
+ EVENT_STATE_BEGIN);
// If the user key hasn't been unlocked yet, we cannot proceed.
if (!StorageManager.isUserKeyUnlocked(userId)) return false;
synchronized (mLock) {
@@ -1073,9 +1014,7 @@
return;
}
- logUserJourneyInfo(null, getUserInfo(userId), USER_JOURNEY_USER_STOP);
- logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_STOP_USER,
- USER_LIFECYCLE_EVENT_STATE_BEGIN);
+ logUserJourneyBegin(userId, USER_JOURNEY_USER_STOP);
if (stopUserCallback != null) {
uss.mStopCallbacks.add(stopUserCallback);
@@ -1138,9 +1077,16 @@
synchronized (mLock) {
if (uss.state != UserState.STATE_STOPPING) {
// Whoops, we are being started back up. Abort, abort!
- logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_STOP_USER,
- USER_LIFECYCLE_EVENT_STATE_NONE);
- clearSessionId(userId);
+ UserJourneySession session = mInjector.getUserJourneyLogger()
+ .logUserJourneyFinishWithError(-1, getUserInfo(userId),
+ USER_JOURNEY_USER_STOP, ERROR_CODE_ABORTED);
+ if (session != null) {
+ mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG, session);
+ } else {
+ mInjector.getUserJourneyLogger()
+ .logUserJourneyFinishWithError(-1, getUserInfo(userId),
+ USER_JOURNEY_USER_STOP, ERROR_CODE_INVALID_SESSION_ID);
+ }
return;
}
uss.setState(UserState.STATE_SHUTDOWN);
@@ -1247,9 +1193,11 @@
mInjector.getUserManager().removeUserEvenWhenDisallowed(userId);
}
- logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_STOP_USER,
- USER_LIFECYCLE_EVENT_STATE_FINISH);
- clearSessionId(userId);
+ UserJourneySession session = mInjector.getUserJourneyLogger()
+ .logUserJourneyFinish(-1, userInfo, USER_JOURNEY_USER_STOP);
+ if (session != null) {
+ mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG, session);
+ }
if (lockUser) {
dispatchUserLocking(userIdToLock, keyEvictedCallbacks);
@@ -1259,9 +1207,11 @@
// which was paused while the SHUTDOWN flow of the user was in progress.
resumePendingUserStarts(userId);
} else {
- logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_STOP_USER,
- USER_LIFECYCLE_EVENT_STATE_NONE);
- clearSessionId(userId);
+ UserJourneySession session = mInjector.getUserJourneyLogger()
+ .finishAndClearIncompleteUserJourney(userId, USER_JOURNEY_USER_STOP);
+ if (session != null) {
+ mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG, session);
+ }
}
}
@@ -2617,9 +2567,9 @@
// we should *not* transition users out of the BOOTING state using finishUserBoot(), as that
// doesn't handle issuing the needed onUserStarting() call, and it would just race with an
// explicit start anyway. We do, however, need to send the "locked boot complete" broadcast
- // for the system user, as that got skipped earlier due to the *device* boot not being
- // complete yet. We also need to try to unlock all started users, since until now explicit
- // user starts didn't proceed to unlocking, due to it being too early in the device boot.
+ // as that got skipped earlier due to the *device* boot not being complete yet.
+ // We also need to try to unlock all started users, since until now explicit user starts
+ // didn't proceed to unlocking, due to it being too early in the device boot.
//
// USER_SYSTEM must be processed first. It will be first in the array, as its ID is lowest.
Preconditions.checkArgument(startedUsers.keyAt(0) == UserHandle.USER_SYSTEM);
@@ -2629,9 +2579,7 @@
if (!mInjector.isHeadlessSystemUserMode()) {
finishUserBoot(uss, resultTo);
} else {
- if (userId == UserHandle.USER_SYSTEM) {
- sendLockedBootCompletedBroadcast(resultTo, userId);
- }
+ sendLockedBootCompletedBroadcast(resultTo, userId);
maybeUnlockUser(userId);
}
}
@@ -3135,10 +3083,7 @@
public boolean handleMessage(Message msg) {
switch (msg.what) {
case START_USER_SWITCH_FG_MSG:
- logUserJourneyInfo(getUserInfo(getCurrentUserId()), getUserInfo(msg.arg1),
- USER_JOURNEY_USER_SWITCH_FG);
- logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_SWITCH_USER,
- USER_LIFECYCLE_EVENT_STATE_BEGIN);
+ logUserJourneyBegin(msg.arg1, USER_JOURNEY_USER_SWITCH_FG);
startUserInForeground(msg.arg1);
break;
case REPORT_USER_SWITCH_MSG:
@@ -3160,18 +3105,15 @@
mInjector.batteryStatsServiceNoteEvent(
BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
Integer.toString(msg.arg1), msg.arg1);
- logUserJourneyInfo(null, getUserInfo(msg.arg1), USER_JOURNEY_USER_START);
- logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_START_USER,
- USER_LIFECYCLE_EVENT_STATE_BEGIN);
+ logUserJourneyBegin(msg.arg1, USER_JOURNEY_USER_START);
mInjector.onUserStarting(/* userId= */ msg.arg1);
scheduleOnUserCompletedEvent(msg.arg1,
UserCompletedEventType.EVENT_TYPE_USER_STARTING,
USER_COMPLETED_EVENT_DELAY_MS);
- logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_START_USER,
- USER_LIFECYCLE_EVENT_STATE_FINISH);
- clearSessionId(msg.arg1, USER_JOURNEY_USER_START);
+ mInjector.getUserJourneyLogger().logUserJourneyFinish(-1 , getUserInfo(msg.arg1),
+ USER_JOURNEY_USER_START);
break;
case USER_UNLOCK_MSG:
final int userId = msg.arg1;
@@ -3180,10 +3122,11 @@
FgThread.getHandler().post(() -> {
mInjector.loadUserRecents(userId);
});
- logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_UNLOCKING_USER,
- USER_LIFECYCLE_EVENT_STATE_FINISH);
- logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_UNLOCKED_USER,
- USER_LIFECYCLE_EVENT_STATE_BEGIN);
+
+ mInjector.getUserJourneyLogger().logUserLifecycleEvent(msg.arg1,
+ USER_LIFECYCLE_EVENT_UNLOCKING_USER, EVENT_STATE_FINISH);
+ mInjector.getUserJourneyLogger().logUserLifecycleEvent(msg.arg1,
+ USER_LIFECYCLE_EVENT_UNLOCKED_USER, EVENT_STATE_BEGIN);
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("finishUserUnlocked-" + userId);
@@ -3199,9 +3142,9 @@
// (No need to acquire lock to read mCurrentUserId since it is volatile.)
// TODO: Find something to wait for in the case of a profile.
mCurrentUserId == msg.arg1 ? USER_COMPLETED_EVENT_DELAY_MS : 1000);
- logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_UNLOCKED_USER,
- USER_LIFECYCLE_EVENT_STATE_FINISH);
- clearSessionId(msg.arg1);
+ mInjector.getUserJourneyLogger().logUserLifecycleEvent(msg.arg1,
+ USER_LIFECYCLE_EVENT_UNLOCKED_USER, EVENT_STATE_FINISH);
+ // Unlocking user is not a journey no need to clear sessionId
break;
case USER_CURRENT_MSG:
mInjector.batteryStatsServiceNoteEvent(
@@ -3224,22 +3167,24 @@
break;
case REPORT_USER_SWITCH_COMPLETE_MSG:
dispatchUserSwitchComplete(msg.arg1, msg.arg2);
- logUserLifecycleEvent(msg.arg2, USER_LIFECYCLE_EVENT_SWITCH_USER,
- USER_LIFECYCLE_EVENT_STATE_FINISH);
+ UserJourneySession session = mInjector.getUserJourneyLogger()
+ .logUserSwitchJourneyFinish(msg.arg1, getUserInfo(msg.arg2));
+ if (session != null) {
+ mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG, session);
+ }
break;
case REPORT_LOCKED_BOOT_COMPLETE_MSG:
dispatchLockedBootComplete(msg.arg1);
break;
case START_USER_SWITCH_UI_MSG:
final Pair<UserInfo, UserInfo> fromToUserPair = (Pair<UserInfo, UserInfo>) msg.obj;
- logUserJourneyInfo(fromToUserPair.first, fromToUserPair.second,
- USER_JOURNEY_USER_SWITCH_UI);
- logUserLifecycleEvent(fromToUserPair.second.id, USER_LIFECYCLE_EVENT_SWITCH_USER,
- USER_LIFECYCLE_EVENT_STATE_BEGIN);
+ logUserJourneyBegin(fromToUserPair.second.id, USER_JOURNEY_USER_SWITCH_UI);
showUserSwitchDialog(fromToUserPair);
break;
case CLEAR_USER_JOURNEY_SESSION_MSG:
- logAndClearSessionId(msg.arg1);
+ mInjector.getUserJourneyLogger()
+ .finishAndClearIncompleteUserJourney(msg.arg1, msg.arg2);
+ mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG, msg.obj);
break;
case COMPLETE_USER_SWITCH_MSG:
completeUserSwitch(msg.arg1, msg.arg2);
@@ -3317,123 +3262,29 @@
* statsd helper method for logging the start of a user journey via a UserLifecycleEventOccurred
* atom given the originating and targeting users for the journey.
*/
- private void logUserJourneyInfo(UserInfo origin, UserInfo target, @UserJourney int journey) {
- final long newSessionId = ThreadLocalRandom.current().nextLong(1, Long.MAX_VALUE);
- synchronized (mUserIdToUserJourneyMap) {
- UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(target.id);
- if (userJourneySession != null) {
- // TODO(b/157007231): Move this logic to a separate class/file.
- if ((userJourneySession.mJourney == USER_JOURNEY_USER_SWITCH_UI
- || userJourneySession.mJourney == USER_JOURNEY_USER_SWITCH_FG)
- && (journey == USER_JOURNEY_USER_START
- || journey == USER_JOURNEY_USER_STOP)) {
- /*
- * There is already a user switch journey, and a user start or stop journey for
- * the same target user received. New journey is most likely a part of user
- * switch journey so no need to create a new journey.
- */
- if (DEBUG_MU) {
- Slogf.d(TAG, journey + " not logged as it is expected to be part of "
- + userJourneySession.mJourney);
- }
- return;
- }
- /*
- * Possible reasons for this condition to be true:
- * - A user switch journey is received while another user switch journey is in
- * process for the same user.
- * - A user switch journey is received while user start journey is in process for
- * the same user.
- * - A user start journey is received while another user start journey is in process
- * for the same user.
- * In all cases potentially an incomplete, timed-out session or multiple
- * simultaneous requests. It is not possible to keep track of multiple sessions for
- * the same user, so previous session is abandoned.
- */
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED,
- userJourneySession.mSessionId, target.id, USER_LIFECYCLE_EVENT_UNKNOWN,
- USER_LIFECYCLE_EVENT_STATE_NONE);
- }
-
+ private void logUserJourneyBegin(int targetId,
+ @UserJourneyLogger.UserJourney int journey) {
+ UserJourneySession oldSession = mInjector.getUserJourneyLogger()
+ .finishAndClearIncompleteUserJourney(targetId, journey);
+ if (oldSession != null) {
if (DEBUG_MU) {
Slogf.d(TAG,
- "Starting a new journey: " + journey + " with session id: " + newSessionId);
+ "Starting a new journey: " + journey + " with session id: "
+ + oldSession);
}
-
- userJourneySession = new UserJourneySession(newSessionId, journey);
- mUserIdToUserJourneyMap.put(target.id, userJourneySession);
/*
- * User lifecyle journey would be complete when {@code #clearSessionId} is called after
- * the last expected lifecycle event for the journey. It may be possible that the last
- * event is not called, e.g., user not unlocked after user switching. In such cases user
- * journey is cleared after {@link USER_JOURNEY_TIMEOUT}.
+ * User lifecycle journey would be complete when {@code #clearSessionId} is called
+ * after the last expected lifecycle event for the journey. It may be possible that
+ * the last event is not called, e.g., user not unlocked after user switching. In such
+ * cases user journey is cleared after {@link USER_JOURNEY_TIMEOUT}.
*/
- mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(CLEAR_USER_JOURNEY_SESSION_MSG,
- target.id, /* arg2= */ 0), USER_JOURNEY_TIMEOUT_MS);
+ mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG, oldSession);
}
+ UserJourneySession newSession = mInjector.getUserJourneyLogger()
+ .logUserJourneyBegin(targetId, journey);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(CLEAR_USER_JOURNEY_SESSION_MSG,
+ targetId, /* arg2= */ journey, newSession), USER_JOURNEY_TIMEOUT_MS);
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED, newSessionId,
- journey, origin != null ? origin.id : -1,
- target.id, UserManager.getUserTypeForStatsd(target.userType), target.flags);
- }
-
- /**
- * statsd helper method for logging the given event for the UserLifecycleEventOccurred statsd
- * atom.
- */
- private void logUserLifecycleEvent(@UserIdInt int userId, @UserLifecycleEvent int event,
- @UserLifecycleEventState int eventState) {
- final long sessionId;
- synchronized (mUserIdToUserJourneyMap) {
- final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(userId);
- if (userJourneySession == null || userJourneySession.mSessionId == INVALID_SESSION_ID) {
- Slogf.w(TAG, "UserLifecycleEvent " + event
- + " received without an active userJourneySession.");
- return;
- }
- sessionId = userJourneySession.mSessionId;
- }
-
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED, sessionId, userId,
- event, eventState);
- }
-
- /**
- * Clears the {@link UserJourneySession} for a given {@link UserIdInt} and {@link UserJourney}.
- */
- private void clearSessionId(@UserIdInt int userId, @UserJourney int journey) {
- synchronized (mUserIdToUserJourneyMap) {
- final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(userId);
- if (userJourneySession != null && userJourneySession.mJourney == journey) {
- clearSessionId(userId);
- }
- }
- }
-
- /**
- * Clears the {@link UserJourneySession} for a given {@link UserIdInt}.
- */
- private void clearSessionId(@UserIdInt int userId) {
- synchronized (mUserIdToUserJourneyMap) {
- mHandler.removeMessages(CLEAR_USER_JOURNEY_SESSION_MSG);
- mUserIdToUserJourneyMap.delete(userId);
- }
- }
-
- /**
- * Log a final event of the {@link UserJourneySession} and clear it.
- */
- private void logAndClearSessionId(@UserIdInt int userId) {
- synchronized (mUserIdToUserJourneyMap) {
- final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(userId);
- if (userJourneySession != null) {
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED,
- userJourneySession.mSessionId, userId, USER_LIFECYCLE_EVENT_UNKNOWN,
- USER_LIFECYCLE_EVENT_STATE_NONE);
- }
- clearSessionId(userId);
- }
}
private BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
@@ -3471,23 +3322,6 @@
return mLastUserUnlockingUptime;
}
- /**
- * Helper class to store user journey and session id.
- *
- * <p> User journey tracks a chain of user lifecycle events occurring during different user
- * activities such as user start, user switch, and user creation.
- */
- // TODO(b/157007231): Move this class and user journey tracking logic to a separate file.
- private static class UserJourneySession {
- final long mSessionId;
- @UserJourney final int mJourney;
-
- UserJourneySession(long sessionId, @UserJourney int journey) {
- mJourney = journey;
- mSessionId = sessionId;
- }
- }
-
private static class UserProgressListener extends IProgressListener.Stub {
private volatile long mUnlockStarted;
@Override
@@ -3562,6 +3396,10 @@
return new Handler(mService.mUiHandler.getLooper(), callback);
}
+ protected UserJourneyLogger getUserJourneyLogger() {
+ return getUserManager().getUserJourneyLogger();
+ }
+
protected Context getContext() {
return mService.mContext;
}
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 412fbe79..4e7865c 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -33,6 +33,8 @@
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
@@ -53,6 +55,8 @@
import com.android.internal.util.UserIcons;
import com.android.server.wm.WindowManagerService;
+import java.util.concurrent.atomic.AtomicBoolean;
+
/**
* Dialog to show during the user switch. This dialog shows target user's name and their profile
* picture with a circular spinner animation around it if the animations for this dialog are not
@@ -64,9 +68,14 @@
// User switching doesn't happen that frequently, so it doesn't hurt to have it always on
protected static final boolean DEBUG = true;
+
private static final long DIALOG_SHOW_HIDE_ANIMATION_DURATION_MS = 300;
private final boolean mDisableAnimations;
+ // Time to wait for the onAnimationEnd() callbacks before moving on
+ private static final int ANIMATION_TIMEOUT_MS = 1000;
+ private final Handler mHandler = new Handler(Looper.myLooper());
+
protected final UserInfo mOldUser;
protected final UserInfo mNewUser;
private final String mSwitchingFromSystemUserMessage;
@@ -180,7 +189,7 @@
@Override
public void show() {
- asyncTraceBegin("", 0);
+ asyncTraceBegin("dialog", 0);
super.show();
}
@@ -188,7 +197,7 @@
public void dismiss() {
super.dismiss();
stopFreezingScreen();
- asyncTraceEnd("", 0);
+ asyncTraceEnd("dialog", 0);
}
public void show(@NonNull Runnable onShown) {
@@ -217,20 +226,18 @@
if (!mNeedToFreezeScreen) {
return;
}
- if (DEBUG) Slog.d(TAG, "startFreezingScreen");
- Trace.traceBegin(TRACE_TAG, "startFreezingScreen");
+ traceBegin("startFreezingScreen");
mWindowManager.startFreezingScreen(0, 0);
- Trace.traceEnd(TRACE_TAG);
+ traceEnd("startFreezingScreen");
}
private void stopFreezingScreen() {
if (!mNeedToFreezeScreen) {
return;
}
- if (DEBUG) Slog.d(TAG, "stopFreezingScreen");
- Trace.traceBegin(TRACE_TAG, "stopFreezingScreen");
+ traceBegin("stopFreezingScreen");
mWindowManager.stopFreezingScreen();
- Trace.traceEnd(TRACE_TAG);
+ traceEnd("stopFreezingScreen");
}
private void startShowAnimation(Runnable onAnimationEnd) {
@@ -238,13 +245,13 @@
onAnimationEnd.run();
return;
}
- asyncTraceBegin("-showAnimation", 1);
- startDialogAnimation(new AlphaAnimation(0, 1), () -> {
- asyncTraceEnd("-showAnimation", 1);
+ asyncTraceBegin("showAnimation", 1);
+ startDialogAnimation("show", new AlphaAnimation(0, 1), () -> {
+ asyncTraceEnd("showAnimation", 1);
- asyncTraceBegin("-spinnerAnimation", 2);
+ asyncTraceBegin("spinnerAnimation", 2);
startProgressAnimation(() -> {
- asyncTraceEnd("-spinnerAnimation", 2);
+ asyncTraceEnd("spinnerAnimation", 2);
onAnimationEnd.run();
});
@@ -257,9 +264,9 @@
onAnimationEnd.run();
return;
}
- asyncTraceBegin("-dismissAnimation", 3);
- startDialogAnimation(new AlphaAnimation(1, 0), () -> {
- asyncTraceEnd("-dismissAnimation", 3);
+ asyncTraceBegin("dismissAnimation", 3);
+ startDialogAnimation("dismiss", new AlphaAnimation(1, 0), () -> {
+ asyncTraceEnd("dismissAnimation", 3);
onAnimationEnd.run();
});
@@ -271,10 +278,11 @@
onAnimationEnd.run();
return;
}
+ final Runnable onAnimationEndWithTimeout = animationWithTimeout("spinner", onAnimationEnd);
avd.registerAnimationCallback(new Animatable2.AnimationCallback() {
@Override
public void onAnimationEnd(Drawable drawable) {
- onAnimationEnd.run();
+ onAnimationEndWithTimeout.run();
}
});
avd.start();
@@ -291,12 +299,13 @@
return null;
}
- private void startDialogAnimation(Animation animation, Runnable onAnimationEnd) {
+ private void startDialogAnimation(String name, Animation animation, Runnable onAnimationEnd) {
final View view = findViewById(R.id.content);
if (mDisableAnimations || view == null) {
onAnimationEnd.run();
return;
}
+ final Runnable onAnimationEndWithTimeout = animationWithTimeout(name, onAnimationEnd);
animation.setDuration(DIALOG_SHOW_HIDE_ANIMATION_DURATION_MS);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
@@ -306,7 +315,7 @@
@Override
public void onAnimationEnd(Animation animation) {
- onAnimationEnd.run();
+ onAnimationEndWithTimeout.run();
}
@Override
@@ -317,11 +326,39 @@
view.startAnimation(animation);
}
+ private Runnable animationWithTimeout(String name, Runnable onAnimationEnd) {
+ final AtomicBoolean isFirst = new AtomicBoolean(true);
+ final Runnable onAnimationEndOrTimeout = () -> {
+ if (isFirst.getAndSet(false)) {
+ mHandler.removeCallbacksAndMessages(null);
+ onAnimationEnd.run();
+ }
+ };
+ mHandler.postDelayed(() -> {
+ Slog.w(TAG, name + " animation not completed in " + ANIMATION_TIMEOUT_MS + " ms");
+ onAnimationEndOrTimeout.run();
+ }, ANIMATION_TIMEOUT_MS);
+
+ return onAnimationEndOrTimeout;
+ }
+
private void asyncTraceBegin(String subTag, int subCookie) {
+ if (DEBUG) Slog.d(TAG, "asyncTraceBegin-" + subTag);
Trace.asyncTraceBegin(TRACE_TAG, TAG + subTag, mTraceCookie + subCookie);
}
private void asyncTraceEnd(String subTag, int subCookie) {
Trace.asyncTraceEnd(TRACE_TAG, TAG + subTag, mTraceCookie + subCookie);
+ if (DEBUG) Slog.d(TAG, "asyncTraceEnd-" + subTag);
+ }
+
+ private void traceBegin(String msg) {
+ if (DEBUG) Slog.d(TAG, "traceBegin-" + msg);
+ Trace.traceBegin(TRACE_TAG, msg);
+ }
+
+ private void traceEnd(String msg) {
+ Trace.traceEnd(TRACE_TAG);
+ if (DEBUG) Slog.d(TAG, "traceEnd-" + msg);
}
}
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index d369af6..e4a5a3e 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -402,11 +402,15 @@
public enum FrameRate {
FPS_DEFAULT(0),
FPS_30(30),
+ FPS_36(36),
FPS_40(40),
FPS_45(45),
+ FPS_48(48),
FPS_60(60),
+ FPS_72(72),
FPS_90(90),
FPS_120(120),
+ FPS_144(144),
FPS_INVALID(-1);
public final int fps;
@@ -423,16 +427,24 @@
switch (raw) {
case "30":
return FrameRate.FPS_30.fps;
+ case "36":
+ return FrameRate.FPS_36.fps;
case "40":
return FrameRate.FPS_40.fps;
case "45":
return FrameRate.FPS_45.fps;
+ case "48":
+ return FrameRate.FPS_48.fps;
case "60":
return FrameRate.FPS_60.fps;
+ case "72":
+ return FrameRate.FPS_72.fps;
case "90":
return FrameRate.FPS_90.fps;
case "120":
return FrameRate.FPS_120.fps;
+ case "144":
+ return FrameRate.FPS_144.fps;
case "disable":
case "":
return FrameRate.FPS_DEFAULT.fps;
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 9429b4c..4984f12 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -303,8 +303,6 @@
SAFE_MEDIA_VOLUME_UNINITIALIZED);
mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_BLE_BROADCAST,
SAFE_MEDIA_VOLUME_UNINITIALIZED);
- mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_HEARING_AID,
- SAFE_MEDIA_VOLUME_UNINITIALIZED);
mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
SAFE_MEDIA_VOLUME_UNINITIALIZED);
// TODO(b/278265907): enable A2DP when we can distinguish A2DP headsets
diff --git a/services/core/java/com/android/server/display/color/CctEvaluator.java b/services/core/java/com/android/server/display/color/CctEvaluator.java
new file mode 100644
index 0000000..878f7e5
--- /dev/null
+++ b/services/core/java/com/android/server/display/color/CctEvaluator.java
@@ -0,0 +1,108 @@
+/*
+ * 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.color;
+
+import android.animation.TypeEvaluator;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Arrays;
+
+/**
+ * Interpolates between CCT values by a given step.
+ */
+class CctEvaluator implements TypeEvaluator<Integer> {
+
+ private static final String TAG = "CctEvaluator";
+
+ /**
+ * The minimum input value, which will represent index 0 in the mValues array. Each
+ * subsequent input value is offset by this amount.
+ */
+ private final int mIndexOffset;
+ /**
+ * Cached step values at each CCT value (offset by the {@link #mIndexOffset} above). For
+ * example, if the minimum CCT is 2000K (which is set to mIndexOffset), then the 0th index of
+ * this array is equivalent to the step value at 2000K, 1st index corresponds to 2001K, and so
+ * on.
+ */
+ @VisibleForTesting
+ final int[] mStepsAtOffsetCcts;
+ /**
+ * Pre-computed stepped CCTs. These will be accessed frequently; the memory cost of caching them
+ * is well-spent.
+ */
+ @VisibleForTesting
+ final int[] mSteppedCctsAtOffsetCcts;
+
+ CctEvaluator(int min, int max, int[] cctRangeMinimums, int[] steps) {
+ final int delta = max - min + 1;
+ mStepsAtOffsetCcts = new int[delta];
+ mSteppedCctsAtOffsetCcts = new int[delta];
+ mIndexOffset = min;
+
+ final int parallelArraysLength = cctRangeMinimums.length;
+ if (cctRangeMinimums.length != steps.length) {
+ Slog.e(TAG,
+ "Parallel arrays cctRangeMinimums and steps are different lengths; setting "
+ + "step of 1");
+ setStepOfOne();
+ } else if (parallelArraysLength == 0) {
+ Slog.e(TAG, "No cctRangeMinimums or steps are set; setting step of 1");
+ setStepOfOne();
+ } else {
+ int parallelArraysIndex = 0;
+ int index = 0;
+ int lastSteppedCct = Integer.MIN_VALUE;
+ while (index < delta) {
+ final int cct = index + mIndexOffset;
+ int nextParallelArraysIndex = parallelArraysIndex + 1;
+ while (nextParallelArraysIndex < parallelArraysLength
+ && cct >= cctRangeMinimums[nextParallelArraysIndex]) {
+ parallelArraysIndex = nextParallelArraysIndex;
+ nextParallelArraysIndex++;
+ }
+ mStepsAtOffsetCcts[index] = steps[parallelArraysIndex];
+ if (lastSteppedCct == Integer.MIN_VALUE
+ || Math.abs(lastSteppedCct - cct) >= steps[parallelArraysIndex]) {
+ lastSteppedCct = cct;
+ }
+ mSteppedCctsAtOffsetCcts[index] = lastSteppedCct;
+ index++;
+ }
+ }
+ }
+
+ @Override
+ public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
+ final int cct = (int) (startValue + fraction * (endValue - startValue));
+ final int index = cct - mIndexOffset;
+ if (index < 0 || index >= mSteppedCctsAtOffsetCcts.length) {
+ Slog.e(TAG, "steppedCctValueAt: returning same since invalid requested index=" + index);
+ return cct;
+ }
+ return mSteppedCctsAtOffsetCcts[index];
+ }
+
+ private void setStepOfOne() {
+ Arrays.fill(mStepsAtOffsetCcts, 1);
+ for (int i = 0; i < mSteppedCctsAtOffsetCcts.length; i++) {
+ mSteppedCctsAtOffsetCcts[i] = mIndexOffset + i;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 0284d9c..c0ea5fea 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -180,6 +180,8 @@
*/
private SparseIntArray mColorModeCompositionColorSpaces = null;
+ private final Object mCctTintApplierLock = new Object();
+
public ColorDisplayService(Context context) {
super(context);
mHandler = new TintHandler(DisplayThread.get().getLooper());
@@ -698,6 +700,79 @@
}
}
+ private void applyTintByCct(ColorTemperatureTintController tintController, boolean immediate) {
+ synchronized (mCctTintApplierLock) {
+ tintController.cancelAnimator();
+
+ final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+ final int from = tintController.getAppliedCct();
+ final int to = tintController.isActivated() ? tintController.getTargetCct()
+ : tintController.getDisabledCct();
+
+ if (immediate) {
+ Slog.d(TAG, tintController.getClass().getSimpleName()
+ + " applied immediately: toCct=" + to + " fromCct=" + from);
+ dtm.setColorMatrix(tintController.getLevel(),
+ tintController.computeMatrixForCct(to));
+ tintController.setAppliedCct(to);
+ } else {
+ Slog.d(TAG, tintController.getClass().getSimpleName() + " animation started: toCct="
+ + to + " fromCct=" + from);
+ ValueAnimator valueAnimator = ValueAnimator.ofInt(from, to);
+ tintController.setAnimator(valueAnimator);
+ final CctEvaluator evaluator = tintController.getEvaluator();
+ if (evaluator != null) {
+ valueAnimator.setEvaluator(evaluator);
+ }
+ valueAnimator.setDuration(tintController.getTransitionDurationMilliseconds());
+ valueAnimator.setInterpolator(AnimationUtils.loadInterpolator(
+ getContext(), android.R.interpolator.linear));
+ valueAnimator.addUpdateListener((ValueAnimator animator) -> {
+ synchronized (mCctTintApplierLock) {
+ final int value = (int) animator.getAnimatedValue();
+ if (value != tintController.getAppliedCct()) {
+ dtm.setColorMatrix(tintController.getLevel(),
+ tintController.computeMatrixForCct(value));
+ tintController.setAppliedCct(value);
+ }
+ }
+ });
+ valueAnimator.addListener(new AnimatorListenerAdapter() {
+
+ private boolean mIsCancelled;
+
+ @Override
+ public void onAnimationCancel(Animator animator) {
+ Slog.d(TAG, tintController.getClass().getSimpleName()
+ + " animation cancelled");
+ mIsCancelled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ synchronized (mCctTintApplierLock) {
+ Slog.d(TAG, tintController.getClass().getSimpleName()
+ + " animation ended: wasCancelled=" + mIsCancelled
+ + " toCct=" + to
+ + " fromCct=" + from);
+ if (!mIsCancelled) {
+ // Ensure final color matrix is set at the end of the animation.
+ // If the animation is cancelled then don't set the final color
+ // matrix so the new animator can pick up from where this one left
+ // off.
+ dtm.setColorMatrix(tintController.getLevel(),
+ tintController.computeMatrixForCct(to));
+ tintController.setAppliedCct(to);
+ }
+ tintController.setAnimator(null);
+ }
+ }
+ });
+ valueAnimator.start();
+ }
+ }
+ }
+
/**
* Returns the first date time corresponding to the local time that occurs before the provided
* date time.
@@ -747,7 +822,7 @@
// If disabled, clear the tint. If enabled, do nothing more here and let the next
// temperature update set the correct tint.
- if (!activated) {
+ if (oldActivated && !activated) {
mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
}
}
@@ -1452,7 +1527,7 @@
public class ColorDisplayServiceInternal {
/** Sets whether DWB should be allowed in the current state. */
- public void setDisplayWhiteBalanceAllowed(boolean allowed) {
+ public void setDisplayWhiteBalanceAllowed(boolean allowed) {
mDisplayWhiteBalanceTintController.setAllowed(allowed);
updateDisplayWhiteBalanceStatus();
}
@@ -1464,8 +1539,8 @@
* @param cct the color temperature in Kelvin.
*/
public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
- // Update the transform matrix even if it can't be applied.
- mDisplayWhiteBalanceTintController.setMatrix(cct);
+ // Update the transform target CCT even if it can't be applied.
+ mDisplayWhiteBalanceTintController.setTargetCct(cct);
if (mDisplayWhiteBalanceTintController.isActivated()) {
mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
@@ -1601,7 +1676,7 @@
applyTint(mNightDisplayTintController, false);
break;
case MSG_APPLY_DISPLAY_WHITE_BALANCE:
- applyTint(mDisplayWhiteBalanceTintController, false);
+ applyTintByCct(mDisplayWhiteBalanceTintController, false);
break;
}
}
diff --git a/services/core/java/com/android/server/display/color/ColorTemperatureTintController.java b/services/core/java/com/android/server/display/color/ColorTemperatureTintController.java
new file mode 100644
index 0000000..0fbd9d4
--- /dev/null
+++ b/services/core/java/com/android/server/display/color/ColorTemperatureTintController.java
@@ -0,0 +1,38 @@
+/*
+ * 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.color;
+
+abstract class ColorTemperatureTintController extends TintController {
+
+ abstract int getAppliedCct();
+
+ abstract void setAppliedCct(int cct);
+
+ abstract int getTargetCct();
+
+ abstract void setTargetCct(int cct);
+
+ /**
+ * Returns the CCT value most closely associated with the "disabled" (identity) matrix for
+ * this device, to use as the target when deactivating this transform.
+ */
+ abstract int getDisabledCct();
+
+ abstract float[] computeMatrixForCct(int cct);
+
+ abstract CctEvaluator getEvaluator();
+}
diff --git a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
index 106ac0c..bf0139f 100644
--- a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
+++ b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
@@ -21,6 +21,7 @@
import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.Size;
import android.content.Context;
import android.content.res.Resources;
@@ -36,7 +37,7 @@
import java.io.PrintWriter;
-final class DisplayWhiteBalanceTintController extends TintController {
+final class DisplayWhiteBalanceTintController extends ColorTemperatureTintController {
// Three chromaticity coordinates per color: X, Y, and Z
private static final int NUM_VALUES_PER_PRIMARY = 3;
@@ -52,9 +53,11 @@
private int mTemperatureDefault;
@VisibleForTesting
float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ private int mDisplayNominalWhiteCct;
@VisibleForTesting
ColorSpace.Rgb mDisplayColorSpaceRGB;
private float[] mChromaticAdaptationMatrix;
+ // The temperature currently represented in the matrix.
@VisibleForTesting
int mCurrentColorTemperature;
private float[] mCurrentColorTemperatureXYZ;
@@ -65,6 +68,9 @@
private Boolean mIsAvailable;
// This feature becomes disallowed if the device is in an unsupported strong/light state.
private boolean mIsAllowed = true;
+ private int mTargetCct;
+ private int mAppliedCct;
+ private CctEvaluator mCctEvaluator;
private final DisplayManagerInternal mDisplayManagerInternal;
@@ -108,6 +114,9 @@
displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
}
+ final int displayNominalWhiteCct = res.getInteger(
+ R.integer.config_displayWhiteBalanceDisplayNominalWhiteCct);
+
final int colorTemperatureMin = res.getInteger(
R.integer.config_displayWhiteBalanceColorTemperatureMin);
if (colorTemperatureMin <= 0) {
@@ -124,19 +133,28 @@
return;
}
- final int colorTemperature = res.getInteger(
+ final int defaultTemperature = res.getInteger(
R.integer.config_displayWhiteBalanceColorTemperatureDefault);
mTransitionDuration = res.getInteger(
R.integer.config_displayWhiteBalanceTransitionTime);
+ int[] cctRangeMinimums = res.getIntArray(
+ R.array.config_displayWhiteBalanceDisplayRangeMinimums);
+ int[] steps = res.getIntArray(R.array.config_displayWhiteBalanceDisplaySteps);
+
synchronized (mLock) {
mDisplayColorSpaceRGB = displayColorSpaceRGB;
mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
+ mDisplayNominalWhiteCct = displayNominalWhiteCct;
+ mTargetCct = mDisplayNominalWhiteCct;
+ mAppliedCct = mDisplayNominalWhiteCct;
mTemperatureMin = colorTemperatureMin;
mTemperatureMax = colorTemperatureMax;
- mTemperatureDefault = colorTemperature;
+ mTemperatureDefault = defaultTemperature;
mSetUp = true;
+ mCctEvaluator = new CctEvaluator(mTemperatureMin, mTemperatureMax,
+ cctRangeMinimums, steps);
}
setMatrix(mTemperatureDefault);
@@ -144,8 +162,16 @@
@Override
public float[] getMatrix() {
- return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance
- : ColorDisplayService.MATRIX_IDENTITY;
+ if (!mSetUp || !isActivated()) {
+ return ColorDisplayService.MATRIX_IDENTITY;
+ }
+ computeMatrixForCct(mAppliedCct);
+ return mMatrixDisplayWhiteBalance;
+ }
+
+ @Override
+ public int getTargetCct() {
+ return mTargetCct;
}
/**
@@ -174,6 +200,12 @@
@Override
public void setMatrix(int cct) {
+ setTargetCct(cct);
+ computeMatrixForCct(mTargetCct);
+ }
+
+ @Override
+ public void setTargetCct(int cct) {
if (!mSetUp) {
Slog.w(ColorDisplayService.TAG,
"Can't set display white balance temperature: uninitialized");
@@ -183,50 +215,93 @@
if (cct < mTemperatureMin) {
Slog.w(ColorDisplayService.TAG,
"Requested display color temperature is below allowed minimum");
- cct = mTemperatureMin;
+ mTargetCct = mTemperatureMin;
} else if (cct > mTemperatureMax) {
Slog.w(ColorDisplayService.TAG,
"Requested display color temperature is above allowed maximum");
- cct = mTemperatureMax;
+ mTargetCct = mTemperatureMax;
+ } else {
+ mTargetCct = cct;
+ }
+ }
+
+ @Override
+ public int getDisabledCct() {
+ return mDisplayNominalWhiteCct;
+ }
+
+ @Override
+ public float[] computeMatrixForCct(int cct) {
+ if (!mSetUp || cct == 0) {
+ Slog.w(ColorDisplayService.TAG, "Couldn't compute matrix for cct=" + cct);
+ return ColorDisplayService.MATRIX_IDENTITY;
}
synchronized (mLock) {
mCurrentColorTemperature = cct;
- // Adapt the display's nominal white point to match the requested CCT value
- mCurrentColorTemperatureXYZ = ColorSpace.cctToXyz(cct);
-
- mChromaticAdaptationMatrix =
- ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
- mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
-
- // Convert the adaptation matrix to RGB space
- float[] result = mul3x3(mChromaticAdaptationMatrix,
- mDisplayColorSpaceRGB.getTransform());
- result = mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
-
- // Normalize the transform matrix to peak white value in RGB space
- final float adaptedMaxR = result[0] + result[3] + result[6];
- final float adaptedMaxG = result[1] + result[4] + result[7];
- final float adaptedMaxB = result[2] + result[5] + result[8];
- final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
-
- Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
- for (int i = 0; i < result.length; i++) {
- result[i] /= denum;
- if (!isColorMatrixCoeffValid(result[i])) {
- Slog.e(ColorDisplayService.TAG, "Invalid DWB color matrix");
- return;
- }
+ if (cct == mDisplayNominalWhiteCct && !isActivated()) {
+ // DWB is finished turning off. Clear the matrix.
+ Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+ } else {
+ computeMatrixForCctLocked(cct);
}
- java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
- java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
- java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+ Slog.d(ColorDisplayService.TAG, "computeDisplayWhiteBalanceMatrix: cct =" + cct
+ + " matrix =" + matrixToString(mMatrixDisplayWhiteBalance, 16));
+
+ return mMatrixDisplayWhiteBalance;
+ }
+ }
+
+ private void computeMatrixForCctLocked(int cct) {
+ // Adapt the display's nominal white point to match the requested CCT value
+ mCurrentColorTemperatureXYZ = ColorSpace.cctToXyz(cct);
+
+ mChromaticAdaptationMatrix =
+ ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
+ mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
+
+ // Convert the adaptation matrix to RGB space
+ float[] result = mul3x3(mChromaticAdaptationMatrix,
+ mDisplayColorSpaceRGB.getTransform());
+ result = mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
+
+ // Normalize the transform matrix to peak white value in RGB space
+ final float adaptedMaxR = result[0] + result[3] + result[6];
+ final float adaptedMaxG = result[1] + result[4] + result[7];
+ final float adaptedMaxB = result[2] + result[5] + result[8];
+ final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
+
+ Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+
+ for (int i = 0; i < result.length; i++) {
+ result[i] /= denum;
+ if (!isColorMatrixCoeffValid(result[i])) {
+ Slog.e(ColorDisplayService.TAG, "Invalid DWB color matrix");
+ return;
+ }
}
- Slog.d(ColorDisplayService.TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct
- + " matrix = " + matrixToString(mMatrixDisplayWhiteBalance, 16));
+ java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
+ java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
+ java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+ }
+
+ @Override
+ int getAppliedCct() {
+ return mAppliedCct;
+ }
+
+ @Override
+ void setAppliedCct(int cct) {
+ mAppliedCct = cct;
+ }
+
+ @Override
+ @Nullable
+ CctEvaluator getEvaluator() {
+ return mCctEvaluator;
}
@Override
@@ -258,7 +333,10 @@
pw.println(" mTemperatureMin = " + mTemperatureMin);
pw.println(" mTemperatureMax = " + mTemperatureMax);
pw.println(" mTemperatureDefault = " + mTemperatureDefault);
+ pw.println(" mDisplayNominalWhiteCct = " + mDisplayNominalWhiteCct);
pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature);
+ pw.println(" mTargetCct = " + mTargetCct);
+ pw.println(" mAppliedCct = " + mAppliedCct);
pw.println(" mCurrentColorTemperatureXYZ = "
+ matrixToString(mCurrentColorTemperatureXYZ, 3));
pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = "
@@ -340,11 +418,7 @@
}
private boolean isColorMatrixCoeffValid(float coeff) {
- if (Float.isNaN(coeff) || Float.isInfinite(coeff)) {
- return false;
- }
-
- return true;
+ return !Float.isNaN(coeff) && !Float.isInfinite(coeff);
}
private boolean isColorMatrixValid(float[] matrix) {
@@ -352,8 +426,8 @@
return false;
}
- for (int i = 0; i < matrix.length; i++) {
- if (!isColorMatrixCoeffValid(matrix[i])) {
+ for (float value : matrix) {
+ if (!isColorMatrixCoeffValid(value)) {
return false;
}
}
diff --git a/services/core/java/com/android/server/display/color/TintController.java b/services/core/java/com/android/server/display/color/TintController.java
index c53ac06..384333a 100644
--- a/services/core/java/com/android/server/display/color/TintController.java
+++ b/services/core/java/com/android/server/display/color/TintController.java
@@ -16,6 +16,7 @@
package com.android.server.display.color;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.util.Slog;
@@ -28,14 +29,14 @@
*/
private static final long TRANSITION_DURATION = 3000L;
- private ColorDisplayService.TintValueAnimator mAnimator;
+ private ValueAnimator mAnimator;
private Boolean mIsActivated;
- public ColorDisplayService.TintValueAnimator getAnimator() {
+ public ValueAnimator getAnimator() {
return mAnimator;
}
- public void setAnimator(ColorDisplayService.TintValueAnimator animator) {
+ public void setAnimator(ValueAnimator animator) {
mAnimator = animator;
}
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index d8716b3..6ec4022 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -562,7 +562,7 @@
key.append(",languageTag:").append(inputDevice.getKeyboardLanguageTag());
}
if (!TextUtils.isEmpty(inputDevice.getKeyboardLayoutType())) {
- key.append(",layoutType:").append(inputDevice.getKeyboardLanguageTag());
+ key.append(",layoutType:").append(inputDevice.getKeyboardLayoutType());
}
}
return key.toString();
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 464a256..02b7053 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -16,6 +16,12 @@
package com.android.server.media;
+import static android.media.VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
+import static android.media.VolumeProvider.VOLUME_CONTROL_FIXED;
+import static android.media.VolumeProvider.VOLUME_CONTROL_RELATIVE;
+import static android.media.session.MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
+import static android.media.session.MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -173,8 +179,8 @@
// Volume handling fields
private AudioAttributes mAudioAttrs;
private AudioManager mAudioManager;
- private int mVolumeType = PlaybackInfo.PLAYBACK_TYPE_LOCAL;
- private int mVolumeControlType = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
+ private int mVolumeType = PLAYBACK_TYPE_LOCAL;
+ private int mVolumeControlType = VOLUME_CONTROL_ABSOLUTE;
private int mMaxVolume = 0;
private int mCurrentVolume = 0;
private int mOptimisticVolume = -1;
@@ -309,13 +315,13 @@
if (checkPlaybackActiveState(true) || isSystemPriority()) {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
}
- if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
+ if (mVolumeType == PLAYBACK_TYPE_LOCAL) {
// Adjust the volume with a handler not to be blocked by other system service.
int stream = getVolumeStream(mAudioAttrs);
postAdjustLocalVolume(stream, direction, flags, opPackageName, pid, uid,
asSystemService, useSuggested, previousFlagPlaySound);
} else {
- if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
+ if (mVolumeControlType == VOLUME_CONTROL_FIXED) {
if (DEBUG) {
Log.d(TAG, "Session does not support volume adjustment");
}
@@ -354,7 +360,7 @@
private void setVolumeTo(String packageName, String opPackageName, int pid, int uid, int value,
int flags) {
- if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
+ if (mVolumeType == PLAYBACK_TYPE_LOCAL) {
int stream = getVolumeStream(mAudioAttrs);
final int volumeValue = value;
mHandler.post(new Runnable() {
@@ -371,7 +377,7 @@
}
});
} else {
- if (mVolumeControlType != VolumeProvider.VOLUME_CONTROL_ABSOLUTE) {
+ if (mVolumeControlType != VOLUME_CONTROL_ABSOLUTE) {
if (DEBUG) {
Log.d(TAG, "Session does not support setting volume");
}
@@ -433,7 +439,7 @@
*/
@Override
public boolean isPlaybackTypeLocal() {
- return mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL;
+ return mVolumeType == PLAYBACK_TYPE_LOCAL;
}
@Override
@@ -495,7 +501,7 @@
@Override
public boolean canHandleVolumeKey() {
- return mVolumeControlType != VolumeProvider.VOLUME_CONTROL_FIXED;
+ return mVolumeControlType != VOLUME_CONTROL_FIXED;
}
@Override
@@ -528,13 +534,48 @@
pw.println(indent + "controllers: " + mControllerCallbackHolders.size());
pw.println(indent + "state=" + (mPlaybackState == null ? null : mPlaybackState.toString()));
pw.println(indent + "audioAttrs=" + mAudioAttrs);
- pw.println(indent + "volumeType=" + mVolumeType + ", controlType=" + mVolumeControlType
- + ", max=" + mMaxVolume + ", current=" + mCurrentVolume);
+ pw.append(indent)
+ .append("volumeType=")
+ .append(toVolumeTypeString(mVolumeType))
+ .append(", controlType=")
+ .append(toVolumeControlTypeString(mVolumeControlType))
+ .append(", max=")
+ .append(Integer.toString(mMaxVolume))
+ .append(", current=")
+ .append(Integer.toString(mCurrentVolume))
+ .append(", volumeControlId=")
+ .append(mVolumeControlId)
+ .println();
pw.println(indent + "metadata: " + mMetadataDescription);
pw.println(indent + "queueTitle=" + mQueueTitle + ", size="
+ (mQueue == null ? 0 : mQueue.size()));
}
+ private static String toVolumeControlTypeString(
+ @VolumeProvider.ControlType int volumeControlType) {
+ switch (volumeControlType) {
+ case VOLUME_CONTROL_FIXED:
+ return "FIXED";
+ case VOLUME_CONTROL_RELATIVE:
+ return "RELATIVE";
+ case VOLUME_CONTROL_ABSOLUTE:
+ return "ABSOLUTE";
+ default:
+ return TextUtils.formatSimple("unknown(%d)", volumeControlType);
+ }
+ }
+
+ private static String toVolumeTypeString(@PlaybackInfo.PlaybackType int volumeType) {
+ switch (volumeType) {
+ case PLAYBACK_TYPE_LOCAL:
+ return "LOCAL";
+ case PLAYBACK_TYPE_REMOTE:
+ return "REMOTE";
+ default:
+ return TextUtils.formatSimple("unknown(%d)", volumeType);
+ }
+ }
+
@Override
public String toString() {
return mPackageName + "/" + mTag + " (userId=" + mUserId + ")";
@@ -877,8 +918,8 @@
int stream = getVolumeStream(attributes);
int max = mAudioManager.getStreamMaxVolume(stream);
int current = mAudioManager.getStreamVolume(stream);
- return new PlaybackInfo(volumeType, VolumeProvider.VOLUME_CONTROL_ABSOLUTE, max,
- current, attributes, null);
+ return new PlaybackInfo(
+ volumeType, VOLUME_CONTROL_ABSOLUTE, max, current, attributes, null);
}
private final Runnable mClearOptimisticVolumeRunnable = new Runnable() {
@@ -1124,7 +1165,7 @@
boolean typeChanged;
synchronized (mLock) {
typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE;
- mVolumeType = PlaybackInfo.PLAYBACK_TYPE_LOCAL;
+ mVolumeType = PLAYBACK_TYPE_LOCAL;
mVolumeControlId = null;
if (attributes != null) {
mAudioAttrs = attributes;
@@ -1148,7 +1189,7 @@
throws RemoteException {
boolean typeChanged;
synchronized (mLock) {
- typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL;
+ typeChanged = mVolumeType == PLAYBACK_TYPE_LOCAL;
mVolumeType = PlaybackInfo.PLAYBACK_TYPE_REMOTE;
mVolumeControlType = control;
mMaxVolume = max;
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index a267e8a..5932929 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -4360,12 +4360,22 @@
// A new application appeared on /system, and we are seeing it for the first time.
// Its also not updated as we don't have a copy of it on /data. So, scan it in a
- // STOPPED state. Ignore if it's an APEX package since stopped state does not affect them.
+ // STOPPED state.
+ // We'll skip this step under the following conditions:
+ // - It's "android"
+ // - It's an APEX or overlay package since stopped state does not affect them.
+ // - It is enumerated with a <initial-package-state> tag having the stopped attribute
+ // set to false
final boolean isApexPkg = (scanFlags & SCAN_AS_APEX) != 0;
- if (mPm.mShouldStopSystemPackagesByDefault && scanSystemPartition
- && !pkgAlreadyExists && !isApexPkg) {
+ if (mPm.mShouldStopSystemPackagesByDefault
+ && scanSystemPartition
+ && !pkgAlreadyExists
+ && !isApexPkg
+ && !parsedPackage.isOverlayIsStatic()
+ ) {
String packageName = parsedPackage.getPackageName();
- if (!mPm.mInitialNonStoppedSystemPackages.contains(packageName)) {
+ if (!mPm.mInitialNonStoppedSystemPackages.contains(packageName)
+ && !"android".contentEquals(packageName)) {
scanFlags |= SCAN_AS_STOPPED_SYSTEM_APP;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b5108af..f482046 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5258,6 +5258,12 @@
}
@Override
+ public @NonNull List<String> getInitialNonStoppedSystemPackages() {
+ return mInitialNonStoppedSystemPackages != null
+ ? new ArrayList<>(mInitialNonStoppedSystemPackages) : new ArrayList<>();
+ }
+
+ @Override
public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) {
Objects.requireNonNull(packageNames, "packageNames cannot be null");
mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index f78b611..58183f0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -782,6 +782,8 @@
getInFileDescriptor(), getOutFileDescriptor(), getErrFileDescriptor(),
new String[] { "list" }, getShellCallback(), adoptResultReceiver());
return 0;
+ case "initial-non-stopped-system-packages":
+ return runListInitialNonStoppedSystemPackages();
}
pw.println("Error: unknown list type '" + type + "'");
return -1;
@@ -794,6 +796,21 @@
return 0;
}
+ private int runListInitialNonStoppedSystemPackages() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ final List<String> list = mInterface.getInitialNonStoppedSystemPackages();
+
+ Collections.sort(list);
+
+ for (String pkgName : list) {
+ pw.print("package:");
+ pw.print(pkgName);
+ pw.println();
+ }
+
+ return 0;
+ }
+
private int runListFeatures() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final List<FeatureInfo> list = mInterface.getSystemAvailableFeatures().getList();
diff --git a/services/core/java/com/android/server/pm/UserJourneyLogger.java b/services/core/java/com/android/server/pm/UserJourneyLogger.java
new file mode 100644
index 0000000..f48a166
--- /dev/null
+++ b/services/core/java/com/android/server/pm/UserJourneyLogger.java
@@ -0,0 +1,552 @@
+/*
+ * 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.pm;
+
+import static android.os.UserManager.USER_TYPE_FULL_DEMO;
+import static android.os.UserManager.USER_TYPE_FULL_GUEST;
+import static android.os.UserManager.USER_TYPE_FULL_RESTRICTED;
+import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
+import static android.os.UserManager.USER_TYPE_FULL_SYSTEM;
+import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
+import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
+import static android.os.UserManager.USER_TYPE_SYSTEM_HEADLESS;
+
+import static com.android.internal.util.FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNKNOWN;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.pm.UserInfo;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * This class is logging User Lifecycle statsd events and synchronise User Lifecycle Journeys
+ * by making sure all events are called in correct order and errors are reported in case of
+ * unexpected journeys. This class also makes sure that all user sub-journeys are logged so
+ * for example User Switch also log User Start Journey.
+ */
+public class UserJourneyLogger {
+
+ public static final int ERROR_CODE_INVALID_SESSION_ID = 0;
+ public static final int ERROR_CODE_UNSPECIFIED = -1;
+ /*
+ * Possible reasons for ERROR_CODE_INCOMPLETE_OR_TIMEOUT to occur:
+ * - A user switch journey is received while another user switch journey is in
+ * process for the same user.
+ * - A user switch journey is received while user start journey is in process for
+ * the same user.
+ * - A user start journey is received while another user start journey is in process
+ * for the same user.
+ * In all cases potentially an incomplete, timed-out session or multiple
+ * simultaneous requests. It is not possible to keep track of multiple sessions for
+ * the same user, so previous session is abandoned.
+ */
+ public static final int ERROR_CODE_INCOMPLETE_OR_TIMEOUT = 2;
+ public static final int ERROR_CODE_ABORTED = 3;
+ public static final int ERROR_CODE_NULL_USER_INFO = 4;
+ public static final int ERROR_CODE_USER_ALREADY_AN_ADMIN = 5;
+ public static final int ERROR_CODE_USER_IS_NOT_AN_ADMIN = 6;
+
+ @IntDef(prefix = {"ERROR_CODE"}, value = {
+ ERROR_CODE_UNSPECIFIED,
+ ERROR_CODE_INCOMPLETE_OR_TIMEOUT,
+ ERROR_CODE_ABORTED,
+ ERROR_CODE_NULL_USER_INFO,
+ ERROR_CODE_USER_ALREADY_AN_ADMIN,
+ ERROR_CODE_USER_IS_NOT_AN_ADMIN,
+ ERROR_CODE_INVALID_SESSION_ID
+ })
+ public @interface UserJourneyErrorCode {
+ }
+
+ // The various user journeys, defined in the UserLifecycleJourneyReported atom for statsd
+ public static final int USER_JOURNEY_UNKNOWN =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__UNKNOWN;
+ public static final int USER_JOURNEY_USER_SWITCH_FG =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_SWITCH_FG;
+ public static final int USER_JOURNEY_USER_SWITCH_UI =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_SWITCH_UI;
+ public static final int USER_JOURNEY_USER_START =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_START;
+ public static final int USER_JOURNEY_USER_CREATE =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE;
+ public static final int USER_JOURNEY_USER_STOP =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_STOP;
+ public static final int USER_JOURNEY_USER_REMOVE =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_REMOVE;
+ public static final int USER_JOURNEY_GRANT_ADMIN =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN;
+ public static final int USER_JOURNEY_REVOKE_ADMIN =
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN;
+
+ @IntDef(prefix = {"USER_JOURNEY"}, value = {
+ USER_JOURNEY_UNKNOWN,
+ USER_JOURNEY_USER_SWITCH_FG,
+ USER_JOURNEY_USER_SWITCH_UI,
+ USER_JOURNEY_USER_START,
+ USER_JOURNEY_USER_STOP,
+ USER_JOURNEY_USER_CREATE,
+ USER_JOURNEY_USER_REMOVE,
+ USER_JOURNEY_GRANT_ADMIN,
+ USER_JOURNEY_REVOKE_ADMIN
+ })
+ public @interface UserJourney {
+ }
+
+
+ // The various user lifecycle events, defined in the UserLifecycleEventOccurred atom for statsd
+ public static final int USER_LIFECYCLE_EVENT_UNKNOWN =
+ USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNKNOWN;
+ public static final int USER_LIFECYCLE_EVENT_SWITCH_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__SWITCH_USER;
+ public static final int USER_LIFECYCLE_EVENT_START_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__START_USER;
+ public static final int USER_LIFECYCLE_EVENT_CREATE_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__CREATE_USER;
+ public static final int USER_LIFECYCLE_EVENT_REMOVE_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REMOVE_USER;
+ public static final int USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__USER_RUNNING_LOCKED;
+ public static final int USER_LIFECYCLE_EVENT_UNLOCKING_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNLOCKING_USER;
+ public static final int USER_LIFECYCLE_EVENT_UNLOCKED_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNLOCKED_USER;
+ public static final int USER_LIFECYCLE_EVENT_STOP_USER =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__STOP_USER;
+ public static final int USER_LIFECYCLE_EVENT_GRANT_ADMIN =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__GRANT_ADMIN;
+ public static final int USER_LIFECYCLE_EVENT_REVOKE_ADMIN =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REVOKE_ADMIN;
+
+ @IntDef(prefix = {"USER_LIFECYCLE_EVENT"}, value = {
+ USER_LIFECYCLE_EVENT_UNKNOWN,
+ USER_LIFECYCLE_EVENT_SWITCH_USER,
+ USER_LIFECYCLE_EVENT_START_USER,
+ USER_LIFECYCLE_EVENT_CREATE_USER,
+ USER_LIFECYCLE_EVENT_REMOVE_USER,
+ USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED,
+ USER_LIFECYCLE_EVENT_UNLOCKING_USER,
+ USER_LIFECYCLE_EVENT_UNLOCKED_USER,
+ USER_LIFECYCLE_EVENT_STOP_USER,
+ USER_LIFECYCLE_EVENT_GRANT_ADMIN,
+ USER_LIFECYCLE_EVENT_REVOKE_ADMIN
+ })
+ public @interface UserLifecycleEvent {
+ }
+
+ // User lifecycle event state, defined in the UserLifecycleEventOccurred atom for statsd
+ public static final int EVENT_STATE_BEGIN =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__BEGIN;
+ public static final int EVENT_STATE_FINISH =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__FINISH;
+ public static final int EVENT_STATE_NONE =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__NONE;
+ public static final int EVENT_STATE_CANCEL =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__CANCEL;
+ public static final int EVENT_STATE_ERROR =
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__ERROR;
+
+ @IntDef(prefix = {"EVENT_STATE"}, value = {
+ EVENT_STATE_BEGIN,
+ EVENT_STATE_FINISH,
+ EVENT_STATE_NONE,
+ EVENT_STATE_CANCEL,
+ EVENT_STATE_ERROR,
+ })
+ public @interface UserLifecycleEventState {
+ }
+
+ private static final int USER_ID_KEY_MULTIPLICATION = 100;
+
+ private final Object mLock = new Object();
+
+ /**
+ * {@link UserIdInt} and {@link UserJourney} to {@link UserJourneySession} mapping used for
+ * statsd logging for the UserLifecycleJourneyReported and UserLifecycleEventOccurred atoms.
+ */
+ @GuardedBy("mLock")
+ private final SparseArray<UserJourneySession> mUserIdToUserJourneyMap = new SparseArray<>();
+
+ /**
+ * Returns event equivalent of given journey
+ */
+ @UserLifecycleEvent
+ private static int journeyToEvent(@UserJourney int journey) {
+ switch (journey) {
+ case USER_JOURNEY_USER_SWITCH_UI:
+ case USER_JOURNEY_USER_SWITCH_FG:
+ return USER_LIFECYCLE_EVENT_SWITCH_USER;
+ case USER_JOURNEY_USER_START:
+ return USER_LIFECYCLE_EVENT_START_USER;
+ case USER_JOURNEY_USER_CREATE:
+ return USER_LIFECYCLE_EVENT_CREATE_USER;
+ case USER_JOURNEY_USER_STOP:
+ return USER_LIFECYCLE_EVENT_STOP_USER;
+ case USER_JOURNEY_USER_REMOVE:
+ return USER_LIFECYCLE_EVENT_REMOVE_USER;
+ case USER_JOURNEY_GRANT_ADMIN:
+ return USER_LIFECYCLE_EVENT_GRANT_ADMIN;
+ case USER_JOURNEY_REVOKE_ADMIN:
+ return USER_LIFECYCLE_EVENT_REVOKE_ADMIN;
+ default:
+ return USER_LIFECYCLE_EVENT_UNKNOWN;
+ }
+ }
+
+ /**
+ * Returns the enum defined in the statsd UserLifecycleJourneyReported atom corresponding to
+ * the user type.
+ * Changes to this method require changes in CTS file
+ * com.android.cts.packagemanager.stats.device.UserInfoUtil
+ * which is duplicate for CTS tests purposes.
+ */
+ public static int getUserTypeForStatsd(@NonNull String userType) {
+ switch (userType) {
+ case USER_TYPE_FULL_SYSTEM:
+ return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SYSTEM;
+ case USER_TYPE_FULL_SECONDARY:
+ return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY;
+ case USER_TYPE_FULL_GUEST:
+ return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_GUEST;
+ case USER_TYPE_FULL_DEMO:
+ return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_DEMO;
+ case USER_TYPE_FULL_RESTRICTED:
+ return FrameworkStatsLog
+ .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_RESTRICTED;
+ case USER_TYPE_PROFILE_MANAGED:
+ return FrameworkStatsLog
+ .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__PROFILE_MANAGED;
+ case USER_TYPE_SYSTEM_HEADLESS:
+ return FrameworkStatsLog
+ .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__SYSTEM_HEADLESS;
+ case USER_TYPE_PROFILE_CLONE:
+ return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__PROFILE_CLONE;
+ default:
+ return FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN;
+ }
+ }
+
+ /**
+ * Map error code to the event finish state.
+ */
+ @UserLifecycleEventState
+ private static int errorToFinishState(@UserJourneyErrorCode int errorCode) {
+ switch (errorCode) {
+ case ERROR_CODE_ABORTED:
+ return EVENT_STATE_CANCEL;
+ case ERROR_CODE_UNSPECIFIED:
+ return EVENT_STATE_FINISH;
+ default:
+ return EVENT_STATE_ERROR;
+ }
+ }
+
+ /**
+ * Simply logging USER_LIFECYCLE_JOURNEY_REPORTED if session exists.
+ * If session does not exist then it logs ERROR_CODE_INVALID_SESSION_ID
+ */
+ @VisibleForTesting
+ public void logUserLifecycleJourneyReported(@Nullable UserJourneySession session,
+ @UserJourney int journey, @UserIdInt int originalUserId, @UserIdInt int targetUserId,
+ int userType, int userFlags, @UserJourneyErrorCode int errorCode) {
+ if (session == null) {
+ writeUserLifecycleJourneyReported(-1, journey, originalUserId, targetUserId,
+ userType, userFlags, ERROR_CODE_INVALID_SESSION_ID);
+ } else {
+ writeUserLifecycleJourneyReported(
+ session.mSessionId, journey, originalUserId, targetUserId, userType, userFlags,
+ errorCode);
+ }
+ }
+
+ /**
+ * Helper method for spy testing
+ */
+ @VisibleForTesting
+ public void writeUserLifecycleJourneyReported(long sessionId, int journey, int originalUserId,
+ int targetUserId, int userType, int userFlags, int errorCode) {
+ FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED,
+ sessionId, journey, originalUserId, targetUserId, userType, userFlags,
+ errorCode);
+ }
+
+ /**
+ * Simply logging USER_LIFECYCLE_EVENT_OCCURRED if session exists.
+ * If session does not exist then it logs ERROR_CODE_INVALID_SESSION_ID
+ * and EVENT_STATE_ERROR
+ */
+ @VisibleForTesting
+ public void logUserLifecycleEventOccurred(UserJourneySession session,
+ @UserIdInt int targetUserId, @UserLifecycleEvent int event,
+ @UserLifecycleEventState int state, @UserJourneyErrorCode int errorCode) {
+ if (session == null) {
+ writeUserLifecycleEventOccurred(-1, targetUserId, event,
+ EVENT_STATE_ERROR, ERROR_CODE_INVALID_SESSION_ID);
+ } else {
+ writeUserLifecycleEventOccurred(session.mSessionId, targetUserId, event, state,
+ errorCode);
+ }
+ }
+
+ /**
+ * Helper method for spy testing
+ */
+ @VisibleForTesting
+ public void writeUserLifecycleEventOccurred(long sessionId, int userId, int event, int state,
+ int errorCode) {
+ FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED,
+ sessionId, userId, event, state, errorCode);
+ }
+
+ /**
+ * statsd helper method for logging the given event for the UserLifecycleEventOccurred statsd
+ * atom. It finds the user journey session for target user id and logs it as that journey.
+ */
+ public void logUserLifecycleEvent(@UserIdInt int userId, @UserLifecycleEvent int event,
+ @UserLifecycleEventState int eventState) {
+ final UserJourneySession userJourneySession = findUserJourneySession(userId);
+ logUserLifecycleEventOccurred(userJourneySession, userId,
+ event, eventState, UserJourneyLogger.ERROR_CODE_UNSPECIFIED);
+ }
+
+ /**
+ * Returns first user session from mUserIdToUserJourneyMap for given user id,
+ * or null if user id was not found in mUserIdToUserJourneyMap.
+ */
+ private @Nullable UserJourneySession findUserJourneySession(@UserIdInt int userId) {
+ synchronized (mLock) {
+ final int keyMapSize = mUserIdToUserJourneyMap.size();
+ for (int i = 0; i < keyMapSize; i++) {
+ int key = mUserIdToUserJourneyMap.keyAt(i);
+ if (key / USER_ID_KEY_MULTIPLICATION == userId) {
+ return mUserIdToUserJourneyMap.get(key);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns unique id for user and journey. For example if user id = 11 and journey = 7
+ * then unique key = 11 * 100 + 7 = 1107
+ */
+ private int getUserJourneyKey(@UserIdInt int targetUserId, @UserJourney int journey) {
+ // We leave 99 for user journeys ids.
+ return (targetUserId * USER_ID_KEY_MULTIPLICATION) + journey;
+ }
+
+ /**
+ * Special use case when user journey incomplete or timeout and current user is unclear
+ */
+ @VisibleForTesting
+ public UserJourneySession finishAndClearIncompleteUserJourney(@UserIdInt int targetUserId,
+ @UserJourney int journey) {
+ synchronized (mLock) {
+ final int key = getUserJourneyKey(targetUserId, journey);
+ final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(key);
+ if (userJourneySession != null) {
+ logUserLifecycleEventOccurred(
+ userJourneySession,
+ targetUserId,
+ journeyToEvent(userJourneySession.mJourney),
+ EVENT_STATE_ERROR,
+ UserJourneyLogger.ERROR_CODE_INCOMPLETE_OR_TIMEOUT);
+
+ logUserLifecycleJourneyReported(
+ userJourneySession,
+ journey,
+ /* originalUserId= */ -1,
+ targetUserId,
+ getUserTypeForStatsd(""), -1,
+ ERROR_CODE_INCOMPLETE_OR_TIMEOUT);
+ mUserIdToUserJourneyMap.remove(key);
+
+ return userJourneySession;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Log user journey event and report finishing without error
+ */
+ public UserJourneySession logUserJourneyFinish(@UserIdInt int originalUserId,
+ UserInfo targetUser, @UserJourney int journey) {
+ return logUserJourneyFinishWithError(originalUserId, targetUser, journey,
+ ERROR_CODE_UNSPECIFIED);
+ }
+
+ /**
+ * Special case when it is unknown which user switch journey was used and checking both
+ */
+ @VisibleForTesting
+ public UserJourneySession logUserSwitchJourneyFinish(@UserIdInt int originalUserId,
+ UserInfo targetUser) {
+ synchronized (mLock) {
+ final int key_fg = getUserJourneyKey(targetUser.id, USER_JOURNEY_USER_SWITCH_FG);
+ final int key_ui = getUserJourneyKey(targetUser.id, USER_JOURNEY_USER_SWITCH_UI);
+
+ if (mUserIdToUserJourneyMap.contains(key_fg)) {
+ return logUserJourneyFinish(originalUserId, targetUser,
+ USER_JOURNEY_USER_SWITCH_FG);
+ }
+
+ if (mUserIdToUserJourneyMap.contains(key_ui)) {
+ return logUserJourneyFinish(originalUserId, targetUser,
+ USER_JOURNEY_USER_SWITCH_UI);
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * Log user journey event and report finishing with error
+ */
+ public UserJourneySession logUserJourneyFinishWithError(@UserIdInt int originalUserId,
+ UserInfo targetUser, @UserJourney int journey, @UserJourneyErrorCode int errorCode) {
+ synchronized (mLock) {
+ final int state = errorToFinishState(errorCode);
+ final int key = getUserJourneyKey(targetUser.id, journey);
+ final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(key);
+ if (userJourneySession != null) {
+ logUserLifecycleEventOccurred(
+ userJourneySession, targetUser.id,
+ journeyToEvent(userJourneySession.mJourney),
+ state,
+ errorCode);
+
+ logUserLifecycleJourneyReported(
+ userJourneySession,
+ journey, originalUserId, targetUser.id,
+ getUserTypeForStatsd(targetUser.userType),
+ targetUser.flags,
+ errorCode);
+ mUserIdToUserJourneyMap.remove(key);
+
+ return userJourneySession;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Log event and report finish when user is null. This is edge case when UserInfo
+ * can not be passed because it is null, therefore all information are passed as arguments.
+ */
+ public UserJourneySession logNullUserJourneyError(@UserJourney int journey,
+ @UserIdInt int currentUserId, @UserIdInt int targetUserId, String targetUserType,
+ int targetUserFlags) {
+ synchronized (mLock) {
+ final int key = getUserJourneyKey(targetUserId, journey);
+ final UserJourneySession session = mUserIdToUserJourneyMap.get(key);
+
+ logUserLifecycleEventOccurred(
+ session, targetUserId, journeyToEvent(journey),
+ EVENT_STATE_ERROR,
+ ERROR_CODE_NULL_USER_INFO);
+
+ logUserLifecycleJourneyReported(
+ session, journey, currentUserId, targetUserId,
+ getUserTypeForStatsd(targetUserType), targetUserFlags,
+ ERROR_CODE_NULL_USER_INFO);
+
+ mUserIdToUserJourneyMap.remove(key);
+ return session;
+ }
+ }
+
+ /**
+ * Log for user creation finish event and report. This is edge case when target user id is
+ * different in begin event and finish event as it is unknown what is user id
+ * until it has been created.
+ */
+ public UserJourneySession logUserCreateJourneyFinish(@UserIdInt int originalUserId,
+ UserInfo targetUser) {
+ synchronized (mLock) {
+ // we do not know user id until we create new user which is why we use -1
+ // as user id to create and find session, but we log correct id.
+ final int key = getUserJourneyKey(-1, USER_JOURNEY_USER_CREATE);
+ final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(key);
+ if (userJourneySession != null) {
+ logUserLifecycleEventOccurred(
+ userJourneySession, targetUser.id,
+ USER_LIFECYCLE_EVENT_CREATE_USER,
+ EVENT_STATE_FINISH,
+ ERROR_CODE_UNSPECIFIED);
+
+ logUserLifecycleJourneyReported(
+ userJourneySession,
+ USER_JOURNEY_USER_CREATE, originalUserId, targetUser.id,
+ getUserTypeForStatsd(targetUser.userType),
+ targetUser.flags,
+ ERROR_CODE_UNSPECIFIED);
+ mUserIdToUserJourneyMap.remove(key);
+
+ return userJourneySession;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Adds new UserJourneySession to mUserIdToUserJourneyMap and log UserJourneyEvent Begin state
+ */
+ public UserJourneySession logUserJourneyBegin(@UserIdInt int targetId,
+ @UserJourney int journey) {
+ final long newSessionId = ThreadLocalRandom.current().nextLong(1, Long.MAX_VALUE);
+ synchronized (mLock) {
+ final int key = getUserJourneyKey(targetId, journey);
+ final UserJourneySession userJourneySession =
+ new UserJourneySession(newSessionId, journey);
+ mUserIdToUserJourneyMap.append(key, userJourneySession);
+
+ logUserLifecycleEventOccurred(
+ userJourneySession, targetId,
+ journeyToEvent(userJourneySession.mJourney),
+ EVENT_STATE_BEGIN,
+ ERROR_CODE_UNSPECIFIED);
+
+ return userJourneySession;
+ }
+ }
+
+ /**
+ * Helper class to store user journey and session id.
+ *
+ * <p> User journey tracks a chain of user lifecycle events occurring during different user
+ * activities such as user start, user switch, and user creation.
+ */
+ public static class UserJourneySession {
+ public final long mSessionId;
+ @UserJourney
+ public final int mJourney;
+
+ @VisibleForTesting
+ public UserJourneySession(long sessionId, @UserJourney int journey) {
+ mJourney = journey;
+ mSessionId = sessionId;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 5f8efe2..b92cdde 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -23,6 +23,15 @@
import static android.os.UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY;
import static android.os.UserManager.USER_OPERATION_ERROR_UNKNOWN;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_ABORTED;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_UNSPECIFIED;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_USER_ALREADY_AN_ADMIN;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_USER_IS_NOT_AN_ADMIN;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_GRANT_ADMIN;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_REVOKE_ADMIN;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_CREATE;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_REMOVE;
+
import android.Manifest;
import android.accounts.Account;
import android.accounts.AccountManager;
@@ -162,7 +171,6 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -519,6 +527,8 @@
@GuardedBy("mUserLifecycleListeners")
private final ArrayList<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
+ private final UserJourneyLogger mUserJourneyLogger = new UserJourneyLogger();
+
private final LockPatternUtils mLockPatternUtils;
private final String ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK =
@@ -1580,45 +1590,56 @@
@Override
public void setUserAdmin(@UserIdInt int userId) {
checkManageUserAndAcrossUsersFullPermission("set user admin");
- final long sessionId = logGrantAdminJourneyBegin(userId);
+ mUserJourneyLogger.logUserJourneyBegin(userId, USER_JOURNEY_GRANT_ADMIN);
UserInfo info;
synchronized (mPackagesLock) {
synchronized (mUsersLock) {
info = getUserInfoLU(userId);
}
- if (info == null || info.isAdmin()) {
- // Exit if no user found with that id, or the user is already an Admin.
- logUserJourneyError(sessionId,
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN,
- userId);
+ if (info == null) {
+ // Exit if no user found with that id,
+ mUserJourneyLogger.logNullUserJourneyError(USER_JOURNEY_GRANT_ADMIN,
+ getCurrentUserId(), userId, /* userType */ "", /* userFlags */ -1);
+ return;
+ } else if (info.isAdmin()) {
+ // Exit if the user is already an Admin.
+ mUserJourneyLogger.logUserJourneyFinishWithError(getCurrentUserId(), info,
+ USER_JOURNEY_GRANT_ADMIN, ERROR_CODE_USER_ALREADY_AN_ADMIN);
return;
}
info.flags ^= UserInfo.FLAG_ADMIN;
writeUserLP(getUserDataLU(info.id));
}
- logGrantAdminJourneyFinish(sessionId, userId, info.userType, info.flags);
+ mUserJourneyLogger.logUserJourneyFinishWithError(getCurrentUserId(), info,
+ USER_JOURNEY_GRANT_ADMIN, ERROR_CODE_UNSPECIFIED);
}
@Override
public void revokeUserAdmin(@UserIdInt int userId) {
checkManageUserAndAcrossUsersFullPermission("revoke admin privileges");
- final long sessionId = logRevokeAdminJourneyBegin(userId);
+ mUserJourneyLogger.logUserJourneyBegin(userId, USER_JOURNEY_REVOKE_ADMIN);
UserData user;
synchronized (mPackagesLock) {
synchronized (mUsersLock) {
user = getUserDataLU(userId);
- if (user == null || !user.info.isAdmin()) {
- // Exit if no user found with that id, or the user is not an Admin.
- logUserJourneyError(sessionId, FrameworkStatsLog
- .USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN,
- userId);
+ if (user == null) {
+ // Exit if no user found with that id
+ mUserJourneyLogger.logNullUserJourneyError(
+ USER_JOURNEY_REVOKE_ADMIN,
+ getCurrentUserId(), userId, "", -1);
+ return;
+ } else if (!user.info.isAdmin()) {
+ // Exit if no user is not an Admin.
+ mUserJourneyLogger.logUserJourneyFinishWithError(getCurrentUserId(), user.info,
+ USER_JOURNEY_REVOKE_ADMIN, ERROR_CODE_USER_IS_NOT_AN_ADMIN);
return;
}
user.info.flags ^= UserInfo.FLAG_ADMIN;
writeUserLP(user);
}
}
- logRevokeAdminJourneyFinish(sessionId, userId, user.info.userType, user.info.flags);
+ mUserJourneyLogger.logUserJourneyFinishWithError(getCurrentUserId(), user.info,
+ USER_JOURNEY_REVOKE_ADMIN, ERROR_CODE_UNSPECIFIED);
}
/**
@@ -4700,16 +4721,20 @@
final int noneUserId = -1;
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("createUser-" + flags);
- final long sessionId = logUserCreateJourneyBegin(noneUserId);
+ mUserJourneyLogger.logUserJourneyBegin(noneUserId, USER_JOURNEY_USER_CREATE);
UserInfo newUser = null;
try {
newUser = createUserInternalUncheckedNoTracing(name, userType, flags, parentId,
preCreate, disallowedPackages, t, token);
return newUser;
} finally {
- logUserCreateJourneyFinish(sessionId,
- newUser != null ? newUser.id : noneUserId, userType, flags,
- newUser != null);
+ if (newUser != null) {
+ mUserJourneyLogger.logUserCreateJourneyFinish(getCurrentUserId(), newUser);
+ } else {
+ mUserJourneyLogger.logNullUserJourneyError(
+ USER_JOURNEY_USER_CREATE,
+ getCurrentUserId(), noneUserId, userType, flags);
+ }
t.traceEnd();
}
}
@@ -5198,137 +5223,6 @@
&& !userTypeDetails.getName().equals(UserManager.USER_TYPE_FULL_RESTRICTED);
}
- private long logUserCreateJourneyBegin(@UserIdInt int userId) {
- return logUserJourneyBegin(
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE,
- userId);
- }
-
- private void logUserCreateJourneyFinish(long sessionId, @UserIdInt int userId, String userType,
- @UserInfoFlag int flags, boolean finish) {
- logUserJourneyFinish(sessionId,
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE,
- userId, userType, flags, finish);
- }
-
- private long logUserRemoveJourneyBegin(@UserIdInt int userId) {
- return logUserJourneyBegin(
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_REMOVE,
- userId);
- }
-
- private void logUserRemoveJourneyFinish(long sessionId, @UserIdInt int userId, String userType,
- @UserInfoFlag int flags, boolean finish) {
- logUserJourneyFinish(sessionId,
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_REMOVE,
- userId, userType, flags, finish);
- }
-
- private long logGrantAdminJourneyBegin(@UserIdInt int userId) {
- return logUserJourneyBegin(
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN,
- userId);
- }
-
- private void logGrantAdminJourneyFinish(long sessionId, @UserIdInt int userId, String userType,
- @UserInfoFlag int flags) {
- logUserJourneyFinish(sessionId,
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN,
- userId, userType, flags, true);
- }
-
- private long logRevokeAdminJourneyBegin(@UserIdInt int userId) {
- return logUserJourneyBegin(
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN,
- userId);
- }
-
- private void logRevokeAdminJourneyFinish(long sessionId, @UserIdInt int userId, String userType,
- @UserInfoFlag int flags) {
- logUserJourneyFinish(sessionId,
- FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN,
- userId, userType, flags, true);
- }
-
- private void logUserJourneyFinish(long sessionId, int journey, @UserIdInt int userId,
- String userType, @UserInfoFlag int flags, boolean finish) {
-
- // log the journey atom with the user metadata
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED, sessionId,
- journey, /* origin_user= */ getCurrentUserId(), userId,
- UserManager.getUserTypeForStatsd(userType), flags);
-
- int event;
- switch (journey) {
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__CREATE_USER;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_REMOVE:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REMOVE_USER;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__GRANT_ADMIN;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REVOKE_ADMIN;
- break;
- default:
- throw new IllegalArgumentException("Journey " + journey + " not expected.");
- }
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED, sessionId, userId,
- event,
- finish ? FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__FINISH
- : FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__NONE);
- }
-
- private long logUserJourneyBegin(int journey, @UserIdInt int userId) {
- final long sessionId = ThreadLocalRandom.current().nextLong(1, Long.MAX_VALUE);
-
- // log the event atom to indicate the event start
- int event;
- switch (journey) {
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__CREATE_USER;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_REMOVE:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REMOVE_USER;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__GRANT_ADMIN;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REVOKE_ADMIN;
- break;
- default:
- throw new IllegalArgumentException("Journey " + journey + " not expected.");
- }
-
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED, sessionId, userId,
- event, FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__BEGIN);
- return sessionId;
- }
-
- private void logUserJourneyError(long sessionId, int journey, @UserIdInt int userId) {
-
- // log the journey atom with the user metadata
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED, sessionId,
- journey, /* origin_user= */ getCurrentUserId(), userId);
-
- int event;
- switch (journey) {
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__GRANT_ADMIN:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__GRANT_ADMIN;
- break;
- case FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN:
- event = FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__REVOKE_ADMIN;
- break;
- default:
- throw new IllegalArgumentException("Journey " + journey + " not expected.");
- }
- FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED, sessionId, userId,
- event, FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__ERROR);
- }
-
/** Register callbacks for statsd pulled atoms. */
private void registerStatsCallbacks() {
final StatsManager statsManager = mContext.getSystemService(StatsManager.class);
@@ -5352,7 +5246,8 @@
if (size > 1) {
for (int idx = 0; idx < size; idx++) {
final UserInfo user = users.get(idx);
- final int userTypeStandard = UserManager.getUserTypeForStatsd(user.userType);
+ final int userTypeStandard = mUserJourneyLogger
+ .getUserTypeForStatsd(user.userType);
final String userTypeCustom = (userTypeStandard == FrameworkStatsLog
.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN)
?
@@ -5635,7 +5530,7 @@
writeUserLP(userData);
}
- final long sessionId = logUserRemoveJourneyBegin(userId);
+ mUserJourneyLogger.logUserJourneyBegin(userId, USER_JOURNEY_USER_REMOVE);
try {
mAppOpsService.removeUser(userId);
@@ -5657,13 +5552,17 @@
@Override
public void userStopped(int userIdParam) {
finishRemoveUser(userIdParam);
- logUserRemoveJourneyFinish(sessionId, userIdParam,
- userData.info.userType, userData.info.flags, true);
+ int originUserId = UserManagerService.this.getCurrentUserId();
+ mUserJourneyLogger.logUserJourneyFinishWithError(originUserId,
+ userData.info, USER_JOURNEY_USER_REMOVE,
+ ERROR_CODE_UNSPECIFIED);
}
@Override
public void userStopAborted(int userIdParam) {
- logUserRemoveJourneyFinish(sessionId, userIdParam,
- userData.info.userType, userData.info.flags, false);
+ int originUserId = UserManagerService.this.getCurrentUserId();
+ mUserJourneyLogger.logUserJourneyFinishWithError(originUserId,
+ userData.info, USER_JOURNEY_USER_REMOVE,
+ ERROR_CODE_ABORTED);
}
});
} catch (RemoteException e) {
@@ -7297,9 +7196,9 @@
final UserInfo userInfo = getUserInfo(userIds[i]);
if (userInfo == null) {
// Not possible because the input user ids should all be valid
- userTypes[i] = UserManager.getUserTypeForStatsd("");
+ userTypes[i] = mUserJourneyLogger.getUserTypeForStatsd("");
} else {
- userTypes[i] = UserManager.getUserTypeForStatsd(userInfo.userType);
+ userTypes[i] = mUserJourneyLogger.getUserTypeForStatsd(userInfo.userType);
}
}
return userTypes;
@@ -7536,4 +7435,11 @@
.getBoolean(R.bool.config_canSwitchToHeadlessSystemUser);
}
+ /**
+ * Returns instance of {@link com.android.server.pm.UserJourneyLogger}.
+ */
+ public UserJourneyLogger getUserJourneyLogger() {
+ return mUserJourneyLogger;
+ }
+
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9ff98be..f8954b7 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -5690,8 +5690,14 @@
}
if (eventTime > now) {
- Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now);
- throw new IllegalArgumentException("event time must not be in the future");
+ Slog.wtf(TAG, "Event cannot be newer than the current time ("
+ + "now=" + now
+ + ", eventTime=" + eventTime
+ + ", displayId=" + displayId
+ + ", event=" + PowerManager.userActivityEventToString(event)
+ + ", flags=" + flags
+ + ")");
+ return;
}
final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 24a271f..26b40b4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -582,6 +582,9 @@
boolean mPauseSchedulePendingForPip = false;
+ // Gets set to indicate that the activity is currently being auto-pipped.
+ boolean mAutoEnteringPip = false;
+
private void updateEnterpriseThumbnailDrawable(Context context) {
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
mEnterpriseThumbnailDrawable = dpm.getResources().getDrawable(
@@ -6099,8 +6102,7 @@
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
PauseActivityItem.obtain(finishing, false /* userLeaving */,
- configChangeFlags, false /* dontReport */,
- false /* autoEnteringPip */));
+ configChangeFlags, false /* dontReport */, mAutoEnteringPip));
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a0ea1c3..b816dad 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3592,15 +3592,21 @@
}
}
+ boolean enterPictureInPictureMode(@NonNull ActivityRecord r,
+ @NonNull PictureInPictureParams params, boolean fromClient) {
+ return enterPictureInPictureMode(r, params, fromClient, false /* isAutoEnter */);
+ }
+
/**
* Puts the given activity in picture in picture mode if possible.
*
* @param fromClient true if this comes from a client call (eg. Activity.enterPip).
+ * @param isAutoEnter true if this comes from an automatic pip-enter.
* @return true if the activity is now in picture-in-picture mode, or false if it could not
* enter picture-in-picture mode.
*/
boolean enterPictureInPictureMode(@NonNull ActivityRecord r,
- @NonNull PictureInPictureParams params, boolean fromClient) {
+ @NonNull PictureInPictureParams params, boolean fromClient, boolean isAutoEnter) {
// If the activity is already in picture in picture mode, then just return early
if (r.inPinnedWindowingMode()) {
return true;
@@ -3635,6 +3641,7 @@
return;
}
r.setPictureInPictureParams(params);
+ r.mAutoEnteringPip = isAutoEnter;
mRootWindowContainer.moveActivityToPinnedRootTask(r,
null /* launchIntoPipHostActivity */, "enterPictureInPictureMode",
transition);
@@ -3643,6 +3650,7 @@
r.getTask().schedulePauseActivity(r, false /* userLeaving */,
false /* pauseImmediately */, true /* autoEnteringPip */, "auto-pip");
}
+ r.mAutoEnteringPip = false;
}
};
@@ -6328,6 +6336,8 @@
public void cleanupDisabledPackageComponents(
String packageName, Set<String> disabledClasses, int userId, boolean booted) {
synchronized (mGlobalLock) {
+ // In case if setWindowManager hasn't been called yet when booting.
+ if (mRootWindowContainer == null) return;
// Clean-up disabled activities.
if (mRootWindowContainer.finishDisabledPackageActivities(
packageName, disabledClasses, true /* doit */, false /* evenPersistent */,
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 2edb082..7852249 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -20,41 +20,73 @@
import static com.android.internal.R.bool.config_unfoldTransitionEnabled;
import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
+import static com.android.server.wm.DeviceStateController.DeviceState.FOLDED;
+import static com.android.server.wm.DeviceStateController.DeviceState.HALF_FOLDED;
+import static com.android.server.wm.DeviceStateController.DeviceState.OPEN;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
import android.graphics.Rect;
import android.window.DisplayAreaInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.DeviceStateController.DeviceState;
+
public class PhysicalDisplaySwitchTransitionLauncher {
private final DisplayContent mDisplayContent;
- private final WindowManagerService mService;
+ private final ActivityTaskManagerService mAtmService;
+ private final Context mContext;
private final TransitionController mTransitionController;
/**
- * If on a foldable device represents whether the device is folded or not
+ * If on a foldable device represents whether we need to show unfold animation when receiving
+ * a physical display switch event
*/
- private boolean mIsFolded;
+ private boolean mShouldRequestTransitionOnDisplaySwitch = false;
+ /**
+ * Current device state from {@link android.hardware.devicestate.DeviceStateManager}
+ */
+ private DeviceState mDeviceState = DeviceState.UNKNOWN;
private Transition mTransition;
public PhysicalDisplaySwitchTransitionLauncher(DisplayContent displayContent,
TransitionController transitionController) {
+ this(displayContent, displayContent.mWmService.mAtmService,
+ displayContent.mWmService.mContext, transitionController);
+ }
+
+ @VisibleForTesting
+ public PhysicalDisplaySwitchTransitionLauncher(DisplayContent displayContent,
+ ActivityTaskManagerService service, Context context,
+ TransitionController transitionController) {
mDisplayContent = displayContent;
- mService = displayContent.mWmService;
+ mAtmService = service;
+ mContext = context;
mTransitionController = transitionController;
}
/**
* Called by the DeviceStateManager callback when the state changes.
*/
- void foldStateChanged(DeviceStateController.DeviceState newDeviceState) {
- // Ignore transitions to/from half-folded.
- if (newDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) return;
- mIsFolded = newDeviceState == DeviceStateController.DeviceState.FOLDED;
+ void foldStateChanged(DeviceState newDeviceState) {
+ boolean isUnfolding = mDeviceState == FOLDED
+ && (newDeviceState == HALF_FOLDED || newDeviceState == OPEN);
+
+ if (isUnfolding) {
+ // Request transition only if we are unfolding the device
+ mShouldRequestTransitionOnDisplaySwitch = true;
+ } else if (newDeviceState != HALF_FOLDED && newDeviceState != OPEN) {
+ // Cancel the transition request in case if we are folding or switching to back
+ // to the rear display before the displays got switched
+ mShouldRequestTransitionOnDisplaySwitch = false;
+ }
+
+ mDeviceState = newDeviceState;
}
/**
@@ -62,12 +94,12 @@
*/
public void requestDisplaySwitchTransitionIfNeeded(int displayId, int oldDisplayWidth,
int oldDisplayHeight, int newDisplayWidth, int newDisplayHeight) {
+ if (!mShouldRequestTransitionOnDisplaySwitch) return;
if (!mTransitionController.isShellTransitionsEnabled()) return;
if (!mDisplayContent.getLastHasContent()) return;
- boolean shouldRequestUnfoldTransition = !mIsFolded
- && mService.mContext.getResources().getBoolean(config_unfoldTransitionEnabled)
- && ValueAnimator.areAnimatorsEnabled();
+ boolean shouldRequestUnfoldTransition = mContext.getResources()
+ .getBoolean(config_unfoldTransitionEnabled) && ValueAnimator.areAnimatorsEnabled();
if (!shouldRequestUnfoldTransition) {
return;
@@ -91,6 +123,8 @@
mDisplayContent.mAtmService.startLaunchPowerMode(POWER_MODE_REASON_CHANGE_DISPLAY);
mTransition = t;
}
+
+ mShouldRequestTransitionOnDisplaySwitch = false;
}
/**
@@ -118,7 +152,7 @@
if (mTransition == null) return;
if (transaction != null) {
- mService.mAtmService.mWindowOrganizerController.applyTransaction(transaction);
+ mAtmService.mWindowOrganizerController.applyTransaction(transaction);
}
markTransitionAsReady();
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 80f918b..50bf38b 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -963,7 +963,7 @@
return false;
}
return mController.mAtm.enterPictureInPictureMode(ar, ar.pictureInPictureArgs,
- false /* fromClient */);
+ false /* fromClient */, true /* isAutoEnter */);
}
// Legacy pip-entry (not via isAutoEnterEnabled).
@@ -2267,7 +2267,7 @@
// Display won't be rotated for multi window Task, so the fixed rotation
// won't be applied. This can happen when the windowing mode is changed
// before the previous fixed rotation is applied.
- && !task.inMultiWindowMode()) {
+ && (!task.inMultiWindowMode() || !topRunningActivity.inMultiWindowMode())) {
// If Activity is in fixed rotation, its will be applied with the next rotation,
// when the Task is still in the previous rotation.
final int taskRotation = task.getWindowConfiguration().getDisplayRotation();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f9b6fc1..40c6c46 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3915,8 +3915,9 @@
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent == null) {
- throw new IllegalStateException("No touch mode is defined for displayId {"
- + displayId + "}");
+ throw new IllegalStateException("Failed to retrieve the touch mode state for"
+ + "display {" + displayId + "}: display is not registered in "
+ + "WindowRootContainer");
}
return displayContent.isInTouchMode();
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index cf49dcf..0c4830a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -684,6 +684,38 @@
}
}
+ <V> void transferPolicies(EnforcingAdmin oldAdmin, EnforcingAdmin newAdmin) {
+ Set<PolicyKey> globalPolicies = new HashSet<>(mGlobalPolicies.keySet());
+ for (PolicyKey policy : globalPolicies) {
+ PolicyState<?> policyState = mGlobalPolicies.get(policy);
+ if (policyState.getPoliciesSetByAdmins().containsKey(oldAdmin)) {
+ PolicyDefinition<V> policyDefinition =
+ (PolicyDefinition<V>) policyState.getPolicyDefinition();
+ PolicyValue<V> policyValue =
+ (PolicyValue<V>) policyState.getPoliciesSetByAdmins().get(oldAdmin);
+ setGlobalPolicy(policyDefinition, newAdmin, policyValue);
+ }
+ }
+
+ for (int i = 0; i < mLocalPolicies.size(); i++) {
+ int userId = mLocalPolicies.keyAt(i);
+ Set<PolicyKey> localPolicies = new HashSet<>(
+ mLocalPolicies.get(userId).keySet());
+ for (PolicyKey policy : localPolicies) {
+ PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy);
+ if (policyState.getPoliciesSetByAdmins().containsKey(oldAdmin)) {
+ PolicyDefinition<V> policyDefinition =
+ (PolicyDefinition<V>) policyState.getPolicyDefinition();
+ PolicyValue<V> policyValue =
+ (PolicyValue<V>) policyState.getPoliciesSetByAdmins().get(oldAdmin);
+ setLocalPolicy(policyDefinition, newAdmin, policyValue, userId);
+ }
+ }
+ }
+
+ removePoliciesForAdmin(oldAdmin);
+ }
+
private Set<UserRestrictionPolicyKey> getUserRestrictionPolicyKeysForAdminLocked(
Map<PolicyKey, PolicyState<?>> policies,
EnforcingAdmin admin) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index dedc073..3578b16 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3882,6 +3882,17 @@
final ActiveAdmin adminToTransfer = policy.mAdminMap.get(outgoingReceiver);
final int oldAdminUid = adminToTransfer.getUid();
+ if (isPolicyEngineForFinanceFlagEnabled() || isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin oldAdmin =
+ EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ outgoingReceiver, userHandle, adminToTransfer);
+ EnforcingAdmin newAdmin =
+ EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ incomingReceiver, userHandle, adminToTransfer);
+
+ mDevicePolicyEngine.transferPolicies(oldAdmin, newAdmin);
+ }
+
adminToTransfer.transfer(incomingDeviceInfo);
policy.mAdminMap.remove(outgoingReceiver);
policy.mAdminMap.put(incomingReceiver, adminToTransfer);
@@ -6051,7 +6062,7 @@
@Override
public void lockNow(int flags, String callerPackageName, boolean parent) {
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(callerPackageName);
} else {
caller = getCallerIdentity();
@@ -6063,7 +6074,7 @@
ActiveAdmin admin;
// Make sure the caller has any active admin with the right policy or
// the required permission.
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
admin = enforcePermissionAndGetEnforcingAdmin(
/* admin= */ null,
/* permission= */ MANAGE_DEVICE_POLICY_LOCK,
@@ -8917,13 +8928,13 @@
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
// The effect of this policy is device-wide.
enforcePermission(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
} else {
@@ -8951,13 +8962,13 @@
return false;
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
enforceCanQuery(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
} else {
Objects.requireNonNull(who, "ComponentName is null");
@@ -8980,13 +8991,13 @@
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
// The effect of this policy is device-wide.
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
@@ -9026,13 +9037,13 @@
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
// The effect of this policy is device-wide.
enforceCanQuery(SET_TIME_ZONE, caller.getPackageName(), UserHandle.USER_ALL);
} else {
@@ -9335,7 +9346,7 @@
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
@@ -9345,7 +9356,7 @@
final int userHandle = caller.getUserId();
int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
synchronized (getLockObject()) {
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
// SUPPORT USES_POLICY_DISABLE_KEYGUARD_FEATURES
EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(
who, MANAGE_DEVICE_POLICY_KEYGUARD, caller.getPackageName(),
@@ -9424,13 +9435,14 @@
synchronized (getLockObject()) {
if (who != null) {
- if (isPermissionCheckFlagEnabled()) {
- EnforcingAdmin admin = getEnforcingAdminForCaller(
- who, who.getPackageName());
+ if (isUnicornFlagEnabled()) {
+ EnforcingAdmin admin = getEnforcingAdminForPackage(
+ who, who.getPackageName(), userHandle);
Integer features = mDevicePolicyEngine.getLocalPolicySetByAdmin(
PolicyDefinition.KEYGUARD_DISABLED_FEATURES,
admin,
affectedUserId);
+
return features == null ? 0 : features;
} else {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
@@ -9438,7 +9450,7 @@
}
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
Integer features = mDevicePolicyEngine.getResolvedPolicy(
PolicyDefinition.KEYGUARD_DISABLED_FEATURES,
affectedUserId);
@@ -9999,10 +10011,6 @@
"clearDeviceOwner can only be called by the device owner");
}
enforceUserUnlocked(deviceOwnerUserId);
- DevicePolicyData policy = getUserData(deviceOwnerUserId);
- if (policy.mPasswordTokenHandle != 0) {
- mLockPatternUtils.removeEscrowToken(policy.mPasswordTokenHandle, deviceOwnerUserId);
- }
final ActiveAdmin admin = getDeviceOwnerAdminLocked();
mInjector.binderWithCleanCallingIdentity(() -> {
@@ -10057,6 +10065,10 @@
}
final DevicePolicyData policyData = getUserData(userId);
policyData.mCurrentInputMethodSet = false;
+ if (policyData.mPasswordTokenHandle != 0) {
+ mLockPatternUtils.removeEscrowToken(policyData.mPasswordTokenHandle, userId);
+ policyData.mPasswordTokenHandle = 0;
+ }
saveSettingsLocked(userId);
mPolicyCache.onUserRemoved(userId);
final DevicePolicyData systemPolicyData = getUserData(UserHandle.USER_SYSTEM);
@@ -11637,7 +11649,7 @@
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_APPLICATION_RESTRICTIONS);
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
@@ -13064,7 +13076,7 @@
String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
@@ -13134,7 +13146,7 @@
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
ActiveAdmin admin;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_PACKAGE_STATE,
@@ -13231,7 +13243,7 @@
public boolean isPackageSuspended(ComponentName who, String callerPackage, String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
enforcePermission(
MANAGE_DEVICE_POLICY_PACKAGE_STATE,
caller.getPackageName(),
@@ -13837,7 +13849,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 {
@@ -13856,7 +13868,7 @@
boolean result;
synchronized (getLockObject()) {
if (parent) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(
caller.getUserId()) && isManagedProfile(caller.getUserId()));
@@ -13873,7 +13885,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),
@@ -13912,7 +13924,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 {
@@ -13924,7 +13936,7 @@
synchronized (getLockObject()) {
if (parent) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId())
&& isManagedProfile(caller.getUserId()));
@@ -14116,13 +14128,13 @@
enforceMaxStringLength(accountType, "account type");
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,
@@ -14185,7 +14197,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,
@@ -15556,12 +15568,12 @@
public boolean setStatusBarDisabled(ComponentName who, String callerPackageName,
boolean disabled) {
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(who, callerPackageName);
} else {
caller = getCallerIdentity(who);
}
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
enforcePermission(MANAGE_DEVICE_POLICY_STATUS_BAR, caller.getPackageName(),
UserHandle.USER_ALL);
} else {
@@ -15572,7 +15584,7 @@
int userId = caller.getUserId();
synchronized (getLockObject()) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isUnicornFlagEnabled()) {
Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
"Admin " + who + " is neither the device owner or affiliated "
+ "user's profile owner.");
@@ -15631,7 +15643,7 @@
@Override
public boolean isStatusBarDisabled(String callerPackage) {
final CallerIdentity caller = getCallerIdentity(callerPackage);
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
enforceCanQuery(
MANAGE_DEVICE_POLICY_STATUS_BAR, caller.getPackageName(), caller.getUserId());
} else {
@@ -15641,7 +15653,7 @@
int userId = caller.getUserId();
synchronized (getLockObject()) {
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isUnicornFlagEnabled()) {
Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
"Admin " + callerPackage
+ " is neither the device owner or affiliated user's profile owner.");
@@ -16802,7 +16814,7 @@
}
}
EnforcingAdmin enforcingAdmin;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
@@ -16973,7 +16985,7 @@
public int getPermissionGrantState(ComponentName admin, String callerPackage,
String packageName, String permission) throws RemoteException {
final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
enforceCanQuery(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, caller.getPackageName(),
caller.getUserId());
} else {
@@ -19111,14 +19123,14 @@
throw new IllegalArgumentException("token must be at least 32-byte long");
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
}
final int userId = caller.getUserId();
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19174,7 +19186,7 @@
return false;
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
@@ -19182,7 +19194,7 @@
final int userId = caller.getUserId();
boolean result = false;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19221,14 +19233,14 @@
return false;
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
}
int userId = caller.getUserId();
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19270,7 +19282,7 @@
Objects.requireNonNull(token);
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
caller = getCallerIdentity(admin, callerPackageName);
} else {
caller = getCallerIdentity(admin);
@@ -19280,7 +19292,7 @@
boolean result = false;
final String password = passwordOrNull != null ? passwordOrNull : "";
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
admin,
MANAGE_DEVICE_POLICY_RESET_PASSWORD,
@@ -19311,7 +19323,7 @@
}
if (result) {
- if (isPermissionCheckFlagEnabled()) {
+ if (isUnicornFlagEnabled()) {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.RESET_PASSWORD_WITH_TOKEN)
.setAdmin(callerPackageName)
@@ -23569,6 +23581,30 @@
return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin);
}
+ private EnforcingAdmin getEnforcingAdminForPackage(@Nullable ComponentName who,
+ String packageName, int userId) {
+ ActiveAdmin admin;
+ if (who != null) {
+ if (isDeviceOwner(who, userId) || isProfileOwner(who, userId)) {
+ synchronized (getLockObject()) {
+ admin = getActiveAdminUncheckedLocked(who, userId);
+ }
+ if (admin != null) {
+ return EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userId, admin);
+ }
+ } else {
+ // Check for non-DPC active admins.
+ admin = getActiveAdminUncheckedLocked(who, userId);
+ if (admin != null) {
+ return EnforcingAdmin.createDeviceAdminEnforcingAdmin(who, userId, admin);
+ }
+ }
+ }
+
+ admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
+ return EnforcingAdmin.createEnforcingAdmin(packageName, userId, admin);
+ }
+
private int getAffectedUser(boolean calledOnParent) {
int callingUserId = mInjector.userHandleGetCallingUserId();
return calledOnParent ? getProfileParentId(callingUserId) : callingUserId;
@@ -23624,6 +23660,10 @@
DEFAULT_KEEP_PROFILES_RUNNING_FLAG);
}
+ private boolean isUnicornFlagEnabled() {
+ return false;
+ }
+
private boolean isWorkProfileTelephonyEnabled() {
return isWorkProfileTelephonyDevicePolicyManagerFlagEnabled()
&& isWorkProfileTelephonySubscriptionManagerFlagEnabled();
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
index 941a3a4..3faf394 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
@@ -72,18 +72,28 @@
mResources = InstrumentationRegistry.getContext().getResources();
// These Resources are common to all tests.
- doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMin))
+ doReturn(4000)
.when(mMockedResources)
.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMin);
- doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMax))
+ doReturn(8000)
.when(mMockedResources)
.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMax);
- doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault))
+ doReturn(6500)
.when(mMockedResources)
.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault);
- doReturn(mResources.getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite))
- .when(mMockedResources)
- .getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite);
+ doReturn(new String[] {"0.950456", "1.000000", "1.089058"})
+ .when(mMockedResources)
+ .getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite);
+ doReturn(6500)
+ .when(mMockedResources)
+ .getInteger(R.integer.config_displayWhiteBalanceDisplayNominalWhiteCct);
+ doReturn(new int[] {0})
+ .when(mMockedResources)
+ .getIntArray(R.array.config_displayWhiteBalanceDisplaySteps);
+ doReturn(new int[] {20})
+ .when(mMockedResources)
+ .getIntArray(R.array.config_displayWhiteBalanceDisplayRangeMinimums);
+
doReturn(mMockedResources).when(mMockedContext).getResources();
mDisplayToken = new Binder();
@@ -195,7 +205,7 @@
* Matrix should match the precalculated one for given cct and display primaries.
*/
@Test
- public void displayWhiteBalance_validateTransformMatrix() {
+ public void displayWhiteBalance_getAndSetMatrix_validateTransformMatrix() {
DisplayPrimaries displayPrimaries = new DisplayPrimaries();
displayPrimaries.red = new CieXyz();
displayPrimaries.red.X = 0.412315f;
@@ -223,10 +233,12 @@
final int cct = 6500;
mDisplayWhiteBalanceTintController.setMatrix(cct);
+ mDisplayWhiteBalanceTintController.setAppliedCct(
+ mDisplayWhiteBalanceTintController.getTargetCct());
+
assertWithMessage("Failed to set temperature")
.that(mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
.isEqualTo(cct);
-
float[] matrixDwb = mDisplayWhiteBalanceTintController.getMatrix();
final float[] expectedMatrixDwb = {
0.971848f, -0.001421f, 0.000491f, 0.0f,
@@ -238,6 +250,54 @@
1e-6f /* tolerance */);
}
+ /**
+ * Matrix should match the precalculated one for given cct and display primaries.
+ */
+ @Test
+ public void displayWhiteBalance_targetApplied_validateTransformMatrix() {
+ DisplayPrimaries displayPrimaries = new DisplayPrimaries();
+ displayPrimaries.red = new CieXyz();
+ displayPrimaries.red.X = 0.412315f;
+ displayPrimaries.red.Y = 0.212600f;
+ displayPrimaries.red.Z = 0.019327f;
+ displayPrimaries.green = new CieXyz();
+ displayPrimaries.green.X = 0.357600f;
+ displayPrimaries.green.Y = 0.715200f;
+ displayPrimaries.green.Z = 0.119200f;
+ displayPrimaries.blue = new CieXyz();
+ displayPrimaries.blue.X = 0.180500f;
+ displayPrimaries.blue.Y = 0.072200f;
+ displayPrimaries.blue.Z = 0.950633f;
+ displayPrimaries.white = new CieXyz();
+ displayPrimaries.white.X = 0.950456f;
+ displayPrimaries.white.Y = 1.000000f;
+ displayPrimaries.white.Z = 1.089058f;
+ when(mDisplayManagerInternal.getDisplayNativePrimaries(DEFAULT_DISPLAY))
+ .thenReturn(displayPrimaries);
+
+ setUpTintController();
+ assertWithMessage("Setup with valid SurfaceControl failed")
+ .that(mDisplayWhiteBalanceTintController.mSetUp)
+ .isTrue();
+
+ final int cct = 6500;
+ mDisplayWhiteBalanceTintController.setTargetCct(cct);
+ final float[] matrixDwb = mDisplayWhiteBalanceTintController.computeMatrixForCct(cct);
+ mDisplayWhiteBalanceTintController.setAppliedCct(cct);
+
+ assertWithMessage("Failed to set temperature")
+ .that(mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+ .isEqualTo(cct);
+ final float[] expectedMatrixDwb = {
+ 0.971848f, -0.001421f, 0.000491f, 0.0f,
+ 0.028193f, 0.945798f, 0.003207f, 0.0f,
+ -0.000042f, -0.000989f, 0.988659f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+ assertArrayEquals("Unexpected DWB matrix", expectedMatrixDwb, matrixDwb,
+ 1e-6f /* tolerance */);
+ }
+
private void setUpTintController() {
mDisplayWhiteBalanceTintController = new DisplayWhiteBalanceTintController(
mDisplayManagerInternal);
diff --git a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
index f788c92..46974cf7 100644
--- a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
@@ -28,6 +28,8 @@
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
+import static com.android.server.am.ProcessList.UNKNOWN_ADJ;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
@@ -81,7 +83,7 @@
public void testEnqueueUidChange() {
int change = mUidObserverController.enqueueUidChange(null, TEST_UID1,
UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE,
- PROCESS_CAPABILITY_ALL, 0, false);
+ UNKNOWN_ADJ, PROCESS_CAPABILITY_ALL, 0, false);
assertEquals("expected=ACTIVE,actual=" + changeToStr(change),
UidRecord.CHANGE_ACTIVE, change);
assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE,
@@ -91,8 +93,8 @@
final ChangeRecord record2 = new ChangeRecord();
change = mUidObserverController.enqueueUidChange(record2, TEST_UID2,
- UidRecord.CHANGE_CACHED, PROCESS_STATE_CACHED_RECENT, PROCESS_CAPABILITY_NONE,
- 99, true);
+ UidRecord.CHANGE_CACHED, PROCESS_STATE_CACHED_RECENT, UNKNOWN_ADJ,
+ PROCESS_CAPABILITY_NONE, 99, true);
assertEquals("expected=ACTIVE,actual=" + changeToStr(change),
UidRecord.CHANGE_CACHED, change);
assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE,
@@ -101,7 +103,8 @@
PROCESS_CAPABILITY_NONE, 99, true, record2);
change = mUidObserverController.enqueueUidChange(record1, TEST_UID1,
- UidRecord.CHANGE_UNCACHED, PROCESS_STATE_TOP, PROCESS_CAPABILITY_ALL, 0, false);
+ UidRecord.CHANGE_UNCACHED, PROCESS_STATE_TOP, UNKNOWN_ADJ,
+ PROCESS_CAPABILITY_ALL, 0, false);
assertEquals("expected=ACTIVE|UNCACHED,actual=" + changeToStr(change),
UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_UNCACHED, change);
assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_UNCACHED,
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index d12741a..317fd58 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -100,6 +100,7 @@
import com.android.server.FgThread;
import com.android.server.SystemService;
import com.android.server.am.UserState.KeyEvictedCallback;
+import com.android.server.pm.UserJourneyLogger;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
import com.android.server.wm.WindowManagerService;
@@ -199,6 +200,7 @@
mUserController.setAllowUserUnlocking(true);
setUpUser(TEST_USER_ID, NO_USERINFO_FLAGS);
setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated= */ true, null);
+ mInjector.mRelevantUser = null;
});
}
@@ -232,6 +234,25 @@
}
@Test
+ public void testStartUser_background_duringBootHsum() {
+ mockIsHeadlessSystemUserMode(true);
+ mUserController.setAllowUserUnlocking(false);
+ mInjector.mRelevantUser = TEST_USER_ID;
+ boolean started = mUserController.startUser(TEST_USER_ID, USER_START_MODE_BACKGROUND);
+ assertWithMessage("startUser(%s, foreground=false)", TEST_USER_ID).that(started).isTrue();
+
+ // ACTION_LOCKED_BOOT_COMPLETED not sent yet
+ startUserAssertions(newArrayList(Intent.ACTION_USER_STARTED, Intent.ACTION_USER_STARTING),
+ START_BACKGROUND_USER_MESSAGE_CODES);
+
+ mUserController.onBootComplete(null);
+
+ startUserAssertions(newArrayList(Intent.ACTION_USER_STARTED, Intent.ACTION_USER_STARTING,
+ Intent.ACTION_LOCKED_BOOT_COMPLETED),
+ START_BACKGROUND_USER_MESSAGE_CODES);
+ }
+
+ @Test
public void testStartUser_sendsNoBroadcastsForSystemUserInNonHeadlessMode() {
setUpUser(SYSTEM_USER_ID, UserInfo.FLAG_SYSTEM, /* preCreated= */ false,
UserManager.USER_TYPE_FULL_SYSTEM);
@@ -1074,8 +1095,12 @@
private final KeyguardManager mKeyguardManagerMock;
private final LockPatternUtils mLockPatternUtilsMock;
+ private final UserJourneyLogger mUserJourneyLoggerMock;
+
private final Context mCtx;
+ private Integer mRelevantUser;
+
TestInjector(Context ctx) {
super(null);
mCtx = ctx;
@@ -1090,6 +1115,7 @@
mKeyguardManagerMock = mock(KeyguardManager.class);
when(mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true);
mLockPatternUtilsMock = mock(LockPatternUtils.class);
+ mUserJourneyLoggerMock = mock(UserJourneyLogger.class);
}
@Override
@@ -1162,7 +1188,9 @@
boolean sticky, int callingPid, int callingUid, int realCallingUid,
int realCallingPid, int userId) {
Log.i(TAG, "broadcastIntentLocked " + intent);
- mSentIntents.add(intent);
+ if (mRelevantUser == null || mRelevantUser == userId || userId == UserHandle.USER_ALL) {
+ mSentIntents.add(intent);
+ }
return 0;
}
@@ -1220,6 +1248,11 @@
void onSystemUserVisibilityChanged(boolean visible) {
Log.i(TAG, "onSystemUserVisibilityChanged(" + visible + ")");
}
+
+ @Override
+ protected UserJourneyLogger getUserJourneyLogger() {
+ return mUserJourneyLoggerMock;
+ }
}
private static class TestHandler extends Handler {
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java
index c5a9af7..dcd06c9 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java
@@ -30,7 +30,7 @@
@Test
public void call_writeToParcel_fromParcel_reconstructsSuccessfully() {
final CallMetadataSyncData.Call call = new CallMetadataSyncData.Call();
- final long id = 5;
+ final String id = "5";
final String callerId = "callerId";
final byte[] appIcon = "appIcon".getBytes();
final String appName = "appName";
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java
index a488ab4..afddf3c 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java
@@ -47,24 +47,24 @@
@Test
public void getCallForId_invalid() {
- when(mMockCrossDeviceCall.getId()).thenReturn(-1L);
- final CrossDeviceCall call = mSyncInCallService.getCallForId(-1L,
+ when(mMockCrossDeviceCall.getId()).thenReturn(null);
+ final CrossDeviceCall call = mSyncInCallService.getCallForId(null,
List.of(mMockCrossDeviceCall));
assertWithMessage("Unexpectedly found a match for call id").that(call).isNull();
}
@Test
public void getCallForId_noMatch() {
- when(mMockCrossDeviceCall.getId()).thenReturn(5L);
- final CrossDeviceCall call = mSyncInCallService.getCallForId(1L,
+ when(mMockCrossDeviceCall.getId()).thenReturn("123abc");
+ final CrossDeviceCall call = mSyncInCallService.getCallForId("abc123",
List.of(mMockCrossDeviceCall));
assertWithMessage("Unexpectedly found a match for call id").that(call).isNull();
}
@Test
public void getCallForId_hasMatch() {
- when(mMockCrossDeviceCall.getId()).thenReturn(5L);
- final CrossDeviceCall call = mSyncInCallService.getCallForId(5L,
+ when(mMockCrossDeviceCall.getId()).thenReturn("123abc");
+ final CrossDeviceCall call = mSyncInCallService.getCallForId("123abc",
List.of(mMockCrossDeviceCall));
assertWithMessage("Unexpectedly did not find a match for call id").that(call).isNotNull();
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
index 9d42a5b..5a0646c 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
@@ -62,9 +62,9 @@
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.RINGING);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT,
- android.companion.Telecom.Call.REJECT,
- android.companion.Telecom.Call.SILENCE));
+ .isEqualTo(Set.of(android.companion.Telecom.ACCEPT,
+ android.companion.Telecom.REJECT,
+ android.companion.Telecom.SILENCE));
}
@Test
@@ -77,9 +77,9 @@
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.ONGOING);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.END,
- android.companion.Telecom.Call.MUTE,
- android.companion.Telecom.Call.PUT_ON_HOLD));
+ .isEqualTo(Set.of(android.companion.Telecom.END,
+ android.companion.Telecom.MUTE,
+ android.companion.Telecom.PUT_ON_HOLD));
}
@Test
@@ -92,8 +92,8 @@
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.ON_HOLD);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.END,
- android.companion.Telecom.Call.TAKE_OFF_HOLD));
+ .isEqualTo(Set.of(android.companion.Telecom.END,
+ android.companion.Telecom.TAKE_OFF_HOLD));
}
@Test
@@ -106,8 +106,8 @@
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.ONGOING);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.END,
- android.companion.Telecom.Call.MUTE));
+ .isEqualTo(Set.of(android.companion.Telecom.END,
+ android.companion.Telecom.MUTE));
}
@Test
@@ -120,8 +120,8 @@
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.ONGOING);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.END,
- android.companion.Telecom.Call.PUT_ON_HOLD));
+ .isEqualTo(Set.of(android.companion.Telecom.END,
+ android.companion.Telecom.PUT_ON_HOLD));
}
@Test
@@ -134,17 +134,17 @@
assertWithMessage("Wrong status for ringing state").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.RINGING);
assertWithMessage("Wrong controls for ringing state").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT,
- android.companion.Telecom.Call.REJECT,
- android.companion.Telecom.Call.SILENCE));
+ .isEqualTo(Set.of(android.companion.Telecom.ACCEPT,
+ android.companion.Telecom.REJECT,
+ android.companion.Telecom.SILENCE));
crossDeviceCall.updateCallDetails(createCallDetails(Call.STATE_ACTIVE,
Call.Details.CAPABILITY_HOLD | Call.Details.CAPABILITY_MUTE));
assertWithMessage("Wrong status for active state").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.ONGOING);
assertWithMessage("Wrong controls for active state").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.END,
- android.companion.Telecom.Call.MUTE,
- android.companion.Telecom.Call.PUT_ON_HOLD));
+ .isEqualTo(Set.of(android.companion.Telecom.END,
+ android.companion.Telecom.MUTE,
+ android.companion.Telecom.PUT_ON_HOLD));
}
@Test
@@ -158,8 +158,8 @@
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.RINGING_SILENCED);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT,
- android.companion.Telecom.Call.REJECT));
+ .isEqualTo(Set.of(android.companion.Telecom.ACCEPT,
+ android.companion.Telecom.REJECT));
}
@Test
@@ -173,9 +173,9 @@
assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
.isEqualTo(android.companion.Telecom.Call.ONGOING);
assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.END,
- android.companion.Telecom.Call.MUTE,
- android.companion.Telecom.Call.PUT_ON_HOLD));
+ .isEqualTo(Set.of(android.companion.Telecom.END,
+ android.companion.Telecom.MUTE,
+ android.companion.Telecom.PUT_ON_HOLD));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
index eec026cc..25b0ae4 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
@@ -81,7 +81,7 @@
@Test
public void processTelecomDataFromSync_createCallUpdateMessage_hasCalls() {
- when(mMockCrossDeviceCall.getId()).thenReturn(5L);
+ when(mMockCrossDeviceCall.getId()).thenReturn("123abc");
final String callerId = "Firstname Lastname";
when(mMockCrossDeviceCall.getReadableCallerId(anyBoolean())).thenReturn(callerId);
final String appName = "AppName";
@@ -90,9 +90,9 @@
when(mMockCrossDeviceCall.getCallingAppIcon()).thenReturn(appIcon.getBytes());
when(mMockCrossDeviceCall.getStatus()).thenReturn(android.companion.Telecom.Call.RINGING);
final Set<Integer> controls = Set.of(
- android.companion.Telecom.Call.ACCEPT,
- android.companion.Telecom.Call.REJECT,
- android.companion.Telecom.Call.SILENCE);
+ android.companion.Telecom.ACCEPT,
+ android.companion.Telecom.REJECT,
+ android.companion.Telecom.SILENCE);
when(mMockCrossDeviceCall.getControls()).thenReturn(controls);
final byte[] data = mCrossDeviceSyncController.createCallUpdateMessage(
new HashSet<>(List.of(mMockCrossDeviceCall)),
@@ -103,35 +103,33 @@
callMetadataSyncData.getCalls()).hasSize(1);
final CallMetadataSyncData.Call call =
callMetadataSyncData.getCalls().stream().findAny().orElseThrow();
- assertWithMessage("Wrong id").that(call.getId()).isEqualTo(5L);
+ assertWithMessage("Wrong id").that(call.getId()).isEqualTo("123abc");
assertWithMessage("Wrong app icon").that(new String(call.getAppIcon())).isEqualTo(appIcon);
assertWithMessage("Wrong app name").that(call.getAppName()).isEqualTo(appName);
assertWithMessage("Wrong caller id").that(call.getCallerId()).isEqualTo(callerId);
assertWithMessage("Wrong status").that(call.getStatus())
.isEqualTo(android.companion.Telecom.Call.RINGING);
assertWithMessage("Wrong controls").that(call.getControls()).isEqualTo(controls);
- assertWithMessage("Unexpectedly has requests").that(
- callMetadataSyncData.getRequests()).isEmpty();
}
@Test
public void processTelecomDataFromMessage_createCallControlMessage_hasCallControlRequest() {
final byte[] data = CrossDeviceSyncController.createCallControlMessage(
- /* callId= */ 5L, /* status= */ android.companion.Telecom.Call.ACCEPT);
+ /* callId= */ "123abc", /* status= */ android.companion.Telecom.ACCEPT);
final CallMetadataSyncData callMetadataSyncData =
mCrossDeviceSyncController.processTelecomDataFromSync(data);
assertWithMessage("Wrong number of requests").that(
callMetadataSyncData.getRequests()).hasSize(1);
final CallMetadataSyncData.Call call =
callMetadataSyncData.getRequests().stream().findAny().orElseThrow();
- assertWithMessage("Wrong id").that(call.getId()).isEqualTo(5L);
+ assertWithMessage("Wrong id").that(call.getId()).isEqualTo("123abc");
assertWithMessage("Wrong app icon").that(call.getAppIcon()).isNull();
assertWithMessage("Wrong app name").that(call.getAppName()).isNull();
assertWithMessage("Wrong caller id").that(call.getCallerId()).isNull();
assertWithMessage("Wrong status").that(call.getStatus())
.isEqualTo(android.companion.Telecom.Call.UNKNOWN_STATUS);
assertWithMessage("Wrong controls").that(call.getControls())
- .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT));
+ .isEqualTo(Set.of(android.companion.Telecom.ACCEPT));
assertWithMessage("Unexpectedly has active calls").that(
callMetadataSyncData.getCalls()).isEmpty();
}
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 1e342f5..57755a9 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1512,6 +1512,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);
@@ -2602,6 +2603,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetApplicationHiddenWithDO() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -2627,6 +2629,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 =
@@ -4373,6 +4376,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledModifiesSetting() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -4384,6 +4388,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledWithPOOnUser0() throws Exception {
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
setupProfileOwnerOnUser0();
@@ -4395,6 +4400,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledFailWithPONotOnUser0() throws Exception {
setupProfileOwner();
assertExpectException(SecurityException.class, null,
@@ -4404,6 +4410,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetAutoTimeZoneEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
@@ -5377,6 +5384,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testResetPasswordWithToken() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -5411,6 +5419,7 @@
}
@Test
+ @Ignore("b/277916462")
public void resetPasswordWithToken_NumericPin() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -5431,6 +5440,7 @@
}
@Test
+ @Ignore("b/277916462")
public void resetPasswordWithToken_EmptyPassword() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -7251,6 +7261,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testCanProfileOwnerResetPasswordWhenLocked() throws Exception {
setDeviceEncryptionPerUser();
setupProfileOwner();
@@ -7314,6 +7325,7 @@
}
@Test
+ @Ignore("b/277916462")
public void testSetAccountTypesWithManagementDisabledOnManagedProfile() throws Exception {
setupProfileOwner();
@@ -7333,6 +7345,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/color/CctEvaluatorTest.java b/services/tests/servicestests/src/com/android/server/display/color/CctEvaluatorTest.java
new file mode 100644
index 0000000..b96666a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/color/CctEvaluatorTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.color;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CctEvaluatorTest {
+
+ @Test
+ public void noEntriesInParallelArrays_setsEverythingToOne() {
+ final CctEvaluator evaluator = new CctEvaluator(0, 5, new int[]{}, new int[]{});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(new int[]{1, 1, 1, 1, 1, 1});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{0, 1, 2, 3, 4, 5});
+ }
+
+ @Test
+ public void unevenNumberOfEntriesInParallelArrays_setsEverythingToOne() {
+ final CctEvaluator evaluator = new CctEvaluator(0, 5, new int[]{0}, new int[]{});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(new int[]{1, 1, 1, 1, 1, 1});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{0, 1, 2, 3, 4, 5});
+ }
+
+ @Test
+ public void singleEntryInParallelArray_computesCorrectly() {
+ final CctEvaluator evaluator = new CctEvaluator(0, 5, new int[]{0}, new int[]{2});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(new int[]{2, 2, 2, 2, 2, 2});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{0, 0, 2, 2, 4, 4});
+ }
+
+ @Test
+ public void minimumIsBelowFirstRange_computesCorrectly() {
+ final CctEvaluator evaluator = new CctEvaluator(3000, 3005, new int[]{3002},
+ new int[]{20});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(new int[]{20, 20, 20, 20, 20, 20});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{3000, 3000, 3000, 3000, 3000, 3000});
+ }
+
+ @Test
+ public void minimumIsAboveFirstRange_computesCorrectly() {
+ final CctEvaluator evaluator = new CctEvaluator(3000, 3008, new int[]{3002},
+ new int[]{20});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(
+ new int[]{20, 20, 20, 20, 20, 20, 20, 20, 20});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000});
+ }
+
+ @Test
+ public void multipleStepsStartsAtThreshold_computesCorrectly() {
+ final CctEvaluator evaluator = new CctEvaluator(5, 20, new int[]{0, 4, 5, 10, 18},
+ new int[]{11, 7, 2, 15, 9});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(
+ new int[]{2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 9, 9, 9});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{5, 5, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18});
+ }
+
+ @Test
+ public void multipleStepsStartsInBetween_computesCorrectly() {
+ final CctEvaluator evaluator = new CctEvaluator(4, 20, new int[]{0, 5, 10, 18},
+ new int[]{14, 2, 15, 9});
+ assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(
+ new int[]{14, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 9, 9, 9});
+ assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+ new int[]{4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 18, 18, 18});
+ }
+}
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 d0d28c3..55c45df 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
@@ -85,6 +85,9 @@
const val DEVICE_ID = 1
const val VENDOR_SPECIFIC_DEVICE_ID = 2
const val ENGLISH_DVORAK_DEVICE_ID = 3
+ const val ENGLISH_QWERTY_DEVICE_ID = 4
+ const val DEFAULT_VENDOR_ID = 123
+ const val DEFAULT_PRODUCT_ID = 456
const val USER_ID = 4
const val IME_ID = "ime_id"
const val PACKAGE_NAME = "KeyboardLayoutManagerTests"
@@ -122,6 +125,7 @@
private lateinit var keyboardDevice: InputDevice
private lateinit var vendorSpecificKeyboardDevice: InputDevice
private lateinit var englishDvorakKeyboardDevice: InputDevice
+ private lateinit var englishQwertyKeyboardDevice: InputDevice
@Before
fun setup() {
@@ -150,17 +154,26 @@
Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE)))
.thenReturn(inputManager)
- keyboardDevice = createKeyboard(DEVICE_ID, 0, 0, "", "")
+ keyboardDevice = createKeyboard(DEVICE_ID, DEFAULT_VENDOR_ID, DEFAULT_PRODUCT_ID, "", "")
vendorSpecificKeyboardDevice = createKeyboard(VENDOR_SPECIFIC_DEVICE_ID, 1, 1, "", "")
- englishDvorakKeyboardDevice =
- createKeyboard(ENGLISH_DVORAK_DEVICE_ID, 0, 0, "en", "dvorak")
+ englishDvorakKeyboardDevice = createKeyboard(ENGLISH_DVORAK_DEVICE_ID, DEFAULT_VENDOR_ID,
+ DEFAULT_PRODUCT_ID, "en", "dvorak")
+ englishQwertyKeyboardDevice = createKeyboard(ENGLISH_QWERTY_DEVICE_ID, DEFAULT_VENDOR_ID,
+ DEFAULT_PRODUCT_ID, "en", "qwerty")
Mockito.`when`(iInputManager.inputDeviceIds)
- .thenReturn(intArrayOf(DEVICE_ID, VENDOR_SPECIFIC_DEVICE_ID, ENGLISH_DVORAK_DEVICE_ID))
+ .thenReturn(intArrayOf(
+ DEVICE_ID,
+ VENDOR_SPECIFIC_DEVICE_ID,
+ ENGLISH_DVORAK_DEVICE_ID,
+ ENGLISH_QWERTY_DEVICE_ID
+ ))
Mockito.`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardDevice)
Mockito.`when`(iInputManager.getInputDevice(VENDOR_SPECIFIC_DEVICE_ID))
.thenReturn(vendorSpecificKeyboardDevice)
Mockito.`when`(iInputManager.getInputDevice(ENGLISH_DVORAK_DEVICE_ID))
.thenReturn(englishDvorakKeyboardDevice)
+ Mockito.`when`(iInputManager.getInputDevice(ENGLISH_QWERTY_DEVICE_ID))
+ .thenReturn(englishQwertyKeyboardDevice)
}
private fun setupBroadcastReceiver() {
@@ -778,14 +791,23 @@
@Test
fun testNewUi_getDefaultKeyboardLayoutForInputDevice_withHwLanguageTagAndLayoutType() {
NewSettingsApiFlag(true).use {
- // Should return English dvorak even if IME current layout is qwerty, since HW says the
+ val frenchSubtype = createImeSubtypeForLanguageTagAndLayoutType("fr", "azerty")
+ // Should return English dvorak even if IME current layout is French, since HW says the
// keyboard is a Dvorak keyboard
assertCorrectLayout(
englishDvorakKeyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("en", "qwerty"),
+ frenchSubtype,
createLayoutDescriptor("keyboard_layout_english_us_dvorak")
)
+ // Back to back changing HW keyboards with same product and vendor ID but different
+ // language and layout type should configure the layouts correctly.
+ assertCorrectLayout(
+ englishQwertyKeyboardDevice,
+ frenchSubtype,
+ createLayoutDescriptor("keyboard_layout_english_us")
+ )
+
// Fallback to IME information if the HW provided layout script is incompatible with the
// provided IME subtype
assertCorrectLayout(
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 01e56a0..1cfaf7c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -228,6 +228,15 @@
});
}
+ public void testShortcutIdTruncated() {
+ ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(),
+ "s".repeat(Short.MAX_VALUE)).build();
+
+ assertTrue(
+ "id must be truncated to MAX_ID_LENGTH",
+ si.getId().length() <= ShortcutInfo.MAX_ID_LENGTH);
+ }
+
public void testShortcutInfoParcel() {
setCaller(CALLING_PACKAGE_1, USER_10);
ShortcutInfo si = parceled(new ShortcutInfo.Builder(mClientContext)
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserJourneyLoggerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserJourneyLoggerTest.java
new file mode 100644
index 0000000..20e2692
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserJourneyLoggerTest.java
@@ -0,0 +1,580 @@
+/*
+ * 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.pm;
+
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_ABORTED;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_INCOMPLETE_OR_TIMEOUT;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_NULL_USER_INFO;
+import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_UNSPECIFIED;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_BEGIN;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_CANCEL;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_ERROR;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_FINISH;
+import static com.android.server.pm.UserJourneyLogger.EVENT_STATE_NONE;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_GRANT_ADMIN;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_CREATE;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_REMOVE;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_START;
+import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_STOP;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_CREATE_USER;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_REMOVE_USER;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_REVOKE_ADMIN;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_START_USER;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_STOP_USER;
+import static com.android.server.pm.UserJourneyLogger.USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.pm.UserInfo;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class UserJourneyLoggerTest {
+
+ public static final int FULL_USER_ADMIN_FLAG = 0x00000402;
+ private UserJourneyLogger mUserJourneyLogger;
+
+ @Before
+ public void setup() throws Exception {
+ mUserJourneyLogger = spy(new UserJourneyLogger());
+ }
+
+ @Test
+ public void testUserStartLifecycleJourneyReported() {
+ final UserLifecycleJourneyReportedCaptor report1 = new UserLifecycleJourneyReportedCaptor();
+ final UserJourneyLogger.UserJourneySession session = new UserJourneyLogger
+ .UserJourneySession(10, USER_JOURNEY_USER_START);
+
+ report1.captureLogAndAssert(mUserJourneyLogger, session,
+ USER_JOURNEY_USER_START, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY, 1,
+ ERROR_CODE_UNSPECIFIED);
+ }
+
+
+ @Test
+ public void testUserLifecycleEventOccurred() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = new UserJourneyLogger
+ .UserJourneySession(10, USER_JOURNEY_USER_START);
+
+ report1.captureLogAndAssert(mUserJourneyLogger, session, 0,
+ USER_LIFECYCLE_EVENT_START_USER, EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED);
+ }
+
+ @Test
+ public void testLogUserLifecycleEvent() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_START_USER, EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ mUserJourneyLogger.logUserLifecycleEvent(10, USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED,
+ EVENT_STATE_NONE);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_USER_RUNNING_LOCKED,
+ EVENT_STATE_NONE, ERROR_CODE_UNSPECIFIED, 2);
+ }
+
+
+ @Test
+ public void testCreateUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(-1, USER_JOURNEY_USER_CREATE);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, -1,
+ USER_LIFECYCLE_EVENT_CREATE_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserCreateJourneyFinish(0, targetUser);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_CREATE_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_USER_CREATE, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+ }
+
+ @Test
+ public void testRemoveUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_REMOVE);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_REMOVE_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(0, targetUser,
+ USER_JOURNEY_USER_REMOVE);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_REMOVE_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_USER_REMOVE, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+ }
+
+ @Test
+ public void testStartUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(0, targetUser,
+ USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_USER_START, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+ }
+
+ @Test
+ public void testStopUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_STOP);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER, EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(0, targetUser,
+ USER_JOURNEY_USER_STOP);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER, EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_USER_STOP, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+ }
+
+ @Test
+ public void testAbortStopUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_STOP);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER, EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+
+ mUserJourneyLogger.logUserJourneyFinishWithError(-1, targetUser,
+ USER_JOURNEY_USER_STOP, ERROR_CODE_ABORTED);
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER,
+ EVENT_STATE_CANCEL, ERROR_CODE_ABORTED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_USER_STOP, -1, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_ABORTED, 1);
+ }
+
+ @Test
+ public void testIncompleteStopUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_STOP);
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ mUserJourneyLogger.finishAndClearIncompleteUserJourney(10, USER_JOURNEY_USER_STOP);
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER,
+ EVENT_STATE_ERROR,
+ ERROR_CODE_INCOMPLETE_OR_TIMEOUT, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_USER_STOP, -1, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN,
+ -1, // information about user are incomplete
+ ERROR_CODE_INCOMPLETE_OR_TIMEOUT, 1);
+ }
+
+ @Test
+ public void testGrantAdminUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_GRANT_ADMIN);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_GRANT_ADMIN,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(0, targetUser,
+ USER_JOURNEY_GRANT_ADMIN);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_GRANT_ADMIN,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_GRANT_ADMIN, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+ }
+
+ @Test
+ public void testNullUserErrorGrantAdminUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+
+ UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_GRANT_ADMIN);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_GRANT_ADMIN,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ mUserJourneyLogger.logNullUserJourneyError(USER_JOURNEY_GRANT_ADMIN,
+ 0, 10, "", -1);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_GRANT_ADMIN,
+ EVENT_STATE_ERROR, ERROR_CODE_NULL_USER_INFO, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ USER_JOURNEY_GRANT_ADMIN, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__UNKNOWN,
+ -1, ERROR_CODE_NULL_USER_INFO, 1);
+ }
+
+ @Test
+ public void testRevokeAdminUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(10, UserJourneyLogger.USER_JOURNEY_REVOKE_ADMIN);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_REVOKE_ADMIN,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user", UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(0, targetUser,
+ UserJourneyLogger.USER_JOURNEY_REVOKE_ADMIN);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_REVOKE_ADMIN,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 2);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ UserJourneyLogger.USER_JOURNEY_REVOKE_ADMIN, 0, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000400, ERROR_CODE_UNSPECIFIED, 1);
+ }
+
+ @Test
+ public void testSwitchFGUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(11, UserJourneyLogger.USER_JOURNEY_USER_SWITCH_FG);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 11,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_SWITCH_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserJourneyLogger.UserJourneySession session2 = mUserJourneyLogger
+ .logUserJourneyBegin(11, USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session2.mSessionId, 11,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 2);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(11, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(10, targetUser,
+ USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session2.mSessionId, 11,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 3);
+
+ report2.captureAndAssert(mUserJourneyLogger, session2.mSessionId,
+ USER_JOURNEY_USER_START, 10, 11,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+
+ mUserJourneyLogger.logUserSwitchJourneyFinish(10, targetUser);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 11,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_SWITCH_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 4);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ UserJourneyLogger.USER_JOURNEY_USER_SWITCH_FG, 10, 11,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 2);
+ }
+
+
+ @Test
+ public void testSwitchUIUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(11, UserJourneyLogger.USER_JOURNEY_USER_SWITCH_UI);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 11,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_SWITCH_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ final UserJourneyLogger.UserJourneySession session2 = mUserJourneyLogger
+ .logUserJourneyBegin(11, USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session2.mSessionId, 11,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 2);
+
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ UserInfo targetUser = new UserInfo(11, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(10, targetUser,
+ USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session2.mSessionId, 11,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 3);
+
+ report2.captureAndAssert(mUserJourneyLogger, session2.mSessionId,
+ USER_JOURNEY_USER_START, 10, 11,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 1);
+
+ mUserJourneyLogger.logUserSwitchJourneyFinish(10, targetUser);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 11,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_SWITCH_USER,
+ EVENT_STATE_FINISH,
+ ERROR_CODE_UNSPECIFIED, 4);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ UserJourneyLogger.USER_JOURNEY_USER_SWITCH_UI, 10, 11,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 2);
+ }
+
+
+ @Test
+ public void testSwitchWithStopUIUserJourney() {
+ final UserLifecycleEventOccurredCaptor report1 = new UserLifecycleEventOccurredCaptor();
+
+ // BEGIN USER SWITCH
+ final UserJourneyLogger.UserJourneySession session = mUserJourneyLogger
+ .logUserJourneyBegin(11, UserJourneyLogger.USER_JOURNEY_USER_SWITCH_UI);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 11,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_SWITCH_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 1);
+
+ // BEGIN USER STOP
+ final UserJourneyLogger.UserJourneySession session2 = mUserJourneyLogger
+ .logUserJourneyBegin(10, USER_JOURNEY_USER_STOP);
+
+ report1.captureAndAssert(mUserJourneyLogger, session2.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 2);
+
+ // BEGIN USER START
+ UserJourneyLogger.UserJourneySession session3 = mUserJourneyLogger
+ .logUserJourneyBegin(11, USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session3.mSessionId, 11,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_BEGIN, ERROR_CODE_UNSPECIFIED, 3);
+
+
+ // FINISH USER STOP
+ final UserLifecycleJourneyReportedCaptor report2 = new UserLifecycleJourneyReportedCaptor();
+ final UserInfo targetUser = new UserInfo(10, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(-1, targetUser,
+ USER_JOURNEY_USER_STOP);
+
+ report1.captureAndAssert(mUserJourneyLogger, session2.mSessionId, 10,
+ USER_LIFECYCLE_EVENT_STOP_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 4);
+
+ report2.captureAndAssert(mUserJourneyLogger, session2.mSessionId,
+ USER_JOURNEY_USER_STOP, -1, 10,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ FULL_USER_ADMIN_FLAG, ERROR_CODE_UNSPECIFIED, 1);
+
+ // FINISH USER START
+ final UserInfo targetUser2 = new UserInfo(11, "test target user",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL);
+ mUserJourneyLogger.logUserJourneyFinish(10, targetUser2,
+ USER_JOURNEY_USER_START);
+
+ report1.captureAndAssert(mUserJourneyLogger, session3.mSessionId, 11,
+ USER_LIFECYCLE_EVENT_START_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 5);
+
+ report2.captureAndAssert(mUserJourneyLogger, session3.mSessionId,
+ USER_JOURNEY_USER_START, 10, 11,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ FULL_USER_ADMIN_FLAG, ERROR_CODE_UNSPECIFIED, 2);
+
+
+ // FINISH USER SWITCH
+ mUserJourneyLogger.logUserSwitchJourneyFinish(10, targetUser2);
+
+ report1.captureAndAssert(mUserJourneyLogger, session.mSessionId, 11,
+ UserJourneyLogger.USER_LIFECYCLE_EVENT_SWITCH_USER,
+ EVENT_STATE_FINISH, ERROR_CODE_UNSPECIFIED, 6);
+
+ report2.captureAndAssert(mUserJourneyLogger, session.mSessionId,
+ UserJourneyLogger.USER_JOURNEY_USER_SWITCH_UI, 10, 11,
+ FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__FULL_SECONDARY,
+ 0x00000402, ERROR_CODE_UNSPECIFIED, 3);
+ }
+
+ static class UserLifecycleJourneyReportedCaptor {
+ ArgumentCaptor<Long> mSessionId = ArgumentCaptor.forClass(Long.class);
+ ArgumentCaptor<Integer> mJourney = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mOriginalUserId = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mTargetUserId = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mUserType = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mUserFlags = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mErrorCode = ArgumentCaptor.forClass(Integer.class);
+
+ public void captureAndAssert(UserJourneyLogger mUserJourneyLogger,
+ long sessionId, int journey, int originalUserId,
+ int targetUserId, int userType, int userFlags, int errorCode, int times) {
+ verify(mUserJourneyLogger, times(times))
+ .writeUserLifecycleJourneyReported(mSessionId.capture(),
+ mJourney.capture(),
+ mOriginalUserId.capture(),
+ mTargetUserId.capture(),
+ mUserType.capture(),
+ mUserFlags.capture(),
+ mErrorCode.capture());
+
+ assertThat(mSessionId.getValue()).isEqualTo(sessionId);
+ assertThat(mJourney.getValue()).isEqualTo(journey);
+ assertThat(mOriginalUserId.getValue()).isEqualTo(originalUserId);
+ assertThat(mTargetUserId.getValue()).isEqualTo(targetUserId);
+ assertThat(mUserType.getValue()).isEqualTo(userType);
+ assertThat(mUserFlags.getValue()).isEqualTo(userFlags);
+ assertThat(mErrorCode.getValue()).isEqualTo(errorCode);
+ }
+
+
+ public void captureLogAndAssert(UserJourneyLogger mUserJourneyLogger,
+ UserJourneyLogger.UserJourneySession session, int journey, int originalUserId,
+ int targetUserId, int userType, int userFlags, int errorCode) {
+ mUserJourneyLogger.logUserLifecycleJourneyReported(session, journey, originalUserId,
+ targetUserId, userType, userFlags, errorCode);
+
+ captureAndAssert(mUserJourneyLogger, session.mSessionId, journey, originalUserId,
+ targetUserId, userType, userFlags, errorCode, 1);
+ }
+ }
+
+
+ static class UserLifecycleEventOccurredCaptor {
+ ArgumentCaptor<Long> mSessionId = ArgumentCaptor.forClass(Long.class);
+ ArgumentCaptor<Integer> mTargetUserId = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mEvent = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mStste = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> mErrorCode = ArgumentCaptor.forClass(Integer.class);
+
+
+ public void captureAndAssert(UserJourneyLogger mUserJourneyLogger,
+ long sessionId, int targetUserId, int event, int state, int errorCode, int times) {
+ verify(mUserJourneyLogger, times(times))
+ .writeUserLifecycleEventOccurred(mSessionId.capture(),
+ mTargetUserId.capture(),
+ mEvent.capture(),
+ mStste.capture(),
+ mErrorCode.capture());
+
+ assertThat(mSessionId.getValue()).isEqualTo(sessionId);
+ assertThat(mTargetUserId.getValue()).isEqualTo(targetUserId);
+ assertThat(mEvent.getValue()).isEqualTo(event);
+ assertThat(mStste.getValue()).isEqualTo(state);
+ assertThat(mErrorCode.getValue()).isEqualTo(errorCode);
+ }
+
+
+ public void captureLogAndAssert(UserJourneyLogger mUserJourneyLogger,
+ UserJourneyLogger.UserJourneySession session, int targetUserId, int event,
+ int state, int errorCode) {
+ mUserJourneyLogger.logUserLifecycleEventOccurred(session, targetUserId, event,
+ state, errorCode);
+
+ captureAndAssert(mUserJourneyLogger, session.mSessionId, targetUserId, event,
+ state, errorCode, 1);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 52bf244..ae3ceb1 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -20,6 +20,7 @@
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_ERRORED;
+import static android.os.PowerManager.USER_ACTIVITY_EVENT_BUTTON;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
@@ -41,6 +42,7 @@
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -112,6 +114,7 @@
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
+import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -2468,4 +2471,18 @@
verify(mNotifierMock).onWakeLockReleased(anyInt(), eq(tag), eq(packageName), anyInt(),
anyInt(), any(), any(), same(callback2));
}
+
+ @Test
+ public void testUserActivity_futureEventsAreIgnored() {
+ createService();
+ startSystem();
+ // Starting the system triggers a user activity event, so clear that before calling
+ // userActivity() directly.
+ clearInvocations(mNotifierMock);
+ final long eventTime = mClock.now() + Duration.ofHours(10).toMillis();
+ mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, eventTime,
+ USER_ACTIVITY_EVENT_BUTTON, /* flags= */ 0);
+ verify(mNotifierMock, never()).onUserActivity(anyInt(), anyInt(), anyInt());
+ }
+
}
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/DeviceStateHandlerTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/DeviceStateHandlerTest.java
new file mode 100644
index 0000000..089bd45
--- /dev/null
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/DeviceStateHandlerTest.java
@@ -0,0 +1,261 @@
+/*
+ * 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 android.os.PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED;
+import static android.os.PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED;
+import static android.os.PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY;
+
+import static com.android.server.soundtrigger.DeviceStateHandler.SoundTriggerDeviceState;
+import static com.android.server.soundtrigger.DeviceStateHandler.SoundTriggerDeviceState.*;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.SystemClock;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.utils.EventLogger;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public final class DeviceStateHandlerTest {
+ private final long CONFIRM_NO_EVENT_WAIT_MS = 1000;
+ // A wait substantially less than the duration we delay phone notifications by
+ private final long PHONE_DELAY_BRIEF_WAIT_MS =
+ DeviceStateHandler.CALL_INACTIVE_MSG_DELAY_MS / 4;
+
+ private DeviceStateHandler mHandler;
+ private DeviceStateHandler.DeviceStateListener mDeviceStateCallback;
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private SoundTriggerDeviceState mState;
+
+ @GuardedBy("mLock")
+ private CountDownLatch mLatch;
+
+ private EventLogger mEventLogger;
+
+ @Before
+ public void setup() {
+ // Reset the state prior to each test
+ mEventLogger = new EventLogger(256, "test logger");
+ synchronized (mLock) {
+ mLatch = new CountDownLatch(1);
+ }
+ mDeviceStateCallback =
+ (SoundTriggerDeviceState state) -> {
+ synchronized (mLock) {
+ mState = state;
+ mLatch.countDown();
+ }
+ };
+ mHandler = new DeviceStateHandler(Runnable::run, mEventLogger);
+ mHandler.onPhoneCallStateChanged(false);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_ENABLED);
+ mHandler.registerListener(mDeviceStateCallback);
+ try {
+ waitAndAssertState(ENABLE);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void waitAndAssertState(SoundTriggerDeviceState state) throws InterruptedException {
+ CountDownLatch latch;
+ synchronized (mLock) {
+ latch = mLatch;
+ }
+ latch.await();
+ synchronized (mLock) {
+ assertThat(mState).isEqualTo(state);
+ mLatch = new CountDownLatch(1);
+ }
+ }
+
+ private void waitToConfirmNoEventReceived() throws InterruptedException {
+ CountDownLatch latch;
+ synchronized (mLock) {
+ latch = mLatch;
+ }
+ // Check that we time out
+ assertThat(latch.await(CONFIRM_NO_EVENT_WAIT_MS, TimeUnit.MILLISECONDS)).isFalse();
+ }
+
+ @Test
+ public void onPowerModeChangedCritical_receiveStateChange() throws Exception {
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitAndAssertState(CRITICAL);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_ENABLED);
+ waitAndAssertState(ENABLE);
+ }
+
+ @Test
+ public void onPowerModeChangedDisabled_receiveStateChange() throws Exception {
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitAndAssertState(DISABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_ENABLED);
+ waitAndAssertState(ENABLE);
+ }
+
+ @Test
+ public void onPowerModeChangedMultiple_receiveStateChange() throws Exception {
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitAndAssertState(DISABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitAndAssertState(CRITICAL);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitAndAssertState(DISABLE);
+ }
+
+ @Test
+ public void onPowerModeSameState_noStateChange() throws Exception {
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitAndAssertState(DISABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitToConfirmNoEventReceived();
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitAndAssertState(CRITICAL);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitToConfirmNoEventReceived();
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_ENABLED);
+ waitAndAssertState(ENABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_ENABLED);
+ waitToConfirmNoEventReceived();
+ }
+
+ @Test
+ public void onPhoneCall_receiveStateChange() throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPhoneCallStateChanged(false);
+ waitAndAssertState(ENABLE);
+ }
+
+ @Test
+ public void onPhoneCall_receiveStateChangeIsDelayed() throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ long beforeTime = SystemClock.uptimeMillis();
+ mHandler.onPhoneCallStateChanged(false);
+ waitAndAssertState(ENABLE);
+ long afterTime = SystemClock.uptimeMillis();
+ assertThat(afterTime - beforeTime).isAtLeast(DeviceStateHandler.CALL_INACTIVE_MSG_DELAY_MS);
+ }
+
+ @Test
+ public void onPhoneCallEnterExitEnter_receiveNoStateChange() throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPhoneCallStateChanged(false);
+ SystemClock.sleep(PHONE_DELAY_BRIEF_WAIT_MS);
+ mHandler.onPhoneCallStateChanged(true);
+ waitToConfirmNoEventReceived();
+ }
+
+ @Test
+ public void onBatteryCallbackDuringPhoneWait_receiveStateChangeDelayed() throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPhoneCallStateChanged(false);
+ SystemClock.sleep(PHONE_DELAY_BRIEF_WAIT_MS);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitAndAssertState(CRITICAL);
+ // Ensure we don't get an ENABLE event after
+ waitToConfirmNoEventReceived();
+ }
+
+ @Test
+ public void onBatteryChangeWhenInPhoneCall_receiveNoStateChange() throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_ENABLED);
+ waitToConfirmNoEventReceived();
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitToConfirmNoEventReceived();
+ }
+
+ @Test
+ public void whenBatteryCriticalChangeDuringCallAfterPhoneCall_receiveCriticalStateChange()
+ throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitToConfirmNoEventReceived();
+ mHandler.onPhoneCallStateChanged(false);
+ waitAndAssertState(CRITICAL);
+ }
+
+ @Test
+ public void whenBatteryDisableDuringCallAfterPhoneCallBatteryEnable_receiveStateChange()
+ throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitToConfirmNoEventReceived();
+ mHandler.onPhoneCallStateChanged(false);
+ waitToConfirmNoEventReceived();
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitAndAssertState(CRITICAL);
+ }
+
+ @Test
+ public void whenPhoneCallDuringBatteryDisable_receiveNoStateChange() throws Exception {
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_ALL_DISABLED);
+ waitAndAssertState(DISABLE);
+ mHandler.onPhoneCallStateChanged(true);
+ waitToConfirmNoEventReceived();
+ mHandler.onPhoneCallStateChanged(false);
+ waitToConfirmNoEventReceived();
+ }
+
+ @Test
+ public void whenPhoneCallDuringBatteryCritical_receiveStateChange() throws Exception {
+ mHandler.onPowerModeChanged(SOUND_TRIGGER_MODE_CRITICAL_ONLY);
+ waitAndAssertState(CRITICAL);
+ mHandler.onPhoneCallStateChanged(true);
+ waitAndAssertState(DISABLE);
+ mHandler.onPhoneCallStateChanged(false);
+ waitAndAssertState(CRITICAL);
+ }
+
+ // This test could be flaky, but we want to verify that we only delay notification if
+ // we are exiting a call, NOT if we are entering a call.
+ @FlakyTest
+ @Test
+ public void whenPhoneCallReceived_receiveStateChangeFast() throws Exception {
+ mHandler.onPhoneCallStateChanged(true);
+ CountDownLatch latch;
+ synchronized (mLock) {
+ latch = mLatch;
+ }
+ assertThat(latch.await(PHONE_DELAY_BRIEF_WAIT_MS, TimeUnit.MILLISECONDS)).isTrue();
+ synchronized (mLock) {
+ assertThat(mState).isEqualTo(DISABLE);
+ }
+ }
+}
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
index 2d0755d..3ac9a27 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
@@ -16,6 +16,8 @@
package com.android.server.soundtrigger_middleware;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -34,12 +36,12 @@
import static org.mockito.Mockito.when;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.HwParcel;
import android.os.IBinder;
import android.os.IHwBinder;
@@ -617,13 +619,16 @@
final int handle = 85;
final int status =
android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT;
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
hwCallback.recognitionCallback(TestUtil.createRecognitionEvent_2_0(handle, status), 99);
mCanonical.flushCallbacks();
verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
- TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.ABORTED,
+ RecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+ TestUtil.validateRecognitionEvent(lastEvent.recognitionEvent,
+ RecognitionStatus.ABORTED,
false);
}
@@ -631,14 +636,16 @@
final int handle = 92;
final int status =
android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS;
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
hwCallback.phraseRecognitionCallback(
TestUtil.createPhraseRecognitionEvent_2_0(handle, status), 99);
mCanonical.flushCallbacks();
verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
- TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
+ PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+ TestUtil.validatePhraseRecognitionEvent(lastEvent.phraseRecognitionEvent,
RecognitionStatus.SUCCESS, false);
}
verifyNoMoreInteractions(canonicalCallback);
@@ -652,28 +659,34 @@
final int handle = 85;
final int status =
android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT;
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
hwCallback.recognitionCallback_2_1(TestUtil.createRecognitionEvent_2_1(handle, status),
99);
mCanonical.flushCallbacks();
verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
- TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.ABORTED,
+ RecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+ TestUtil.validateRecognitionEvent(lastEvent.recognitionEvent,
+ RecognitionStatus.ABORTED,
false);
}
{
final int handle = 87;
final int status = 3; // FORCED;
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
hwCallback.recognitionCallback_2_1(TestUtil.createRecognitionEvent_2_1(handle, status),
99);
mCanonical.flushCallbacks();
verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
- TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.FORCED,
+ RecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+ TestUtil.validateRecognitionEvent(lastEvent.recognitionEvent,
+ RecognitionStatus.FORCED,
true);
}
@@ -681,28 +694,32 @@
final int handle = 92;
final int status =
android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS;
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
hwCallback.phraseRecognitionCallback_2_1(
TestUtil.createPhraseRecognitionEvent_2_1(handle, status), 99);
mCanonical.flushCallbacks();
verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
- TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
+ PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+ TestUtil.validatePhraseRecognitionEvent(lastEvent.phraseRecognitionEvent,
RecognitionStatus.SUCCESS, false);
}
{
final int handle = 102;
final int status = 3; // FORCED;
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
hwCallback.phraseRecognitionCallback_2_1(
TestUtil.createPhraseRecognitionEvent_2_1(handle, status), 99);
mCanonical.flushCallbacks();
verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
- TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
+ PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+ TestUtil.validatePhraseRecognitionEvent(lastEvent.phraseRecognitionEvent,
RecognitionStatus.FORCED, true);
}
verifyNoMoreInteractions(canonicalCallback);
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java
index 6198925..9a59ede 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java
@@ -30,8 +30,8 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import androidx.annotation.NonNull;
@@ -68,13 +68,14 @@
mNotifier.setActive(true);
verify(mUnderlying).stopRecognition(handle);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
Thread.sleep(50);
verify(callback).recognitionCallback(eq(handle), eventCaptor.capture());
- RecognitionEvent event = eventCaptor.getValue();
- assertEquals(event.status, RecognitionStatus.ABORTED);
- assertFalse(event.recognitionStillActive);
+ RecognitionEventSys event = eventCaptor.getValue();
+ assertEquals(event.halEventReceivedMillis, -1);
+ assertEquals(event.recognitionEvent.status, RecognitionStatus.ABORTED);
+ assertFalse(event.recognitionEvent.recognitionStillActive);
verifyZeroInteractions(mGlobalCallback);
clearInvocations(callback, mUnderlying);
@@ -116,8 +117,11 @@
mNotifier.setActive(true);
verify(mUnderlying, times(1)).stopRecognition(handle);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
mHandler.stopRecognition(handle);
- verify(callback, times(1)).recognitionCallback(eq(handle), any());
+ verify(callback).recognitionCallback(eq(handle), eventCaptor.capture());
+ assertEquals(eventCaptor.getValue().halEventReceivedMillis, -1);
}
@Test(timeout = 200)
@@ -133,19 +137,21 @@
verify(mUnderlying).startRecognition(eq(handle), eq(101), eq(102), any());
doAnswer(invocation -> {
- RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.ABORTED,
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+ RecognitionStatus.ABORTED,
false);
+ recognitionEventSys.halEventReceivedMillis = 12345;
// Call the callback from a different thread to detect deadlocks by preventing recursive
// locking from working.
- runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+ runOnSeparateThread(
+ () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
return null;
}).when(mUnderlying).stopRecognition(handle);
mHandler.stopRecognition(handle);
verify(mUnderlying, times(1)).stopRecognition(handle);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
- verify(callback, atMost(1)).recognitionCallback(eq(handle), eventCaptor.capture());
+ verify(callback, atMost(1)).recognitionCallback(eq(handle), any(RecognitionEventSys.class));
}
@Test(timeout = 200)
@@ -162,11 +168,15 @@
doAnswer(invocation -> {
// The stop request causes a callback to be flushed.
- RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.FORCED,
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+ RecognitionStatus.FORCED,
true);
+ recognitionEventSys.halEventReceivedMillis = 12345;
// Call the callback from a different thread to detect deadlocks by preventing recursive
// locking from working.
- runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+ runOnSeparateThread(
+ () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
// While the HAL is processing the stop request, capture state becomes active.
new Thread(() -> mNotifier.setActive(true)).start();
Thread.sleep(50);
@@ -194,11 +204,15 @@
doAnswer(invocation -> {
// The stop request causes a callback to be flushed.
- RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.FORCED,
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+ RecognitionStatus.FORCED,
true);
+ recognitionEventSys.halEventReceivedMillis = 12345;
// Call the callback from a different thread to detect deadlocks by preventing recursive
// locking from working.
- runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+ runOnSeparateThread(
+ () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
// While the HAL is processing the stop request, client requests stop.
new Thread(() -> mHandler.stopRecognition(handle)).start();
Thread.sleep(50);
@@ -223,23 +237,22 @@
verify(mUnderlying).startRecognition(eq(handle), eq(101), eq(102), any());
doAnswer(invocation -> {
- RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.SUCCESS,
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+ RecognitionStatus.SUCCESS,
false);
+ recognitionEventSys.halEventReceivedMillis = 12345;
// Call the callback from a different thread to detect deadlocks by preventing recursive
// locking from working.
- runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+ runOnSeparateThread(
+ () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
return null;
}).when(mUnderlying).stopRecognition(handle);
mNotifier.setActive(true);
verify(mUnderlying, times(1)).stopRecognition(handle);
Thread.sleep(50);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
- verify(callback, atMost(2)).recognitionCallback(eq(handle), eventCaptor.capture());
- RecognitionEvent lastEvent = eventCaptor.getValue();
- assertEquals(lastEvent.status, RecognitionStatus.ABORTED);
- assertFalse(lastEvent.recognitionStillActive);
+ verify(callback, atMost(2)).recognitionCallback(eq(handle), any());
}
@@ -256,11 +269,15 @@
verify(mUnderlying).startRecognition(eq(handle), eq(101), eq(102), any());
doAnswer(invocation -> {
- RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.FORCED,
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+ RecognitionStatus.FORCED,
true);
+ recognitionEventSys.halEventReceivedMillis = 12345;
// Call the callback from a different thread to detect deadlocks by preventing recursive
// locking from working.
- runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+ runOnSeparateThread(
+ () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
return null;
}).when(mUnderlying).stopRecognition(handle);
@@ -268,12 +285,7 @@
verify(mUnderlying, times(1)).stopRecognition(handle);
Thread.sleep(50);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
- verify(callback, atMost(2)).recognitionCallback(eq(handle), eventCaptor.capture());
- RecognitionEvent lastEvent = eventCaptor.getValue();
- assertEquals(lastEvent.status, RecognitionStatus.ABORTED);
- assertFalse(lastEvent.recognitionStillActive);
+ verify(callback, atMost(2)).recognitionCallback(eq(handle), any());
}
private static void runOnSeparateThread(Runnable runnable) {
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
index 3bebc94..5a2451f 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
@@ -30,18 +30,19 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.ElapsedRealtimeLong;
import android.media.soundtrigger.ModelParameter;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.os.RemoteException;
import android.util.Pair;
@@ -224,10 +225,12 @@
// Stop the recognition.
stopRecognition(module, handle, hwHandle);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
- assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status);
+ RecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertEquals(-1, lastEvent.halEventReceivedMillis);
+ assertEquals(RecognitionStatus.ABORTED, lastEvent.recognitionEvent.status);
// Unload the model.
unloadModel(module, handle, hwHandle);
@@ -273,10 +276,12 @@
// Stop the recognition.
stopRecognition(module, handle, hwHandle);
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
- assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status);
+ PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertEquals(-1, lastEvent.halEventReceivedMillis);
+ assertEquals(RecognitionStatus.ABORTED, lastEvent.phraseRecognitionEvent.common.status);
// Unload the model.
unloadModel(module, handle, hwHandle);
@@ -299,11 +304,11 @@
{
// Signal a capture from the driver (with "still active").
- RecognitionEvent event = hwCallback.sendRecognitionEvent(hwHandle,
- RecognitionStatus.SUCCESS, true);
+ RecognitionEventSys event = hwCallback.sendRecognitionEvent(hwHandle,
+ RecognitionStatus.SUCCESS, true, 12345);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
@@ -312,11 +317,11 @@
{
// Signal a capture from the driver (without "still active").
- RecognitionEvent event = hwCallback.sendRecognitionEvent(hwHandle,
- RecognitionStatus.SUCCESS, false);
+ RecognitionEventSys event = hwCallback.sendRecognitionEvent(hwHandle,
+ RecognitionStatus.SUCCESS, false, 12345);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
verify(callback, times(2)).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
@@ -343,11 +348,11 @@
startRecognition(module, handle, hwHandle);
// Signal a capture from the driver.
- PhraseRecognitionEvent event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
- RecognitionStatus.SUCCESS, false);
+ PhraseRecognitionEventSys event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
+ RecognitionStatus.SUCCESS, false, 12345);
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
@@ -377,11 +382,11 @@
verify(mHalDriver).forceRecognitionEvent(hwHandle);
// Signal a capture from the driver.
- RecognitionEvent event = hwCallback.sendRecognitionEvent(hwHandle,
- RecognitionStatus.FORCED, true);
+ RecognitionEventSys event = hwCallback.sendRecognitionEvent(hwHandle,
+ RecognitionStatus.FORCED, true, 12345);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
@@ -445,11 +450,11 @@
verify(mHalDriver).forceRecognitionEvent(hwHandle);
// Signal a capture from the driver.
- PhraseRecognitionEvent event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
- RecognitionStatus.FORCED, true);
+ PhraseRecognitionEventSys event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
+ RecognitionStatus.FORCED, true, 12345);
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
@@ -510,14 +515,16 @@
startRecognition(module, handle, hwHandle);
// Abort.
- hwCallback.sendRecognitionEvent(hwHandle, RecognitionStatus.ABORTED, false);
+ hwCallback.sendRecognitionEvent(hwHandle, RecognitionStatus.ABORTED, false, 12345);
- ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- RecognitionEvent.class);
+ ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEventSys.class);
verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
- assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status);
+ RecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertEquals(12345, lastEvent.halEventReceivedMillis);
+ assertEquals(RecognitionStatus.ABORTED, lastEvent.recognitionEvent.status);
// Unload the model.
unloadModel(module, handle, hwHandle);
@@ -540,14 +547,16 @@
startRecognition(module, handle, hwHandle);
// Abort.
- hwCallback.sendPhraseRecognitionEvent(hwHandle, RecognitionStatus.ABORTED, false);
+ hwCallback.sendPhraseRecognitionEvent(hwHandle, RecognitionStatus.ABORTED, false, 12345);
- ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
- PhraseRecognitionEvent.class);
+ ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEventSys.class);
verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
// Validate the event.
- assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status);
+ PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+ assertEquals(12345, lastEvent.halEventReceivedMillis);
+ assertEquals(RecognitionStatus.ABORTED, lastEvent.phraseRecognitionEvent.common.status);
// Unload the model.
unloadModel(module, handle, hwHandle);
@@ -630,18 +639,24 @@
mCallback = callback;
}
- private RecognitionEvent sendRecognitionEvent(int hwHandle, @RecognitionStatus int status,
- boolean recognitionStillActive) {
- RecognitionEvent event = TestUtil.createRecognitionEvent(status,
+ private RecognitionEventSys sendRecognitionEvent(int hwHandle,
+ @RecognitionStatus int status,
+ boolean recognitionStillActive, @ElapsedRealtimeLong long halEventReceivedMillis) {
+ RecognitionEventSys event = new RecognitionEventSys();
+ event.recognitionEvent = TestUtil.createRecognitionEvent(status,
recognitionStillActive);
+ event.halEventReceivedMillis = halEventReceivedMillis;
mCallback.recognitionCallback(hwHandle, event);
return event;
}
- private PhraseRecognitionEvent sendPhraseRecognitionEvent(int hwHandle,
- @RecognitionStatus int status, boolean recognitionStillActive) {
- PhraseRecognitionEvent event = TestUtil.createPhraseRecognitionEvent(status,
+ private PhraseRecognitionEventSys sendPhraseRecognitionEvent(int hwHandle,
+ @RecognitionStatus int status, boolean recognitionStillActive,
+ @ElapsedRealtimeLong long halEventReceivedMillis) {
+ PhraseRecognitionEventSys event = new PhraseRecognitionEventSys();
+ event.phraseRecognitionEvent = TestUtil.createPhraseRecognitionEvent(status,
recognitionStillActive);
+ event.halEventReceivedMillis = halEventReceivedMillis;
mCallback.phraseRecognitionCallback(hwHandle, event);
return event;
}
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
index f8a068c..cc357d7 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
@@ -32,7 +32,7 @@
import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
-import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
import android.os.BatteryStatsInternal;
import android.os.Process;
import android.os.RemoteException;
@@ -51,8 +51,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Optional;
-
@RunWith(JUnit4.class)
public class SoundTriggerMiddlewareLoggingLatencyTest {
@@ -63,8 +61,6 @@
private ISoundTriggerMiddlewareInternal mDelegateMiddleware;
@Mock
private ISoundTriggerCallback mISoundTriggerCallback;
- @Mock
- private ISoundTriggerModule mSoundTriggerModule;
private SoundTriggerMiddlewareLogging mSoundTriggerMiddlewareLogging;
@Before
@@ -109,7 +105,7 @@
verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
- RecognitionStatus.SUCCESS, Optional.of(100) /* keyphraseId */);
+ RecognitionStatus.SUCCESS, 100 /* keyphraseId */);
assertThat(mLatencyTracker.getActiveActionStartTime(
ACTION_SHOW_VOICE_INTERACTION)).isGreaterThan(-1);
@@ -124,11 +120,11 @@
verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
- RecognitionStatus.SUCCESS, Optional.of(100) /* keyphraseId */);
+ RecognitionStatus.SUCCESS, 100 /* keyphraseId */);
long firstTriggerSessionStartTime = mLatencyTracker.getActiveActionStartTime(
ACTION_SHOW_VOICE_INTERACTION);
triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
- RecognitionStatus.SUCCESS, Optional.of(100) /* keyphraseId */);
+ RecognitionStatus.SUCCESS, 100 /* keyphraseId */);
assertThat(mLatencyTracker.getActiveActionStartTime(
ACTION_SHOW_VOICE_INTERACTION)).isGreaterThan(-1);
assertThat(mLatencyTracker.getActiveActionStartTime(
@@ -145,7 +141,7 @@
verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
- RecognitionStatus.ABORTED, Optional.of(100) /* keyphraseId */);
+ RecognitionStatus.ABORTED, 100 /* keyphraseId */);
assertThat(
mLatencyTracker.getActiveActionStartTime(ACTION_SHOW_VOICE_INTERACTION)).isEqualTo(
@@ -162,7 +158,7 @@
verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
- RecognitionStatus.SUCCESS, Optional.empty() /* keyphraseId */);
+ RecognitionStatus.SUCCESS);
assertThat(
mLatencyTracker.getActiveActionStartTime(ACTION_SHOW_VOICE_INTERACTION)).isEqualTo(
@@ -170,19 +166,27 @@
}
private void triggerPhraseRecognitionEvent(ISoundTriggerCallback callback,
- @RecognitionStatus int triggerEventStatus, Optional<Integer> optionalKeyphraseId)
- throws RemoteException {
+ @RecognitionStatus int triggerEventStatus) throws RemoteException {
+ triggerPhraseRecognitionEvent(callback, triggerEventStatus, -1 /* keyphraseId */);
+ }
+
+ private void triggerPhraseRecognitionEvent(ISoundTriggerCallback callback,
+ @RecognitionStatus int triggerEventStatus, int keyphraseId) throws RemoteException {
// trigger a phrase recognition to start a latency tracker session
PhraseRecognitionEvent successEventWithKeyphraseId = new PhraseRecognitionEvent();
successEventWithKeyphraseId.common = new RecognitionEvent();
successEventWithKeyphraseId.common.status = triggerEventStatus;
- if (optionalKeyphraseId.isPresent()) {
+ if (keyphraseId > 0) {
PhraseRecognitionExtra recognitionExtra = new PhraseRecognitionExtra();
- recognitionExtra.id = optionalKeyphraseId.get();
+ recognitionExtra.id = keyphraseId;
successEventWithKeyphraseId.phraseExtras =
new PhraseRecognitionExtra[]{recognitionExtra};
}
- callback.onPhraseRecognition(0 /* modelHandle */, successEventWithKeyphraseId,
+ PhraseRecognitionEventSys phraseRecognitionEventSys = new PhraseRecognitionEventSys();
+ phraseRecognitionEventSys.phraseRecognitionEvent = successEventWithKeyphraseId;
+ phraseRecognitionEventSys.halEventReceivedMillis = 12345;
+ callback.onPhraseRecognition(0 /* modelHandle */, phraseRecognitionEventSys,
0 /* captureSession */);
}
+
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncherTest.java b/services/tests/wmtests/src/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncherTest.java
new file mode 100644
index 0000000..cc8dab9
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncherTest.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.TRANSIT_CHANGE;
+
+import static com.android.server.wm.DeviceStateController.DeviceState.FOLDED;
+import static com.android.server.wm.DeviceStateController.DeviceState.HALF_FOLDED;
+import static com.android.server.wm.DeviceStateController.DeviceState.OPEN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.window.TransitionRequestInfo.DisplayChange;
+
+import static com.android.internal.R.bool.config_unfoldTransitionEnabled;
+import static com.android.server.wm.DeviceStateController.DeviceState.REAR;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for the {@link WindowToken} class.
+ *
+ * Build/Install/Run:
+ * atest WmTests:PhysicalDisplaySwitchTransitionLauncherTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class PhysicalDisplaySwitchTransitionLauncherTest extends WindowTestsBase {
+
+ @Mock
+ DisplayContent mDisplayContent;
+ @Mock
+ Context mContext;
+ @Mock
+ Resources mResources;
+ @Mock
+ ActivityTaskManagerService mActivityTaskManagerService;
+ @Mock
+ TransitionController mTransitionController;
+
+ private PhysicalDisplaySwitchTransitionLauncher mTarget;
+ private float mOriginalAnimationScale;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getResources()).thenReturn(mResources);
+ mTarget = new PhysicalDisplaySwitchTransitionLauncher(mDisplayContent,
+ mActivityTaskManagerService, mContext, mTransitionController);
+ mOriginalAnimationScale = ValueAnimator.getDurationScale();
+ }
+
+ @After
+ public void after() {
+ ValueAnimator.setDurationScale(mOriginalAnimationScale);
+ }
+
+ @Test
+ public void testDisplaySwitchAfterUnfoldToOpen_animationsEnabled_requestsTransition() {
+ givenAllAnimationsEnabled();
+ mTarget.foldStateChanged(FOLDED);
+
+ mTarget.foldStateChanged(OPEN);
+ mTarget.requestDisplaySwitchTransitionIfNeeded(
+ /* displayId= */ 123,
+ /* oldDisplayWidth= */ 100,
+ /* oldDisplayHeight= */ 150,
+ /* newDisplayWidth= */ 200,
+ /* newDisplayHeight= */ 250
+ );
+
+ ArgumentCaptor<DisplayChange> displayChangeArgumentCaptor =
+ ArgumentCaptor.forClass(DisplayChange.class);
+ verify(mTransitionController).requestTransitionIfNeeded(eq(TRANSIT_CHANGE), /* flags= */
+ eq(0), eq(mDisplayContent), eq(mDisplayContent), /* remoteTransition= */ isNull(),
+ displayChangeArgumentCaptor.capture());
+ assertThat(displayChangeArgumentCaptor.getValue().getDisplayId()).isEqualTo(123);
+ assertThat(displayChangeArgumentCaptor.getValue().getStartAbsBounds()).isEqualTo(
+ new Rect(0, 0, 100, 150));
+ assertThat(displayChangeArgumentCaptor.getValue().getEndAbsBounds()).isEqualTo(
+ new Rect(0, 0, 200, 250));
+ }
+
+ @Test
+ public void testDisplaySwitchAfterFolding_animationEnabled_doesNotRequestTransition() {
+ givenAllAnimationsEnabled();
+ mTarget.foldStateChanged(OPEN);
+
+ mTarget.foldStateChanged(FOLDED);
+ requestDisplaySwitch();
+
+ assertTransitionNotRequested();
+ }
+
+ @Test
+ public void testDisplaySwitchAfterUnfoldingToHalf_animationEnabled_requestsTransition() {
+ givenAllAnimationsEnabled();
+ mTarget.foldStateChanged(FOLDED);
+
+ mTarget.foldStateChanged(HALF_FOLDED);
+ requestDisplaySwitch();
+
+ assertTransitionRequested();
+ }
+
+ @Test
+ public void testDisplaySwitchSecondTimeAfterUnfolding_animationEnabled_noTransition() {
+ givenAllAnimationsEnabled();
+ mTarget.foldStateChanged(FOLDED);
+ mTarget.foldStateChanged(OPEN);
+ requestDisplaySwitch();
+ clearInvocations(mTransitionController);
+
+ requestDisplaySwitch();
+
+ assertTransitionNotRequested();
+ }
+
+
+ @Test
+ public void testDisplaySwitchAfterGoingToRearAndBack_animationEnabled_noTransition() {
+ givenAllAnimationsEnabled();
+ mTarget.foldStateChanged(OPEN);
+
+ mTarget.foldStateChanged(REAR);
+ mTarget.foldStateChanged(OPEN);
+ requestDisplaySwitch();
+
+ assertTransitionNotRequested();
+ }
+
+ @Test
+ public void testDisplaySwitchAfterUnfoldingAndFolding_animationEnabled_noTransition() {
+ givenAllAnimationsEnabled();
+ mTarget.foldStateChanged(FOLDED);
+ mTarget.foldStateChanged(OPEN);
+ // No request display switch event (simulate very fast fold after unfold, even before
+ // the displays switched)
+ mTarget.foldStateChanged(FOLDED);
+
+ requestDisplaySwitch();
+
+ assertTransitionNotRequested();
+ }
+
+ @Test
+ public void testDisplaySwitch_whenShellTransitionsNotEnabled_noTransition() {
+ givenAllAnimationsEnabled();
+ givenShellTransitionsEnabled(false);
+ mTarget.foldStateChanged(FOLDED);
+
+ mTarget.foldStateChanged(OPEN);
+ requestDisplaySwitch();
+
+ assertTransitionNotRequested();
+ }
+
+ @Test
+ public void testDisplaySwitch_whenAnimationsDisabled_noTransition() {
+ givenAllAnimationsEnabled();
+ givenAnimationsEnabled(false);
+ mTarget.foldStateChanged(FOLDED);
+
+ mTarget.foldStateChanged(OPEN);
+ requestDisplaySwitch();
+
+ assertTransitionNotRequested();
+ }
+
+ @Test
+ public void testDisplaySwitch_whenUnfoldAnimationDisabled_noTransition() {
+ givenAllAnimationsEnabled();
+ givenUnfoldTransitionEnabled(false);
+ mTarget.foldStateChanged(FOLDED);
+
+ mTarget.foldStateChanged(OPEN);
+ requestDisplaySwitch();
+
+ assertTransitionNotRequested();
+ }
+
+ @Test
+ public void testDisplaySwitch_whenNoContentInDisplayContent_noTransition() {
+ givenAllAnimationsEnabled();
+ givenDisplayContentHasContent(false);
+ mTarget.foldStateChanged(FOLDED);
+
+ mTarget.foldStateChanged(OPEN);
+ requestDisplaySwitch();
+
+ assertTransitionNotRequested();
+ }
+
+ private void assertTransitionRequested() {
+ verify(mTransitionController).requestTransitionIfNeeded(anyInt(), anyInt(), any(), any(),
+ any(), any());
+ }
+
+ private void assertTransitionNotRequested() {
+ verify(mTransitionController, never()).requestTransitionIfNeeded(anyInt(), anyInt(), any(),
+ any(), any(), any());
+ }
+
+ private void requestDisplaySwitch() {
+ mTarget.requestDisplaySwitchTransitionIfNeeded(
+ /* displayId= */ 123,
+ /* oldDisplayWidth= */ 100,
+ /* oldDisplayHeight= */ 150,
+ /* newDisplayWidth= */ 200,
+ /* newDisplayHeight= */ 250
+ );
+ }
+
+ private void givenAllAnimationsEnabled() {
+ givenAnimationsEnabled(true);
+ givenUnfoldTransitionEnabled(true);
+ givenShellTransitionsEnabled(true);
+ givenDisplayContentHasContent(true);
+ }
+
+ private void givenUnfoldTransitionEnabled(boolean enabled) {
+ when(mResources.getBoolean(config_unfoldTransitionEnabled)).thenReturn(enabled);
+ }
+
+ private void givenAnimationsEnabled(boolean enabled) {
+ ValueAnimator.setDurationScale(enabled ? 1.0f : 0.0f);
+ }
+
+ private void givenShellTransitionsEnabled(boolean enabled) {
+ when(mTransitionController.isShellTransitionsEnabled()).thenReturn(enabled);
+ }
+
+ private void givenDisplayContentHasContent(boolean hasContent) {
+ when(mDisplayContent.getLastHasContent()).thenReturn(hasContent);
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
index c8fc6b8..d84620b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
@@ -32,6 +32,7 @@
import com.android.server.testutils.StubTransaction;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -52,6 +53,11 @@
SurfaceSyncGroup.setTransactionFactory(StubTransaction::new);
}
+ @After
+ public void tearDown() {
+ SurfaceSyncGroup.setTransactionFactory(SurfaceControl.Transaction::new);
+ }
+
@Test
public void testSyncOne() throws InterruptedException {
final CountDownLatch finishedLatch = new CountDownLatch(1);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/DeviceStateHandler.java b/services/voiceinteraction/java/com/android/server/soundtrigger/DeviceStateHandler.java
new file mode 100644
index 0000000..6605449
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/DeviceStateHandler.java
@@ -0,0 +1,279 @@
+/**
+ * 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 android.os.PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED;
+import static android.os.PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED;
+import static android.os.PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.utils.EventLogger;
+
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Manages device state events which require pausing SoundTrigger recognition
+ *
+ * @hide
+ */
+public class DeviceStateHandler implements PhoneCallStateHandler.Callback {
+
+ public static final long CALL_INACTIVE_MSG_DELAY_MS = 1000;
+
+ public interface DeviceStateListener {
+ void onSoundTriggerDeviceStateUpdate(SoundTriggerDeviceState state);
+ }
+
+ public enum SoundTriggerDeviceState {
+ DISABLE, // The device state requires all SoundTrigger sessions are disabled
+ CRITICAL, // The device state requires all non-critical SoundTrigger sessions are disabled
+ ENABLE // The device state permits all SoundTrigger sessions
+ }
+
+ private final Object mLock = new Object();
+
+ private final EventLogger mEventLogger;
+
+ @GuardedBy("mLock")
+ SoundTriggerDeviceState mSoundTriggerDeviceState = SoundTriggerDeviceState.ENABLE;
+
+ // Individual components of the SoundTriggerDeviceState
+ @GuardedBy("mLock")
+ private int mSoundTriggerPowerSaveMode = SOUND_TRIGGER_MODE_ALL_ENABLED;
+
+ @GuardedBy("mLock")
+ private boolean mIsPhoneCallOngoing = false;
+
+ // There can only be one pending notify at any given time.
+ // If any phone state change comes in between, we will cancel the previous pending
+ // task.
+ @GuardedBy("mLock")
+ private NotificationTask mPhoneStateChangePendingNotify = null;
+
+ private Set<DeviceStateListener> mCallbackSet = ConcurrentHashMap.newKeySet(4);
+
+ private final Executor mDelayedNotificationExecutor = Executors.newSingleThreadExecutor();
+
+ private final Executor mCallbackExecutor;
+
+ public void onPowerModeChanged(int soundTriggerPowerSaveMode) {
+ mEventLogger.enqueue(new SoundTriggerPowerEvent(soundTriggerPowerSaveMode));
+ synchronized (mLock) {
+ if (soundTriggerPowerSaveMode == mSoundTriggerPowerSaveMode) {
+ // No state change, nothing to do
+ return;
+ }
+ mSoundTriggerPowerSaveMode = soundTriggerPowerSaveMode;
+ evaluateStateChange();
+ }
+ }
+
+ @Override
+ public void onPhoneCallStateChanged(boolean isInPhoneCall) {
+ mEventLogger.enqueue(new PhoneCallEvent(isInPhoneCall));
+ synchronized (mLock) {
+ if (mIsPhoneCallOngoing == isInPhoneCall) {
+ // no change, nothing to do
+ return;
+ }
+ // Clear any pending notification
+ if (mPhoneStateChangePendingNotify != null) {
+ mPhoneStateChangePendingNotify.cancel();
+ mPhoneStateChangePendingNotify = null;
+ }
+ mIsPhoneCallOngoing = isInPhoneCall;
+ if (!mIsPhoneCallOngoing) {
+ // State has changed from call to no call, delay notification
+ mPhoneStateChangePendingNotify = new NotificationTask(
+ new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ if (mPhoneStateChangePendingNotify != null &&
+ mPhoneStateChangePendingNotify.runnableEquals(this)) {
+
+ mPhoneStateChangePendingNotify = null;
+ evaluateStateChange();
+ }
+ }
+ }
+ },
+ CALL_INACTIVE_MSG_DELAY_MS);
+ mDelayedNotificationExecutor.execute(mPhoneStateChangePendingNotify);
+ } else {
+ evaluateStateChange();
+ }
+ }
+ }
+
+ /** Note, we expect initial callbacks immediately following construction */
+ public DeviceStateHandler(Executor callbackExecutor, EventLogger eventLogger) {
+ mCallbackExecutor = Objects.requireNonNull(callbackExecutor);
+ mEventLogger = Objects.requireNonNull(eventLogger);
+ }
+
+ public SoundTriggerDeviceState getDeviceState() {
+ synchronized (mLock) {
+ return mSoundTriggerDeviceState;
+ }
+ }
+
+ public void registerListener(DeviceStateListener callback) {
+ final var state = getDeviceState();
+ mCallbackExecutor.execute(
+ () -> callback.onSoundTriggerDeviceStateUpdate(state));
+ mCallbackSet.add(callback);
+ }
+
+ public void unregisterListener(DeviceStateListener callback) {
+ mCallbackSet.remove(callback);
+ }
+
+ void dump(PrintWriter pw) {
+ synchronized (mLock) {
+ pw.println("DeviceState: " + mSoundTriggerDeviceState.name());
+ pw.println("PhoneState: " + mIsPhoneCallOngoing);
+ pw.println("PowerSaveMode: " + mSoundTriggerPowerSaveMode);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void evaluateStateChange() {
+ // We should wait until any pending delays are complete to update.
+ // We will eventually get called by the notification task, or something which
+ // cancels it.
+ // Additionally, if there isn't a state change, there is nothing to update.
+ SoundTriggerDeviceState newState = computeState();
+ if (mPhoneStateChangePendingNotify != null || mSoundTriggerDeviceState == newState) {
+ return;
+ }
+
+ mSoundTriggerDeviceState = newState;
+ mEventLogger.enqueue(new DeviceStateEvent(mSoundTriggerDeviceState));
+ final var state = mSoundTriggerDeviceState;
+ for (var callback : mCallbackSet) {
+ mCallbackExecutor.execute(
+ () -> callback.onSoundTriggerDeviceStateUpdate(state));
+ }
+ }
+
+ @GuardedBy("mLock")
+ private SoundTriggerDeviceState computeState() {
+ if (mIsPhoneCallOngoing) {
+ return SoundTriggerDeviceState.DISABLE;
+ }
+ return switch (mSoundTriggerPowerSaveMode) {
+ case SOUND_TRIGGER_MODE_ALL_ENABLED -> SoundTriggerDeviceState.ENABLE;
+ case SOUND_TRIGGER_MODE_CRITICAL_ONLY -> SoundTriggerDeviceState.CRITICAL;
+ case SOUND_TRIGGER_MODE_ALL_DISABLED -> SoundTriggerDeviceState.DISABLE;
+ default -> throw new IllegalStateException(
+ "Received unexpected power state code" + mSoundTriggerPowerSaveMode);
+ };
+ }
+
+ /**
+ * One-shot, cancellable task which runs after a delay. Run must only be called once, from a
+ * single thread. Cancel can be called from any other thread.
+ */
+ private static class NotificationTask implements Runnable {
+ private final Runnable mRunnable;
+ private final long mWaitInMillis;
+
+ private final CountDownLatch mCancelLatch = new CountDownLatch(1);
+
+ NotificationTask(Runnable r, long waitInMillis) {
+ mRunnable = r;
+ mWaitInMillis = waitInMillis;
+ }
+
+ void cancel() {
+ mCancelLatch.countDown();
+ }
+
+ // Used for determining task equality.
+ boolean runnableEquals(Runnable runnable) {
+ return mRunnable == runnable;
+ }
+
+ public void run() {
+ try {
+ if (!mCancelLatch.await(mWaitInMillis, TimeUnit.MILLISECONDS)) {
+ mRunnable.run();
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new AssertionError("Unexpected InterruptedException", e);
+ }
+ }
+ }
+
+ private static class PhoneCallEvent extends EventLogger.Event {
+ final boolean mIsInPhoneCall;
+
+ PhoneCallEvent(boolean isInPhoneCall) {
+ mIsInPhoneCall = isInPhoneCall;
+ }
+
+ @Override
+ public String eventToString() {
+ return "PhoneCallChange - inPhoneCall: " + mIsInPhoneCall;
+ }
+ }
+
+ private static class SoundTriggerPowerEvent extends EventLogger.Event {
+ final int mSoundTriggerPowerState;
+
+ SoundTriggerPowerEvent(int soundTriggerPowerState) {
+ mSoundTriggerPowerState = soundTriggerPowerState;
+ }
+
+ @Override
+ public String eventToString() {
+ return "SoundTriggerPowerChange: " + stateToString();
+ }
+
+ private String stateToString() {
+ return switch (mSoundTriggerPowerState) {
+ case SOUND_TRIGGER_MODE_ALL_ENABLED -> "All enabled";
+ case SOUND_TRIGGER_MODE_CRITICAL_ONLY -> "Critical only";
+ case SOUND_TRIGGER_MODE_ALL_DISABLED -> "All disabled";
+ default -> "Unknown power state: " + mSoundTriggerPowerState;
+ };
+ }
+ }
+
+ private static class DeviceStateEvent extends EventLogger.Event {
+ final SoundTriggerDeviceState mSoundTriggerDeviceState;
+
+ DeviceStateEvent(SoundTriggerDeviceState soundTriggerDeviceState) {
+ mSoundTriggerDeviceState = soundTriggerDeviceState;
+ }
+
+ @Override
+ public String eventToString() {
+ return "DeviceStateChange: " + mSoundTriggerDeviceState.name();
+ }
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java b/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java
new file mode 100644
index 0000000..8773cab
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java
@@ -0,0 +1,158 @@
+/**
+ * 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.telephony.Annotation;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Handles monitoring telephony call state across active subscriptions.
+ *
+ * @hide
+ */
+public class PhoneCallStateHandler {
+
+ public interface Callback {
+ void onPhoneCallStateChanged(boolean isInPhoneCall);
+ }
+
+ private final Object mLock = new Object();
+
+ // Actually never contended due to executor.
+ @GuardedBy("mLock")
+ private final List<MyCallStateListener> mListenerList = new ArrayList<>();
+
+ private final AtomicBoolean mIsPhoneCallOngoing = new AtomicBoolean(false);
+
+ private final SubscriptionManager mSubscriptionManager;
+ private final TelephonyManager mTelephonyManager;
+ private final Callback mCallback;
+
+ private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+
+ public PhoneCallStateHandler(
+ SubscriptionManager subscriptionManager,
+ TelephonyManager telephonyManager,
+ Callback callback) {
+ mSubscriptionManager = Objects.requireNonNull(subscriptionManager);
+ mTelephonyManager = Objects.requireNonNull(telephonyManager);
+ mCallback = Objects.requireNonNull(callback);
+ mSubscriptionManager.addOnSubscriptionsChangedListener(
+ mExecutor,
+ new SubscriptionManager.OnSubscriptionsChangedListener() {
+ @Override
+ public void onSubscriptionsChanged() {
+ updateTelephonyListeners();
+ }
+
+ @Override
+ public void onAddListenerFailed() {
+ Slog.wtf(
+ "SoundTriggerPhoneCallStateHandler",
+ "Failed to add a telephony listener");
+ }
+ });
+ }
+
+ private final class MyCallStateListener extends TelephonyCallback
+ implements TelephonyCallback.CallStateListener {
+
+ final TelephonyManager mTelephonyManagerForSubId;
+
+ // Manager corresponding to the sub-id
+ MyCallStateListener(TelephonyManager telephonyManager) {
+ mTelephonyManagerForSubId = telephonyManager;
+ }
+
+ void cleanup() {
+ mExecutor.execute(() -> mTelephonyManagerForSubId.unregisterTelephonyCallback(this));
+ }
+
+ @Override
+ public void onCallStateChanged(int unused) {
+ updateCallStatus();
+ }
+ }
+
+ /** Compute the current call status, and dispatch callback if it has changed. */
+ private void updateCallStatus() {
+ boolean callStatus = checkCallStatus();
+ if (mIsPhoneCallOngoing.compareAndSet(!callStatus, callStatus)) {
+ mCallback.onPhoneCallStateChanged(callStatus);
+ }
+ }
+
+ /**
+ * Synchronously query the current telephony call state across all subscriptions
+ *
+ * @return - {@code true} if in call, {@code false} if not in call.
+ */
+ private boolean checkCallStatus() {
+ List<SubscriptionInfo> infoList = mSubscriptionManager.getActiveSubscriptionInfoList();
+ if (infoList == null) return false;
+ return infoList.stream()
+ .filter(s -> (s.getSubscriptionId() != SubscriptionManager.INVALID_SUBSCRIPTION_ID))
+ .anyMatch(s -> isCallOngoingFromState(
+ mTelephonyManager
+ .createForSubscriptionId(s.getSubscriptionId())
+ .getCallStateForSubscription()));
+ }
+
+ private void updateTelephonyListeners() {
+ synchronized (mLock) {
+ for (var listener : mListenerList) {
+ listener.cleanup();
+ }
+ mListenerList.clear();
+ List<SubscriptionInfo> infoList = mSubscriptionManager.getActiveSubscriptionInfoList();
+ if (infoList == null) return;
+ infoList.stream()
+ .filter(s -> s.getSubscriptionId()
+ != SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ .map(s -> mTelephonyManager.createForSubscriptionId(s.getSubscriptionId()))
+ .forEach(manager -> {
+ synchronized (mLock) {
+ var listener = new MyCallStateListener(manager);
+ mListenerList.add(listener);
+ manager.registerTelephonyCallback(mExecutor, listener);
+ }
+ });
+ }
+ }
+
+ private static boolean isCallOngoingFromState(@Annotation.CallState int callState) {
+ return switch (callState) {
+ case TelephonyManager.CALL_STATE_IDLE, TelephonyManager.CALL_STATE_RINGING -> false;
+ case TelephonyManager.CALL_STATE_OFFHOOK -> true;
+ default -> throw new IllegalStateException(
+ "Received unexpected call state from Telephony Manager: " + callState);
+ };
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 255db1e..b4066ab 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -16,15 +16,12 @@
package com.android.server.soundtrigger;
+import static com.android.server.soundtrigger.DeviceStateHandler.SoundTriggerDeviceState;
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;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
@@ -45,11 +42,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.PowerManager;
-import android.os.PowerManager.SoundTriggerPowerSaveMode;
import android.os.RemoteException;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -99,37 +92,20 @@
private SoundTriggerModule mModule;
private final Object mLock = new Object();
private final Context mContext;
- private final TelephonyManager mTelephonyManager;
- private final PhoneStateListener mPhoneStateListener;
- private final PowerManager mPowerManager;
// The SoundTriggerManager layer handles multiple recognition models of type generic and
// keyphrase. We store the ModelData here in a hashmap.
- private final HashMap<UUID, ModelData> mModelDataMap;
+ private final HashMap<UUID, ModelData> mModelDataMap = new HashMap<>();
// An index of keyphrase sound models so that we can reach them easily. We support indexing
// keyphrase sound models with a keyphrase ID. Sound model with the same keyphrase ID will
// replace an existing model, thus there is a 1:1 mapping from keyphrase ID to a voice
// sound model.
- private HashMap<Integer, UUID> mKeyphraseUuidMap;
-
- private boolean mCallActive = false;
- private @SoundTriggerPowerSaveMode int mSoundTriggerPowerSaveMode =
- PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED;
+ private final HashMap<Integer, UUID> mKeyphraseUuidMap = new HashMap<>();
// Whether ANY recognition (keyphrase or generic) has been requested.
private boolean mRecognitionRequested = false;
- private PowerSaveModeListener mPowerSaveModeListener;
-
-
- // Handler to process call state changes will delay to allow time for the audio
- // and sound trigger HALs to process the end of call notifications
- // before we re enable pending recognition requests.
- private final Handler mHandler;
- private static final int MSG_CALL_STATE_CHANGED = 0;
- private static final int CALL_INACTIVE_MSG_DELAY_MS = 1000;
-
// TODO(b/269366605) Temporary solution to query correct moduleProperties
private final int mModuleId;
private final Function<SoundTrigger.StatusListener, SoundTriggerModule> mModuleProvider;
@@ -139,16 +115,15 @@
@GuardedBy("mLock")
private boolean mIsDetached = false;
+ @GuardedBy("mLock")
+ private SoundTriggerDeviceState mDeviceState = SoundTriggerDeviceState.DISABLE;
+
SoundTriggerHelper(Context context, EventLogger eventLogger,
@NonNull Function<SoundTrigger.StatusListener, SoundTriggerModule> moduleProvider,
int moduleId,
@NonNull Supplier<List<ModuleProperties>> modulePropertiesProvider) {
mModuleId = moduleId;
mContext = context;
- mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mModelDataMap = new HashMap<UUID, ModelData>();
- mKeyphraseUuidMap = new HashMap<Integer, UUID>();
mModuleProvider = moduleProvider;
mEventLogger = eventLogger;
mModulePropertiesProvider = modulePropertiesProvider;
@@ -157,31 +132,6 @@
} else {
mModule = mModuleProvider.apply(this);
}
- Looper looper = Looper.myLooper();
- if (looper == null) {
- looper = Looper.getMainLooper();
- }
- mPhoneStateListener = new MyCallStateListener(looper);
- if (looper != null) {
- mHandler = new Handler(looper) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_CALL_STATE_CHANGED:
- synchronized (mLock) {
- onCallStateChangedLocked(
- TelephonyManager.CALL_STATE_OFFHOOK == msg.arg1);
- }
- break;
- default:
- Slog.e(TAG, "unknown message in handler:" + msg.what);
- break;
- }
- }
- };
- } else {
- mHandler = null;
- }
}
/**
@@ -373,7 +323,6 @@
modelData.setSoundModel(soundModel);
if (!isRecognitionAllowedByDeviceState(modelData)) {
- initializeDeviceStateListeners();
return STATUS_OK;
}
@@ -497,11 +446,6 @@
modelData.setLoaded();
modelData.clearCallback();
modelData.setRecognitionConfig(null);
-
- if (!computeRecognitionRequestedLocked()) {
- internalClearGlobalStateLocked();
- }
-
return status;
}
}
@@ -638,6 +582,17 @@
}
}
+ public void onDeviceStateChanged(SoundTriggerDeviceState state) {
+ synchronized (mLock) {
+ if (mIsDetached || mDeviceState == state) {
+ // Nothing to update
+ return;
+ }
+ mDeviceState = state;
+ updateAllRecognitionsLocked();
+ }
+ }
+
public int getGenericModelState(UUID modelId) {
synchronized (mLock) {
MetricsLogger.count(mContext, "sth_get_generic_model_state", 1);
@@ -880,25 +835,6 @@
}
}
- private void onCallStateChangedLocked(boolean callActive) {
- if (mCallActive == callActive) {
- // We consider multiple call states as being active
- // so we check if something really changed or not here.
- return;
- }
- mCallActive = callActive;
- updateAllRecognitionsLocked();
- }
-
- private void onPowerSaveModeChangedLocked(
- @SoundTriggerPowerSaveMode int soundTriggerPowerSaveMode) {
- if (mSoundTriggerPowerSaveMode == soundTriggerPowerSaveMode) {
- return;
- }
- mSoundTriggerPowerSaveMode = soundTriggerPowerSaveMode;
- updateAllRecognitionsLocked();
- }
-
private void onModelUnloadedLocked(int modelHandle) {
ModelData modelData = getModelDataForLocked(modelHandle);
if (modelData != null) {
@@ -1011,10 +947,6 @@
return status;
}
status = startRecognitionLocked(model, notifyClientOnError);
- // Initialize power save, call active state monitoring logic.
- if (status == STATUS_OK) {
- initializeDeviceStateListeners();
- }
return status;
} else {
return stopRecognitionLocked(model, notifyClientOnError);
@@ -1040,7 +972,6 @@
}
} finally {
internalClearModelStateLocked();
- internalClearGlobalStateLocked();
if (mModule != null) {
mModule.detach();
try {
@@ -1054,24 +985,6 @@
}
}
- // internalClearGlobalStateLocked() cleans up the telephony and power save listeners.
- private void internalClearGlobalStateLocked() {
- // Unregister from call state changes.
- final long token = Binder.clearCallingIdentity();
- try {
- mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
- // Unregister from power save mode changes.
- if (mPowerSaveModeListener != null) {
- mContext.unregisterReceiver(mPowerSaveModeListener);
- mPowerSaveModeListener = null;
- }
- mRecognitionRequested = false;
- }
-
// Clears state for all models (generic and keyphrase).
private void internalClearModelStateLocked() {
for (ModelData modelData : mModelDataMap.values()) {
@@ -1079,67 +992,6 @@
}
}
- class MyCallStateListener extends PhoneStateListener {
- MyCallStateListener(@NonNull Looper looper) {
- super(Objects.requireNonNull(looper));
- }
-
- @Override
- public void onCallStateChanged(int state, String arg1) {
-
- if (mHandler != null) {
- synchronized (mLock) {
- mHandler.removeMessages(MSG_CALL_STATE_CHANGED);
- Message msg = mHandler.obtainMessage(MSG_CALL_STATE_CHANGED, state, 0);
- mHandler.sendMessageDelayed(
- msg, (TelephonyManager.CALL_STATE_OFFHOOK == state) ? 0
- : CALL_INACTIVE_MSG_DELAY_MS);
- }
- }
- }
- }
-
- class PowerSaveModeListener extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
- return;
- }
- @SoundTriggerPowerSaveMode int soundTriggerPowerSaveMode =
- mPowerManager.getSoundTriggerPowerSaveMode();
- synchronized (mLock) {
- onPowerSaveModeChangedLocked(soundTriggerPowerSaveMode);
- }
- }
- }
-
- private void initializeDeviceStateListeners() {
- if (mRecognitionRequested) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- // Get the current call state synchronously for the first recognition.
- mCallActive = mTelephonyManager.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK;
-
- // Register for call state changes when the first call to start recognition occurs.
- mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
-
- // Register for power saver mode changes when the first call to start recognition
- // occurs.
- if (mPowerSaveModeListener == null) {
- mPowerSaveModeListener = new PowerSaveModeListener();
- mContext.registerReceiver(mPowerSaveModeListener,
- new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
- }
- mSoundTriggerPowerSaveMode = mPowerManager.getSoundTriggerPowerSaveMode();
-
- mRecognitionRequested = true;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
/**
* Stops and unloads all models. This is intended as a clean-up call with the expectation that
* this instance is not used after.
@@ -1153,7 +1005,6 @@
forceStopAndUnloadModelLocked(model, null);
}
mModelDataMap.clear();
- internalClearGlobalStateLocked();
if (mModule != null) {
mModule.detach();
mModule = null;
@@ -1305,28 +1156,14 @@
* @param modelData Model data to be used for recognition
* @return True if recognition is allowed to run at this time. False if not.
*/
+ @GuardedBy("mLock")
private boolean isRecognitionAllowedByDeviceState(ModelData modelData) {
- // if mRecognitionRequested is false, call and power state listeners are not registered so
- // we read current state directly from services
- if (!mRecognitionRequested) {
- mCallActive = mTelephonyManager.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK;
- mSoundTriggerPowerSaveMode = mPowerManager.getSoundTriggerPowerSaveMode();
- }
-
- return !mCallActive && isRecognitionAllowedByPowerState(
- modelData);
- }
-
- /**
- * Helper function to validate if a recognition should run based on the current power state
- *
- * @param modelData Model data to be used for recognition
- * @return True if device state allows recognition to run, false if not.
- */
- private boolean isRecognitionAllowedByPowerState(ModelData modelData) {
- return mSoundTriggerPowerSaveMode == PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED
- || (mSoundTriggerPowerSaveMode == PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY
- && modelData.shouldRunInBatterySaverMode());
+ return switch (mDeviceState) {
+ case DISABLE -> false;
+ case CRITICAL -> modelData.shouldRunInBatterySaverMode();
+ case ENABLE -> true;
+ default -> throw new AssertionError("Enum changed between compile and runtime");
+ };
}
// A single routine that implements the start recognition logic for both generic and keyphrase
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 913535e..3151781 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -35,14 +35,18 @@
import static com.android.server.utils.EventLogger.Event.ALOGW;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import static com.android.server.soundtrigger.DeviceStateHandler.DeviceStateListener;
+import static com.android.server.soundtrigger.DeviceStateHandler.SoundTriggerDeviceState;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
@@ -85,6 +89,8 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -112,6 +118,8 @@
import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -131,8 +139,8 @@
private static final boolean DEBUG = true;
private static final int SESSION_MAX_EVENT_SIZE = 128;
- final Context mContext;
- private Object mLock;
+ private final Context mContext;
+ private final Object mLock = new Object();
private final SoundTriggerServiceStub mServiceStub;
private final LocalSoundTriggerService mLocalSoundTriggerService;
@@ -140,6 +148,7 @@
private SoundTriggerDbHelper mDbHelper;
private final EventLogger mServiceEventLogger = new EventLogger(256, "Service");
+ private final EventLogger mDeviceEventLogger = new EventLogger(256, "Device Event");
private final Set<EventLogger> mSessionEventLoggers = ConcurrentHashMap.newKeySet(4);
private final Deque<EventLogger> mDetachedSessionEventLoggers = new LinkedBlockingDeque<>(4);
@@ -223,13 +232,18 @@
@GuardedBy("mLock")
private final ArrayMap<String, NumOps> mNumOpsPerPackage = new ArrayMap<>();
+ private final DeviceStateHandler mDeviceStateHandler;
+ private final Executor mDeviceStateHandlerExecutor = Executors.newSingleThreadExecutor();
+ private PhoneCallStateHandler mPhoneCallStateHandler;
+
public SoundTriggerService(Context context) {
super(context);
mContext = context;
mServiceStub = new SoundTriggerServiceStub();
mLocalSoundTriggerService = new LocalSoundTriggerService(context);
- mLock = new Object();
mSoundModelStatTracker = new SoundModelStatTracker();
+ mDeviceStateHandler = new DeviceStateHandler(mDeviceStateHandlerExecutor,
+ mDeviceEventLogger);
}
@Override
@@ -243,6 +257,29 @@
Slog.d(TAG, "onBootPhase: " + phase + " : " + isSafeMode());
if (PHASE_THIRD_PARTY_APPS_CAN_START == phase) {
mDbHelper = new SoundTriggerDbHelper(mContext);
+ final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
+ // Hook up power state listener
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!PowerManager.ACTION_POWER_SAVE_MODE_CHANGED
+ .equals(intent.getAction())) {
+ return;
+ }
+ mDeviceStateHandler.onPowerModeChanged(
+ powerManager.getSoundTriggerPowerSaveMode());
+ }
+ }, new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
+ // Initialize the initial power state
+ // Do so after registering the listener so we ensure that we don't drop any events
+ mDeviceStateHandler.onPowerModeChanged(powerManager.getSoundTriggerPowerSaveMode());
+
+ // PhoneCallStateHandler initializes the original call state
+ mPhoneCallStateHandler = new PhoneCallStateHandler(
+ mContext.getSystemService(SubscriptionManager.class),
+ mContext.getSystemService(TelephonyManager.class),
+ mDeviceStateHandler);
}
mMiddlewareService = ISoundTriggerMiddlewareService.Stub.asInterface(
ServiceManager.waitForService(Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE));
@@ -380,6 +417,9 @@
// Event loggers
pw.println("##Service-Wide logs:");
mServiceEventLogger.dump(pw, /* indent = */ " ");
+ pw.println("\n##Device state logs:");
+ mDeviceStateHandler.dump(pw);
+ mDeviceEventLogger.dump(pw, /* indent = */ " ");
pw.println("\n##Active Session dumps:\n");
for (var sessionLogger : mSessionEventLoggers) {
@@ -403,6 +443,7 @@
class SoundTriggerSessionStub extends ISoundTriggerSession.Stub {
private final SoundTriggerHelper mSoundTriggerHelper;
+ private final DeviceStateListener mListener;
// Used to detect client death.
private final IBinder mClient;
private final Identity mOriginatorIdentity;
@@ -424,6 +465,9 @@
} catch (RemoteException e) {
clientDied();
}
+ mListener = (SoundTriggerDeviceState state)
+ -> mSoundTriggerHelper.onDeviceStateChanged(state);
+ mDeviceStateHandler.registerListener(mListener);
}
@Override
@@ -874,6 +918,7 @@
}
private void detach() {
+ mDeviceStateHandler.unregisterListener(mListener);
mSoundTriggerHelper.detach();
detachSessionLogger(mEventLogger);
}
@@ -890,7 +935,8 @@
private void enforceDetectionPermissions(ComponentName detectionService) {
PackageManager packageManager = mContext.getPackageManager();
String packageName = detectionService.getPackageName();
- if (packageManager.checkPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD, packageName)
+ if (packageManager.checkPermission(
+ Manifest.permission.CAPTURE_AUDIO_HOTWORD, packageName)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException(detectionService.getPackageName() + " does not have"
+ " permission " + Manifest.permission.CAPTURE_AUDIO_HOTWORD);
@@ -1576,6 +1622,7 @@
private final @NonNull IBinder mClient;
private final EventLogger mEventLogger;
private final Identity mOriginatorIdentity;
+ private final @NonNull DeviceStateListener mListener;
private final SparseArray<UUID> mModelUuid = new SparseArray<>(1);
@@ -1594,6 +1641,9 @@
} catch (RemoteException e) {
clientDied();
}
+ mListener = (SoundTriggerDeviceState state)
+ -> mSoundTriggerHelper.onDeviceStateChanged(state);
+ mDeviceStateHandler.registerListener(mListener);
}
@Override
@@ -1662,6 +1712,7 @@
private void detachInternal() {
mEventLogger.enqueue(new SessionEvent(Type.DETACH, null));
detachSessionLogger(mEventLogger);
+ mDeviceStateHandler.unregisterListener(mListener);
mSoundTriggerHelper.detach();
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java
index f3457f5..56a159e 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java
@@ -21,6 +21,8 @@
import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModelType;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
/**
* Utilities for working with sound trigger related AIDL generated types.
@@ -49,23 +51,29 @@
/**
* Creates a new generic abort event.
+ *
* @return The new event.
*/
- static RecognitionEvent newAbortEvent() {
- RecognitionEvent event = newEmptyRecognitionEvent();
- event.type = SoundModelType.GENERIC;
- event.status = RecognitionStatus.ABORTED;
- return event;
+ static RecognitionEventSys newAbortEvent() {
+ RecognitionEvent recognitionEvent = newEmptyRecognitionEvent();
+ recognitionEvent.type = SoundModelType.GENERIC;
+ recognitionEvent.status = RecognitionStatus.ABORTED;
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = recognitionEvent;
+ return recognitionEventSys;
}
/**
* Creates a new generic phrase event.
+ *
* @return The new event.
*/
- static PhraseRecognitionEvent newAbortPhraseEvent() {
- PhraseRecognitionEvent event = newEmptyPhraseRecognitionEvent();
- event.common.type = SoundModelType.KEYPHRASE;
- event.common.status = RecognitionStatus.ABORTED;
- return event;
+ static PhraseRecognitionEventSys newAbortPhraseEvent() {
+ PhraseRecognitionEvent recognitionEvent = newEmptyPhraseRecognitionEvent();
+ recognitionEvent.common.type = SoundModelType.KEYPHRASE;
+ recognitionEvent.common.status = RecognitionStatus.ABORTED;
+ PhraseRecognitionEventSys phraseRecognitionEventSys = new PhraseRecognitionEventSys();
+ phraseRecognitionEventSys.phraseRecognitionEvent = recognitionEvent;
+ return phraseRecognitionEventSys;
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
index 75206e6..6f4a946 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
@@ -20,12 +20,12 @@
import android.hardware.soundtrigger3.ISoundTriggerHwCallback;
import android.hardware.soundtrigger3.ISoundTriggerHwGlobalCallback;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.IBinder;
/**
@@ -173,14 +173,19 @@
*/
interface ModelCallback {
/**
- * @see ISoundTriggerHwCallback#recognitionCallback(int, RecognitionEvent)
+ * Decorated callback of
+ * {@link ISoundTriggerHwCallback#recognitionCallback(int, RecognitionEvent)} where
+ * {@link RecognitionEventSys} is decorating the returned {@link RecognitionEvent}
*/
- void recognitionCallback(int modelHandle, RecognitionEvent event);
+ void recognitionCallback(int modelHandle, RecognitionEventSys event);
/**
- * @see ISoundTriggerHwCallback#phraseRecognitionCallback(int, PhraseRecognitionEvent)
+ * Decorated callback of
+ * {@link ISoundTriggerHwCallback#phraseRecognitionCallback(int, PhraseRecognitionEvent)}
+ * where {@link PhraseRecognitionEventSys} is decorating the returned
+ * {@link PhraseRecognitionEvent}
*/
- void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEvent event);
+ void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEventSys event);
/**
* @see ISoundTriggerHwCallback#modelUnloaded(int)
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
index 8c7cabe..d8ef2b6 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
@@ -19,14 +19,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.SoundModelType;
import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.IBinder;
import java.util.HashSet;
@@ -238,13 +238,13 @@
}
@Override
- public void recognitionCallback(int modelHandle, RecognitionEvent event) {
+ public void recognitionCallback(int modelHandle, RecognitionEventSys event) {
synchronized (mActiveModels) {
if (!mActiveModels.contains(modelHandle)) {
// Discard the event.
return;
}
- if (!event.recognitionStillActive) {
+ if (!event.recognitionEvent.recognitionStillActive) {
mActiveModels.remove(modelHandle);
}
// A recognition event must be the last one for its model, unless it indicates that
@@ -255,13 +255,13 @@
}
@Override
- public void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEvent event) {
+ public void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEventSys event) {
synchronized (mActiveModels) {
if (!mActiveModels.contains(modelHandle)) {
// Discard the event.
return;
}
- if (!event.common.recognitionStillActive) {
+ if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
mActiveModels.remove(modelHandle);
}
// A recognition event must be the last one for its model, unless it indicates that
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
index 24741e1..bac2466 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
@@ -17,14 +17,14 @@
package com.android.server.soundtrigger_middleware;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.DeadObjectException;
import android.os.IBinder;
import android.util.Log;
@@ -253,7 +253,7 @@
}
@Override
- public void recognitionCallback(int model, RecognitionEvent event) {
+ public void recognitionCallback(int model, RecognitionEventSys event) {
synchronized (mModelStates) {
ModelState state = mModelStates.get(model);
if (state == null || state == ModelState.INACTIVE) {
@@ -261,15 +261,16 @@
reboot();
return;
}
- if (event.recognitionStillActive && event.status != RecognitionStatus.SUCCESS
- && event.status != RecognitionStatus.FORCED) {
+ if (event.recognitionEvent.recognitionStillActive
+ && event.recognitionEvent.status != RecognitionStatus.SUCCESS
+ && event.recognitionEvent.status != RecognitionStatus.FORCED) {
Log.wtfStack(TAG,
"recognitionStillActive is only allowed when the recognition status "
+ "is SUCCESS");
reboot();
return;
}
- if (!event.recognitionStillActive) {
+ if (!event.recognitionEvent.recognitionStillActive) {
mModelStates.replace(model, ModelState.INACTIVE);
}
}
@@ -278,7 +279,7 @@
}
@Override
- public void phraseRecognitionCallback(int model, PhraseRecognitionEvent event) {
+ public void phraseRecognitionCallback(int model, PhraseRecognitionEventSys event) {
synchronized (mModelStates) {
ModelState state = mModelStates.get(model);
if (state == null || state == ModelState.INACTIVE) {
@@ -286,16 +287,16 @@
reboot();
return;
}
- if (event.common.recognitionStillActive
- && event.common.status != RecognitionStatus.SUCCESS
- && event.common.status != RecognitionStatus.FORCED) {
+ if (event.phraseRecognitionEvent.common.recognitionStillActive
+ && event.phraseRecognitionEvent.common.status != RecognitionStatus.SUCCESS
+ && event.phraseRecognitionEvent.common.status != RecognitionStatus.FORCED) {
Log.wtfStack(TAG,
"recognitionStillActive is only allowed when the recognition status "
+ "is SUCCESS");
reboot();
return;
}
- if (!event.common.recognitionStillActive) {
+ if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
mModelStates.replace(model, ModelState.INACTIVE);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
index c67bdd7..df2e9b4 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
@@ -25,9 +25,12 @@
import android.media.soundtrigger.RecognitionConfig;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.IBinder;
import android.os.IHwBinder;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.system.OsConstants;
import android.util.Log;
@@ -570,16 +573,20 @@
public void recognitionCallback_2_1(
android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent event,
int cookie) {
- mDelegate.recognitionCallback(event.header.model,
- ConversionUtil.hidl2aidlRecognitionEvent(event));
+ RecognitionEventSys eventSys = new RecognitionEventSys();
+ eventSys.recognitionEvent = ConversionUtil.hidl2aidlRecognitionEvent(event);
+ eventSys.halEventReceivedMillis = SystemClock.elapsedRealtime();
+ mDelegate.recognitionCallback(event.header.model, eventSys);
}
@Override
public void phraseRecognitionCallback_2_1(
android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent event,
int cookie) {
- mDelegate.phraseRecognitionCallback(event.common.header.model,
- ConversionUtil.hidl2aidlPhraseRecognitionEvent(event));
+ PhraseRecognitionEventSys eventSys = new PhraseRecognitionEventSys();
+ eventSys.phraseRecognitionEvent = ConversionUtil.hidl2aidlPhraseRecognitionEvent(event);
+ eventSys.halEventReceivedMillis = SystemClock.elapsedRealtime();
+ mDelegate.phraseRecognitionCallback(event.common.header.model, eventSys);
}
@Override
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
index 8bb5eb1..b1165bb 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
@@ -29,9 +29,12 @@
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.os.SystemClock;
public class SoundTriggerHw3Compat implements ISoundTriggerHal {
private final @NonNull ISoundTriggerHw mDriver;
@@ -244,14 +247,20 @@
public void phraseRecognitionCallback(int model, PhraseRecognitionEvent event) {
// A FORCED status implies that recognition is still active after the event.
event.common.recognitionStillActive |= event.common.status == RecognitionStatus.FORCED;
- mDelegate.phraseRecognitionCallback(model, event);
+ PhraseRecognitionEventSys phraseRecognitionEventSys = new PhraseRecognitionEventSys();
+ phraseRecognitionEventSys.phraseRecognitionEvent = event;
+ phraseRecognitionEventSys.halEventReceivedMillis = SystemClock.elapsedRealtimeNanos();
+ mDelegate.phraseRecognitionCallback(model, phraseRecognitionEventSys);
}
@Override
public void recognitionCallback(int model, RecognitionEvent event) {
// A FORCED status implies that recognition is still active after the event.
event.recognitionStillActive |= event.status == RecognitionStatus.FORCED;
- mDelegate.recognitionCallback(model, event);
+ RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+ recognitionEventSys.recognitionEvent = event;
+ recognitionEventSys.halEventReceivedMillis = SystemClock.elapsedRealtimeNanos();
+ mDelegate.recognitionCallback(model, recognitionEventSys);
}
@Override
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 0e796d1..2ee4e3c 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
@@ -16,12 +16,24 @@
package com.android.server.soundtrigger_middleware;
-import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.*;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.DETACH;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.FORCE_RECOGNITION;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.GET_MODEL_PARAMETER;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.LOAD_MODEL;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.LOAD_PHRASE_MODEL;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.MODEL_UNLOADED;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.MODULE_DIED;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.QUERY_MODEL_PARAMETER;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.RECOGNITION;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.RESOURCES_AVAILABLE;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.SET_MODEL_PARAMETER;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.START_RECOGNITION;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.STOP_RECOGNITION;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.UNLOAD_MODEL;
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;
import android.media.permission.Identity;
import android.media.permission.IdentityContext;
@@ -29,11 +41,12 @@
import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.os.BatteryStatsInternal;
import android.os.IBinder;
@@ -45,19 +58,18 @@
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 com.android.server.utils.EventLogger.Event;
import java.io.PrintWriter;
import java.util.Arrays;
+import java.util.Deque;
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;
/**
@@ -370,7 +382,7 @@
}
@Override
- public void onRecognition(int modelHandle, RecognitionEvent event, int captureSession)
+ public void onRecognition(int modelHandle, RecognitionEventSys event, int captureSession)
throws RemoteException {
try {
mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
@@ -388,13 +400,13 @@
}
@Override
- public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event,
+ public void onPhraseRecognition(int modelHandle, PhraseRecognitionEventSys event,
int captureSession)
throws RemoteException {
try {
mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
SystemClock.elapsedRealtime(), mOriginatorIdentity.uid);
- startKeyphraseEventLatencyTracking(event);
+ startKeyphraseEventLatencyTracking(event.phraseRecognitionEvent);
mCallbackDelegate.onPhraseRecognition(modelHandle, event, captureSession);
mEventLogger.enqueue(SessionEvent.createForVoid(
RECOGNITION, modelHandle, event, captureSession)
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index 00cedd7..00b894e 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -27,15 +27,15 @@
import android.media.permission.IdentityContext;
import android.media.permission.PermissionUtil;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.os.IBinder;
import android.os.RemoteException;
@@ -307,16 +307,15 @@
}
@Override
- public void onRecognition(int modelHandle, RecognitionEvent event, int captureSession)
- throws RemoteException {
+ public void onRecognition(int modelHandle, RecognitionEventSys event,
+ int captureSession) throws RemoteException {
enforcePermissions("Sound trigger recognition.");
mDelegate.onRecognition(modelHandle, event, captureSession);
}
@Override
- public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event,
- int captureSession)
- throws RemoteException {
+ public void onPhraseRecognition(int modelHandle, PhraseRecognitionEventSys event,
+ int captureSession) throws RemoteException {
enforcePermissions("Sound trigger phrase recognition.");
mDelegate.onPhraseRecognition(modelHandle, event, captureSession);
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 15c9ba9..f208c03 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -21,17 +21,17 @@
import android.media.permission.Identity;
import android.media.permission.IdentityContext;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.os.IBinder;
import android.os.RemoteException;
@@ -710,8 +710,7 @@
}
}
- class CallbackWrapper implements ISoundTriggerCallback,
- IBinder.DeathRecipient {
+ class CallbackWrapper implements ISoundTriggerCallback, IBinder.DeathRecipient {
private final ISoundTriggerCallback mCallback;
CallbackWrapper(ISoundTriggerCallback callback) {
@@ -728,11 +727,11 @@
}
@Override
- public void onRecognition(int modelHandle, @NonNull RecognitionEvent event,
+ public void onRecognition(int modelHandle, @NonNull RecognitionEventSys event,
int captureSession) {
synchronized (SoundTriggerMiddlewareValidation.this) {
ModelState modelState = mLoadedModels.get(modelHandle);
- if (!event.recognitionStillActive) {
+ if (!event.recognitionEvent.recognitionStillActive) {
modelState.activityState = ModelState.Activity.LOADED;
}
}
@@ -744,7 +743,7 @@
Log.w(TAG, "Client callback exception.", e);
synchronized (SoundTriggerMiddlewareValidation.this) {
ModelState modelState = mLoadedModels.get(modelHandle);
- if (event.status != RecognitionStatus.FORCED) {
+ if (event.recognitionEvent.status != RecognitionStatus.FORCED) {
modelState.activityState = ModelState.Activity.INTERCEPTED;
// If we failed to deliver an actual event to the client, they would
// never know to restart it whenever circumstances change. Thus, we
@@ -758,10 +757,10 @@
@Override
public void onPhraseRecognition(int modelHandle,
- @NonNull PhraseRecognitionEvent event, int captureSession) {
+ @NonNull PhraseRecognitionEventSys event, int captureSession) {
synchronized (SoundTriggerMiddlewareValidation.this) {
ModelState modelState = mLoadedModels.get(modelHandle);
- if (!event.common.recognitionStillActive) {
+ if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
modelState.activityState = ModelState.Activity.LOADED;
}
}
@@ -773,7 +772,7 @@
Log.w(TAG, "Client callback exception.", e);
synchronized (SoundTriggerMiddlewareValidation.this) {
ModelState modelState = mLoadedModels.get(modelHandle);
- if (!event.common.recognitionStillActive) {
+ if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
modelState.activityState = ModelState.Activity.INTERCEPTED;
// If we failed to deliver an actual event to the client, they would
// never know to restart it whenever circumstances change. Thus, we
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index 6223b2e..84cec55 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -19,16 +19,16 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.SoundModelType;
import android.media.soundtrigger.Status;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -499,10 +499,10 @@
@Override
public void recognitionCallback(int modelHandle,
- @NonNull RecognitionEvent recognitionEvent) {
+ @NonNull RecognitionEventSys event) {
ISoundTriggerCallback callback;
synchronized (SoundTriggerModule.this) {
- if (!recognitionEvent.recognitionStillActive) {
+ if (!event.recognitionEvent.recognitionStillActive) {
setState(ModelState.LOADED);
}
callback = mCallback;
@@ -510,7 +510,7 @@
// The callback must be invoked outside of the lock.
try {
if (callback != null) {
- callback.onRecognition(mHandle, recognitionEvent, mSession.mSessionHandle);
+ callback.onRecognition(mHandle, event, mSession.mSessionHandle);
}
} catch (RemoteException e) {
// We're not expecting any exceptions here.
@@ -520,10 +520,10 @@
@Override
public void phraseRecognitionCallback(int modelHandle,
- @NonNull PhraseRecognitionEvent phraseRecognitionEvent) {
+ @NonNull PhraseRecognitionEventSys event) {
ISoundTriggerCallback callback;
synchronized (SoundTriggerModule.this) {
- if (!phraseRecognitionEvent.common.recognitionStillActive) {
+ if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
setState(ModelState.LOADED);
}
callback = mCallback;
@@ -532,8 +532,7 @@
// The callback must be invoked outside of the lock.
try {
if (callback != null) {
- mCallback.onPhraseRecognition(mHandle, phraseRecognitionEvent,
- mSession.mSessionHandle);
+ mCallback.onPhraseRecognition(mHandle, event, mSession.mSessionHandle);
}
} catch (RemoteException e) {
// We're not expecting any exceptions here.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index 6053f1d..daecfe7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -17,8 +17,8 @@
package com.android.server.wm.flicker.helpers
import android.app.Instrumentation
+import android.tools.common.PlatformConsts
import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.wm.WindowManagerState.Companion.STATE_RESUMED
import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.helpers.FIND_TIMEOUT
import android.tools.device.traces.parsers.WindowManagerStateHelper
@@ -54,8 +54,8 @@
launchButton.click()
wmHelper
.StateSyncBuilder()
- .withActivityState(SECONDARY_ACTIVITY_COMPONENT, STATE_RESUMED)
- .withActivityState(MAIN_ACTIVITY_COMPONENT, STATE_RESUMED)
+ .withActivityState(SECONDARY_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
+ .withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
.waitForAndVerify()
}
@@ -73,8 +73,8 @@
launchButton.click()
wmHelper
.StateSyncBuilder()
- .withActivityState(PLACEHOLDER_PRIMARY_COMPONENT, STATE_RESUMED)
- .withActivityState(PLACEHOLDER_SECONDARY_COMPONENT, STATE_RESUMED)
+ .withActivityState(PLACEHOLDER_PRIMARY_COMPONENT, PlatformConsts.STATE_RESUMED)
+ .withActivityState(PLACEHOLDER_SECONDARY_COMPONENT, PlatformConsts.STATE_RESUMED)
.waitForAndVerify()
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
index 017de60..e2d17cd 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
@@ -26,39 +26,57 @@
import android.graphics.PixelFormat;
import android.graphics.RenderNode;
import android.graphics.Shader;
+import android.graphics.SurfaceTexture;
import android.hardware.HardwareBuffer;
import android.media.Image;
import android.media.ImageWriter;
import android.os.Bundle;
+import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
+import android.view.TextureView;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
@SuppressWarnings({"UnusedDeclaration"})
public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callback,
- AdapterView.OnItemSelectedListener {
+ TextureView.SurfaceTextureListener {
private static final int WIDTH = 512;
private static final int HEIGHT = 512;
private ImageView mImageView;
private SurfaceView mSurfaceView;
+ private TextureView mTextureView;
private HardwareBuffer mGradientBuffer;
- private ImageWriter mImageWriter;
+ private Map<View, ImageWriter> mImageWriters = new HashMap<>();
private ColorSpace mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
private String[] mColorNames = {"sRGB", "BT2020_HLG", "BT2020_PQ"};
- private String mCurrentColorName = "sRGB";
- private FutureTask<HardwareBuffer> authorGradientBuffer(HardwareBuffer buffer) {
+ private int mGradientEndColor = 0xFFFFFFFF;
+
+ private int[] mGradientEndColors = {0xFFFFFFFF, 0xFFFF0000, 0xFF00FF00, 0xFF0000FF};
+ private String[] mGradientColorNames = {"Grayscale", "Red", "Green", "Blue"};
+
+ private final ExecutorService mBufferFenceExecutor = Executors.newFixedThreadPool(1);
+ private final ExecutorService mBufferExecutor = Executors.newFixedThreadPool(1);
+
+ private FutureTask<HardwareBuffer> authorGradientBuffer(
+ HardwareBuffer buffer, int gradentEndColor) {
HardwareBufferRenderer renderer = new HardwareBufferRenderer(buffer);
RenderNode node = new RenderNode("content");
node.setPosition(0, 0, buffer.getWidth(), buffer.getHeight());
@@ -66,9 +84,10 @@
Canvas canvas = node.beginRecording();
LinearGradient gradient = new LinearGradient(
0, 0, buffer.getWidth(), buffer.getHeight(), 0xFF000000,
- 0xFFFFFFFF, Shader.TileMode.CLAMP);
+ gradentEndColor, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setShader(gradient);
+ paint.setDither(true);
canvas.drawRect(0f, 0f, buffer.getWidth(), buffer.getHeight(), paint);
node.endRecording();
@@ -78,7 +97,7 @@
FutureTask<HardwareBuffer> resolvedBuffer = new FutureTask<>(() -> buffer);
renderer.obtainRenderRequest()
.setColorSpace(colorSpace)
- .draw(Executors.newSingleThreadExecutor(), result -> {
+ .draw(mBufferFenceExecutor, result -> {
result.getFence().await(Duration.ofSeconds(3));
resolvedBuffer.run();
});
@@ -90,7 +109,7 @@
WIDTH, HEIGHT, PixelFormat.RGBA_8888, 1,
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
| HardwareBuffer.USAGE_GPU_COLOR_OUTPUT);
- return authorGradientBuffer(buffer);
+ return authorGradientBuffer(buffer, mGradientEndColor);
}
@Override
@@ -101,29 +120,70 @@
mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
- ArrayAdapter<String> adapter = new ArrayAdapter<>(
+ ArrayAdapter<String> colorSpaceAdapter = new ArrayAdapter<>(
this, android.R.layout.simple_spinner_item, mColorNames);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- Spinner spinner = new Spinner(this);
- spinner.setAdapter(adapter);
- spinner.setOnItemSelectedListener(this);
+ colorSpaceAdapter
+ .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ Spinner colorSpaceSpinner = new Spinner(this);
+ colorSpaceSpinner.setAdapter(colorSpaceAdapter);
+ colorSpaceSpinner.setOnItemSelectedListener(new ColorSpaceOnItemSelectedListener());
+
+ ArrayAdapter<String> gradientColorAdapter = new ArrayAdapter<>(
+ this, android.R.layout.simple_spinner_item, mGradientColorNames);
+
+ gradientColorAdapter
+ .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ Spinner gradientColorSpinner = new Spinner(this);
+ gradientColorSpinner.setAdapter(gradientColorAdapter);
+ gradientColorSpinner
+ .setOnItemSelectedListener(new GradientColorOnItemSelectedListener());
mGradientBuffer = getGradientBuffer().get();
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.VERTICAL);
+ TextView imageViewText = new TextView(this);
+ imageViewText.setText("ImageView");
mImageView = new ImageView(this);
+ TextView textureViewText = new TextView(this);
+ textureViewText.setText("TextureView");
+ mTextureView = new TextureView(this);
+ mTextureView.setSurfaceTextureListener(this);
+
+ TextView surfaceViewText = new TextView(this);
+ surfaceViewText.setText("SurfaceView");
mSurfaceView = new SurfaceView(this);
mSurfaceView.getHolder().addCallback(this);
- linearLayout.addView(spinner, new LinearLayout.LayoutParams(
+ LinearLayout spinnerLayout = new LinearLayout(this);
+ spinnerLayout.setOrientation(LinearLayout.HORIZONTAL);
+
+ spinnerLayout.addView(colorSpaceSpinner, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
+ spinnerLayout.addView(gradientColorSpinner, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+
+ linearLayout.addView(spinnerLayout, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+
+ linearLayout.addView(imageViewText, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.addView(mImageView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
+ linearLayout.addView(textureViewText, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+ linearLayout.addView(mTextureView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
+ linearLayout.addView(surfaceViewText, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.addView(mSurfaceView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
setContentView(linearLayout);
@@ -145,16 +205,24 @@
}
private void populateBuffers() {
- Bitmap bitmap = Bitmap.wrapHardwareBuffer(
- mGradientBuffer, ColorSpace.get(ColorSpace.Named.SRGB));
- Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, false);
- copy.setColorSpace(mColorSpace);
- mImageView.setImageBitmap(copy);
+ try {
+ Bitmap bitmap = Bitmap.wrapHardwareBuffer(
+ getGradientBuffer().get(), ColorSpace.get(ColorSpace.Named.SRGB));
+ Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, false);
+ copy.setColorSpace(mColorSpace);
+ mImageView.setImageBitmap(copy);
- try (Image image = mImageWriter.dequeueInputImage()) {
- authorGradientBuffer(image.getHardwareBuffer()).get();
- image.setDataSpace(mColorSpace.getDataSpace());
- mImageWriter.queueInputImage(image);
+ for (ImageWriter writer : mImageWriters.values()) {
+ mBufferExecutor.execute(() -> {
+ try (Image image = writer.dequeueInputImage()) {
+ authorGradientBuffer(image.getHardwareBuffer(), mGradientEndColor).get();
+ image.setDataSpace(mColorSpace.getDataSpace());
+ writer.queueInputImage(image);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -167,30 +235,81 @@
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- mImageWriter = new ImageWriter.Builder(holder.getSurface())
+ mImageWriters.put(mSurfaceView, new ImageWriter.Builder(holder.getSurface())
.setUsage(HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
| HardwareBuffer.USAGE_GPU_COLOR_OUTPUT
| HardwareBuffer.USAGE_COMPOSER_OVERLAY)
- .build();
+ .build());
populateBuffers();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
- mImageWriter.close();
- mImageWriter = null;
+ if (mImageWriters.containsKey(mSurfaceView)) {
+ mImageWriters.remove(mSurfaceView);
+ }
}
-
@Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- mCurrentColorName = mColorNames[position];
- mColorSpace = getFromName(mCurrentColorName);
+ public void onSurfaceTextureAvailable(
+ @NonNull SurfaceTexture surface, int width, int height) {
+ mImageWriters.put(mTextureView, new ImageWriter.Builder(new Surface(surface))
+ .setUsage(HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
+ | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT)
+ .build());
populateBuffers();
}
@Override
- public void onNothingSelected(AdapterView<?> parent) {
+ public void onSurfaceTextureSizeChanged(
+ @NonNull SurfaceTexture surface, int width, int height) {
}
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
+ if (mImageWriters.containsKey(mTextureView)) {
+ mImageWriters.remove(mTextureView);
+ }
+ return false;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
+
+ }
+
+ private final class ColorSpaceOnItemSelectedListener
+ implements AdapterView.OnItemSelectedListener {
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ ColorBitmapActivity.this.mColorSpace =
+ getFromName(ColorBitmapActivity.this.mColorNames[position]);
+ ColorBitmapActivity.this.getMainExecutor()
+ .execute(ColorBitmapActivity.this::populateBuffers);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+
+ }
+ }
+
+ private final class GradientColorOnItemSelectedListener
+ implements AdapterView.OnItemSelectedListener {
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ ColorBitmapActivity.this.mGradientEndColor =
+ ColorBitmapActivity.this.mGradientEndColors[position];
+ ColorBitmapActivity.this.getMainExecutor()
+ .execute(ColorBitmapActivity.this::populateBuffers);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+
+ }
+ }
}